<commit_before>/* @flow */

import { ZalgoPromise } from 'zalgo-promise/src';
import * as postRobot from 'post-robot/src';
import { btoa } from 'Base64';
import * as $logger from 'beaver-logger/client';

import { config, FPTI } from '../config';
import { request, memoize } from '../lib';

import { Button } from '../components';

let proxyRest : { [key : string] : () => ZalgoPromise<string> } = {};

let createAccessToken = memoize((env : string, client : { [key : string] : string }) : ZalgoPromise<string> => {

    $logger.info(`rest_api_create_access_token`);

    env = env || config.env;

    let clientID : string = client[env];

    if (!clientID) {
        throw new Error(`Client ID not found for env: ${env}`);
    }

    if (proxyRest.createAccessToken && !proxyRest.createAccessToken.source.closed) {
        return proxyRest.createAccessToken(env, client);
    }

    let basicAuth : string = btoa(`${clientID}:`);

    return request({

        method: `post`,
        url: config.authApiUrls[env],
        headers: {
            Authorization: `Basic ${basicAuth}`
        },
        data: {
            grant_type: `client_credentials`
        }

    }).then(res => {

        if (res && res.error === 'invalid_client') {
            throw new Error(`Auth Api invalid ${env} client id: ${clientID}:\n\n${JSON.stringify(res, null, 4)}`);
        }

        if (!res || !res.access_token) {
            throw new Error(`Auth Api response error:\n\n${JSON.stringify(res, null, 4)}`);
        }

        return res.access_token;
    });

}, { time: 10 * 60 * 1000 });

let createExperienceProfile = memoize((env : string, client : { [key : string] : string }, experienceDetails : Object = {}) : ZalgoPromise<string> => {

    $logger.info(`rest_api_create_experience_profile`);

    env = env || config.env;

    let clientID = client[env];

    if (!clientID) {
        throw new Error(`Client ID not found for env: ${env}`);
    }

    if (proxyRest.createExperienceProfile && !proxyRest.createExperienceProfile.source.closed) {
        return proxyRest.createExperienceProfile(env, client, experienceDetails);
    }

    experienceDetails.temporary = true;
    experienceDetails.name = experienceDetails.name ? `${experienceDetails.name}_${Math.random().toString()}` : Math.random().toString();

    return createAccessToken(env, client).then((accessToken) : ZalgoPromise<Object> => {

        return request({
            method: `post`,
            url: config.experienceApiUrls[env],
            headers: {
                Authorization: `Bearer ${accessToken}`
            },
            json: experienceDetails
        });

    }).then((res) : string => {

        if (res && res.error) {
            throw new Error(res.error);
        }

        if (!res.id) {
            throw new Error(`No id in experience profile response:\n\n${JSON.stringify(res, null, 4)}`);
        }

        return res.id;
    });

}, { time: 10 * 60 * 1000 });

function logPaymentResponse(res) {

    if (!res) {
        return;
    }

    let paymentToken;
    let paymentID;

    if (res.id) {
        paymentID = res.id;
    }

    if (res.links && res.links.length) {
        for (let i = 0; i < res.links.length; i++) {
            if (res.links[i].method === 'REDIRECT' && res.links[i].rel === 'approval_url') {
                let match = res.links[i].href.match(/token=((EC-)?[A-Z0-9]{17})/);
                if (match) {
                    paymentToken = match[1];
                }
            }
        }
    }

    $logger.track({
        [ FPTI.KEY.STATE ]: FPTI.STATE.BUTTON,
        [ FPTI.KEY.TRANSITION ]: FPTI.TRANSITION.CREATE_PAYMENT,
        [ FPTI.KEY.CONTEXT_TYPE ]: FPTI.CONTEXT_TYPE.EC_TOKEN,
        [ FPTI.KEY.PAY_ID ]: paymentID,
        [ FPTI.KEY.TOKEN ]: paymentToken,
        [ FPTI.KEY.CONTEXT_ID ]: paymentToken
    });
}

function createCheckoutToken(env : string, client : { [key : string] : string }, paymentDetails : Object, experienceDetails? : ?Object) : ZalgoPromise<string> {

    $logger.info(`rest_api_create_checkout_token`);

    env = env || config.env;

    let clientID = client[env];

    if (!clientID) {
        throw new Error(`Client ID not found for env: ${env}`);
    }

    let payment;
    let experience;
    let meta;

    if (paymentDetails.payment) {
        ({ payment, experience, meta } = paymentDetails);
    } else {
        [ payment, experience ] = [ paymentDetails, experienceDetails ];
    }

    if (!payment) {
        throw new Error(`Expected payment details to be passed`);
    }

    if (proxyRest.createCheckoutToken && !proxyRest.createCheckoutToken.source.closed) {
        return proxyRest.createCheckoutToken(env, client, { payment, experience, meta });
    }

    payment = { ...payment };
    payment.intent = payment.intent || 'sale';
    payment.redirect_urls = payment.redirect_urls || {};
    payment.redirect_urls.return_url = payment.redirect_urls.return_url || `${window.location.protocol}//${window.location.host}`;
    payment.redirect_urls.cancel_url = payment.redirect_urls.cancel_url || `${window.location.protocol}//${window.location.host}`;
    payment.payer = payment.payer || {};
    payment.payer.payment_method = payment.payer.payment_method || 'paypal';

    return createAccessToken(env, client).then((accessToken) : ZalgoPromise<Object> => {

        return ZalgoPromise.try(() => {

            if (experience) {
                return createExperienceProfile(env, client, experience);
            }

        }).then((experienceID) : ZalgoPromise<Object> => {

            if (experienceID) {
                payment.experience_profile_id = experienceID;
            }

            let headers : Object = {
                Authorization: `Bearer ${accessToken}`
            };

            if (meta && meta.partner_attribution_id) {
                headers['PayPal-Partner-Attribution-Id'] = meta.partner_attribution_id;
            }

            return request({
                method: `post`,
                url: config.paymentApiUrls[env],
                headers,
                json: payment
            });
        });

    }).then((res) : string => {

        logPaymentResponse(res);

        if (res && res.id) {
            return res.id;
        }

        throw new Error(`Payment Api response error:\n\n${JSON.stringify(res, null, 4)}`);
    });
}

export function createBillingToken(env : string, client : { [key : string] : string }, billingDetails : Object, experienceDetails? : ?Object) : ZalgoPromise<string> {

    $logger.info(`rest_api_create_billing_token`);

    env = env || config.env;

    let clientID = client[env];

    if (!clientID) {
        throw new Error(`Client ID not found for env: ${env}`);
    }

    if (proxyRest.createBillingToken && !proxyRest.createBillingToken.source.closed) {
        return proxyRest.createBillingToken(env, client, billingDetails, experienceDetails);
    }

    billingDetails = { ...billingDetails };
    billingDetails.plan = billingDetails.plan || {};
    billingDetails.plan.merchant_preferences = billingDetails.plan.merchant_preferences || {};
    billingDetails.plan.merchant_preferences.return_url = billingDetails.plan.merchant_preferences.return_url || `${window.location.protocol}//${window.location.host}`;
    billingDetails.plan.merchant_preferences.cancel_url = billingDetails.plan.merchant_preferences.cancel_url || `${window.location.protocol}//${window.location.host}`;
    billingDetails.payer = billingDetails.payer || {};
    billingDetails.payer.payment_method = billingDetails.payer.payment_method || 'paypal';

    return createAccessToken(env, client).then((accessToken) : ZalgoPromise<Object> => {

        return ZalgoPromise.try(() => {

            if (experienceDetails) {
                return createExperienceProfile(env, client, experienceDetails);
            }

        }).then((experienceID) : ZalgoPromise<Object> => {

            if (experienceID) {
                billingDetails.experience_profile_id = experienceID;
            }

            return request({
                method: `post`,
                url: config.billingApiUrls[env],
                headers: {
                    Authorization: `Bearer ${accessToken}`
                },
                json: billingDetails
            });
        });

    }).then(res => {

        if (res && res.token_id) {
            return res.token_id;
        }

        throw new Error(`Billing Api response error:\n\n${JSON.stringify(res, null, 4)}`);
    });
}

export let rest = {
    payment: {
        create: createCheckoutToken
    },
    billingAgreement: {
        create: createBillingToken
    },
    experience: {
        create: createExperienceProfile
    }
};

const PROXY_REST = `proxy_rest`;

if (postRobot.bridge.isBridge() || Button.isChild()) {
    postRobot.sendToParent(PROXY_REST, { createAccessToken, createExperienceProfile, createCheckoutToken, createBillingToken })
        .catch(() => {
            // pass
        });

} else {
    postRobot.on(PROXY_REST, { domain: config.paypal_domain_regex }, ({ data }) => {
        proxyRest = data;
    });
}
<commit_msg>Type safety fix<commit_after>/* @flow */

import { ZalgoPromise } from 'zalgo-promise/src';
import * as postRobot from 'post-robot/src';
import { btoa } from 'Base64';
import * as $logger from 'beaver-logger/client';

import { config, FPTI } from '../config';
import { request, memoize } from '../lib';

import { Button } from '../components';

let proxyRest : { [key : string] : () => ZalgoPromise<string> } = {};

let createAccessToken = memoize((env : string, client : { [key : string] : string }) : ZalgoPromise<string> => {

    $logger.info(`rest_api_create_access_token`);

    env = env || config.env;

    let clientID : string = client[env];

    if (!clientID) {
        throw new Error(`Client ID not found for env: ${env}`);
    }

    if (proxyRest.createAccessToken && !proxyRest.createAccessToken.source.closed) {
        return proxyRest.createAccessToken(env, client);
    }

    let basicAuth : string = btoa(`${clientID}:`);

    return request({

        method: `post`,
        url: config.authApiUrls[env],
        headers: {
            Authorization: `Basic ${basicAuth}`
        },
        data: {
            grant_type: `client_credentials`
        }

    }).then(res => {

        if (res && res.error === 'invalid_client') {
            throw new Error(`Auth Api invalid ${env} client id: ${clientID}:\n\n${JSON.stringify(res, null, 4)}`);
        }

        if (!res || !res.access_token) {
            throw new Error(`Auth Api response error:\n\n${JSON.stringify(res, null, 4)}`);
        }

        return res.access_token;
    });

}, { time: 10 * 60 * 1000 });

let createExperienceProfile = memoize((env : string, client : { [key : string] : string }, experienceDetails : Object = {}) : ZalgoPromise<string> => {

    $logger.info(`rest_api_create_experience_profile`);

    env = env || config.env;

    let clientID = client[env];

    if (!clientID) {
        throw new Error(`Client ID not found for env: ${env}`);
    }

    if (proxyRest.createExperienceProfile && !proxyRest.createExperienceProfile.source.closed) {
        return proxyRest.createExperienceProfile(env, client, experienceDetails);
    }

    experienceDetails.temporary = true;
    experienceDetails.name = experienceDetails.name ? `${experienceDetails.name}_${Math.random().toString()}` : Math.random().toString();

    return createAccessToken(env, client).then((accessToken) : ZalgoPromise<Object> => {

        return request({
            method: `post`,
            url: config.experienceApiUrls[env],
            headers: {
                Authorization: `Bearer ${accessToken}`
            },
            json: experienceDetails
        });

    }).then((res) : string => {

        if (res && res.error) {
            throw new Error(res.error);
        }

        if (!res.id) {
            throw new Error(`No id in experience profile response:\n\n${JSON.stringify(res, null, 4)}`);
        }

        return res.id;
    });

}, { time: 10 * 60 * 1000 });

function logPaymentResponse(res) {

    if (!res) {
        return;
    }

    let paymentToken;
    let paymentID;

    if (res.id) {
        paymentID = res.id;
    }

    if (res.links && res.links.length) {
        for (let i = 0; i < res.links.length; i++) {
            if (res.links[i].method === 'REDIRECT' && res.links[i].rel === 'approval_url') {
                let match = res.links[i].href.match(/token=((EC-)?[A-Z0-9]{17})/);
                if (match) {
                    paymentToken = match[1];
                }
            }
        }
    }

    $logger.track({
        [ FPTI.KEY.STATE ]: FPTI.STATE.BUTTON,
        [ FPTI.KEY.TRANSITION ]: FPTI.TRANSITION.CREATE_PAYMENT,
        [ FPTI.KEY.CONTEXT_TYPE ]: FPTI.CONTEXT_TYPE.EC_TOKEN,
        [ FPTI.KEY.PAY_ID ]: paymentID,
        [ FPTI.KEY.TOKEN ]: paymentToken,
        [ FPTI.KEY.CONTEXT_ID ]: paymentToken
    });
}

function createCheckoutToken(env : string, client : { [key : string] : string }, paymentDetails : Object, experienceDetails? : ?Object) : ZalgoPromise<string> {

    $logger.info(`rest_api_create_checkout_token`);

    env = env || config.env;

    let clientID = client[env];

    if (!clientID) {
        throw new Error(`Client ID not found for env: ${env}`);
    }

    let payment;
    let experience;
    let meta;

    if (paymentDetails.payment) {
        ({ payment, experience, meta } = paymentDetails);
    } else {
        [ payment, experience ] = [ paymentDetails, experienceDetails ];
    }

    if (!payment) {
        throw new Error(`Expected payment details to be passed`);
    }

    if (proxyRest.createCheckoutToken && !proxyRest.createCheckoutToken.source.closed) {
        return proxyRest.createCheckoutToken(env, client, { payment, experience, meta });
    }

    payment = { ...payment };
    payment.intent = payment.intent || 'sale';
    payment.redirect_urls = payment.redirect_urls || {};
    payment.redirect_urls.return_url = payment.redirect_urls.return_url || `${window.location.protocol}//${window.location.host}`;
    payment.redirect_urls.cancel_url = payment.redirect_urls.cancel_url || `${window.location.protocol}//${window.location.host}`;
    payment.payer = payment.payer || {};
    payment.payer.payment_method = payment.payer.payment_method || 'paypal';

    return createAccessToken(env, client).then((accessToken) : ZalgoPromise<Object> => {

        return ZalgoPromise.try(() => {

            if (experience) {
                return createExperienceProfile(env, client, experience);
            }

        }).then((experienceID) : ZalgoPromise<Object> => {

            if (experienceID) {
                payment.experience_profile_id = experienceID;
            }

            let headers : Object = {
                Authorization: `Bearer ${accessToken}`
            };

            if (meta && meta.partner_attribution_id) {
                headers['PayPal-Partner-Attribution-Id'] = meta.partner_attribution_id;
            }

            return request({
                method: `post`,
                url: config.paymentApiUrls[env],
                headers,
                json: payment
            });
        });

    }).then((res) : string => {

        logPaymentResponse(res);

        if (res && res.id) {
            return res.id;
        }

        throw new Error(`Payment Api response error:\n\n${JSON.stringify(res, null, 4)}`);
    });
}

export function createBillingToken(env : string, client : { [key : string] : string }, billingDetails : Object, experienceDetails? : ?Object) : ZalgoPromise<string> {

    $logger.info(`rest_api_create_billing_token`);

    env = env || config.env;

    let clientID = client[env];

    if (!clientID) {
        throw new Error(`Client ID not found for env: ${env}`);
    }

    if (proxyRest.createBillingToken && !proxyRest.createBillingToken.source.closed) {
        return proxyRest.createBillingToken(env, client, billingDetails, experienceDetails);
    }

    billingDetails = { ...billingDetails };
    billingDetails.plan = billingDetails.plan || {};
    billingDetails.plan.merchant_preferences = billingDetails.plan.merchant_preferences || {};
    billingDetails.plan.merchant_preferences.return_url = billingDetails.plan.merchant_preferences.return_url || `${window.location.protocol}//${window.location.host}`;
    billingDetails.plan.merchant_preferences.cancel_url = billingDetails.plan.merchant_preferences.cancel_url || `${window.location.protocol}//${window.location.host}`;
    billingDetails.payer = billingDetails.payer || {};
    billingDetails.payer.payment_method = billingDetails.payer.payment_method || 'paypal';

    return createAccessToken(env, client).then((accessToken) : ZalgoPromise<Object> => {

        return ZalgoPromise.try(() => {

            if (experienceDetails) {
                return createExperienceProfile(env, client, experienceDetails);
            }

        }).then((experienceID) : ZalgoPromise<Object> => {

            if (experienceID) {
                billingDetails.experience_profile_id = experienceID;
            }

            return request({
                method: `post`,
                url: config.billingApiUrls[env],
                headers: {
                    Authorization: `Bearer ${accessToken}`
                },
                json: billingDetails
            });
        });

    }).then(res => {

        if (res && res.token_id) {
            return res.token_id;
        }

        throw new Error(`Billing Api response error:\n\n${JSON.stringify(res, null, 4)}`);
    });
}

export let rest = {
    payment: {
        create: createCheckoutToken
    },
    billingAgreement: {
        create: createBillingToken
    },
    experience: {
        create: createExperienceProfile
    }
};

const PROXY_REST = `proxy_rest`;

if ((postRobot.bridge && postRobot.bridge.isBridge()) || Button.isChild()) {
    postRobot.sendToParent(PROXY_REST, { createAccessToken, createExperienceProfile, createCheckoutToken, createBillingToken })
        .catch(() => {
            // pass
        });

} else {
    postRobot.on(PROXY_REST, { domain: config.paypal_domain_regex }, ({ data }) => {
        proxyRest = data;
    });
}
<|endoftext|>


<commit_before>import {
  applyProp,
  attributes,
  elementClose,
  elementOpen,
  elementVoid,
  skip,
  symbols,
  text,
} from 'incremental-dom';
import { name as $name, ref as $ref } from '../util/symbols';
import { shadowDomV0, shadowDomV1 } from '../util/support';

const applyDefault = attributes[symbols.default];
const fallbackToV0 = !shadowDomV1 && shadowDomV0;

// A stack of children that corresponds to the current function helper being
// executed.
const stackChren = [];

const $skipCurrentElement = '__skip';
const $currentEventHandlers = '__events';
const $stackCurrentHelperProps = '__props';

// The current function helper in the stack.
let stackCurrentHelper;

// This is used for the Incremental DOM overrides to keep track of what args
// to pass the main elementOpen() function.
let overrideArgs;

// Whether or not to skip the current rendering tree.
let skipCurrentTree = false;

// Adds or removes an event listener for an element.
function applyEvent(elem, ename, newFunc) {
  let events = elem[$currentEventHandlers];

  if (!events) {
    events = elem[$currentEventHandlers] = {};
  }

  const oldFunc = events[ename];

  // Remove old listener so they don't double up.
  if (oldFunc) {
    elem.removeEventListener(ename, oldFunc);
  }

  // Bind new listener.
  if (newFunc) {
    elem.addEventListener(ename, events[ename] = newFunc);
  }
}

// Attributes that are not handled by Incremental DOM.
attributes.key = attributes.statics = function () {};

// Attributes that *must* be set via a property on all elements.
attributes.checked = attributes.className = attributes.disabled = attributes.value = applyProp;

// V0 Shadow DOM to V1 normalisation.
attributes.name = function (elem, name, value) {
  if (elem.tagName === 'CONTENT') {
    name = 'select';
    value = `[slot="${value}"]`;
  }
  applyDefault(elem, 'name', value);
};

// Ref handler.
attributes.ref = function (elem, name, value) {
  elem[$ref] = value;
};

// Skip handler.
attributes.skip = function (elem, name, value) {
  if (value) {
    elem[$skipCurrentElement] = true;
  }
};

// Default attribute applicator.
attributes[symbols.default] = function (elem, name, value) {
  // Custom element properties should be set as properties.
  const props = elem.constructor.props;
  if (props && name in props) {
    return applyProp(elem, name, value);
  }

  // Boolean false values should not set attributes at all.
  if (value === false) {
    return;
  }

  // Handle built-in and custom events.
  if (name.indexOf('on') === 0) {
    const firstChar = name[2];
    let eventName;

    if (firstChar === '-') {
      eventName = name.substring(3);
    } else if (firstChar === firstChar.toUpperCase()) {
      eventName = firstChar.toLowerCase() + name.substring(3);
    }

    if (eventName) {
      applyEvent(elem, eventName, value);
      return;
    }
  }

  // Set defined props on the element directly. This ensures properties like
  // "value" on <input> elements get set correctly. Setting those as attributes
  // doesn't always work and setting props is faster than attributes.
  //
  // However, certain props on SVG elements are readonly and error when you try
  // to set them.
  if (name in elem && !('ownerSVGElement' in elem)) {
    applyProp(elem, name, value);
    return;
  }

  // Fallback to default IncrementalDOM behaviour.
  applyDefault(elem, name, value);
};

function resolveTagName(tname) {
  // If the tag name is a function, a Skate constructor or a standard function
  // is supported.
  //
  // - If a Skate constructor, the tag name is extracted from that.
  // - If a standard function, it is used as a helper.
  if (typeof tname === 'function') {
    return tname[$name] || tname;
  }

  // Skate allows the consumer to use <slot /> and it will translate it to
  // <content /> if Shadow DOM V0 is preferred.
  if (tname === 'slot' && fallbackToV0) {
    return 'content';
  }

  // All other tag names are just passed through.
  return tname;
}

function wrapIdomFunc(func, tnameFuncHandler = () => {}) {
  return function wrap(...args) {
    args[0] = resolveTagName(args[0]);
    stackCurrentHelper = null;
    if (typeof args[0] === 'function') {
      // If we've encountered a function, handle it according to the type of
      // function that is being wrapped.
      stackCurrentHelper = args[0];
      return tnameFuncHandler(...args);
    } else if (stackChren.length) {
      // We pass the wrap() function in here so that when it's called as
      // children, it will queue up for the next stack, if there is one.
      stackChren[stackChren.length - 1].push([wrap, args]);
    } else {
      const isElementClosing = func === elementClose;
      const isElementOpening = func === elementOpen;

      if (skipCurrentTree && !isElementClosing) {
        return;
      }

      const elem = func(...args);

      if (isElementOpening && elem[$skipCurrentElement]) {
        skipCurrentTree = true;
      } else if (isElementClosing) {
        const eref = elem[$ref];

        // We delete so that it isn't called again for the same element. If the
        // ref changes, or the element changes, this will be defined again.
        delete elem[$ref];

        // Execute the saved ref after esuring we've cleand up after it.
        if (typeof eref === 'function') {
          eref(elem);
        }

        // If this element was skipped, we should stop skipping the tree since
        // the element is now closing.
        if (elem[$skipCurrentElement]) {
          skipCurrentTree = false;
        }
      }

      return elem;
    }
  };
}

function newAttr(...args) {
  if (stackCurrentHelper) {
    stackCurrentHelper[$stackCurrentHelperProps][args[0]] = args[1];
  } else if (stackChren.length) {
    stackChren[stackChren.length - 1].push([newAttr, args]);
  } else {
    overrideArgs.push(args[0]);
    overrideArgs.push(args[1]);
  }
}

function stackOpen(tname, key, statics, ...attrs) {
  const props = { key, statics };
  for (let a = 0; a < attrs.length; a += 2) {
    props[attrs[a]] = attrs[a + 1];
  }
  tname[$stackCurrentHelperProps] = props;
  stackChren.push([]);
}

function stackClose(tname) {
  const chren = stackChren.pop();
  const props = tname[$stackCurrentHelperProps];
  delete tname[$stackCurrentHelperProps];
  return tname(props, () => chren.forEach(args => args[0](...args[1])));
}

function stackVoid(...args) {
  stackOpen(...args);
  return stackClose(args[0]);
}

// Incremental DOM overrides
// -------------------------

// We must override internal functions that call internal Incremental DOM
// functions because we can't override the internal references. This means
// we must roughly re-implement their behaviour. Luckily, they're fairly
// simple.
const newElementOpenEnd = wrapIdomFunc(() => {
  const node = newElementOpen(...overrideArgs);
  overrideArgs = null;
  return node;
});
const newElementOpenStart = wrapIdomFunc((...args) => {
  overrideArgs = args;
}, stackOpen);

// Standard open / closed overrides don't need to reproduce internal behaviour
// because they are the ones referenced from *End and *Start.
const newElementOpen = wrapIdomFunc(elementOpen, stackOpen);
const newElementClose = wrapIdomFunc(elementClose, stackClose);

// Ensure we call our overridden functions instead of the internal ones.
const newElementVoid = wrapIdomFunc(elementVoid, stackVoid);

// Text override ensures their calls can queue if using function helpers.
const newText = wrapIdomFunc(text);

// Convenience function for declaring an Incremental DOM element using
// hyperscript-style syntax.
export function element(tname, attrs, chren) {
  const atype = typeof attrs;

  // If attributes are a function, then they should be treated as children.
  if (atype === 'function' || atype === 'string') {
    chren = attrs;
  }

  // Ensure the attributes are an object.
  if (atype !== 'object') {
    attrs = {};
  }

  // We open the element so we can set attrs after.
  newElementOpenStart(tname, attrs.key, attrs.statics);

  // Delete so special attrs don't actually get set.
  delete attrs.key;
  delete attrs.statics;

  // Set attributes.
  Object.keys(attrs).forEach(name => newAttr(name, attrs[name]));

  // Close before we render the descendant tree.
  newElementOpenEnd(tname);

  const ctype = typeof chren;
  if (ctype === 'function') {
    chren();
  } else if (ctype === 'string' || ctype === 'number') {
    newText(chren);
  }

  return newElementClose(tname);
}

// We don't have to do anything special for the text function; it's just a
// straight export from Incremental DOM.
export {
  newAttr as attr,
  newElementClose as elementClose,
  newElementOpen as elementOpen,
  newElementOpenEnd as elementOpenEnd,
  newElementOpenStart as elementOpenStart,
  newElementVoid as elementVoid,
  newText as text,
};
<commit_msg>chore: Fix test again.<commit_after>import {
  applyProp,
  attributes,
  elementClose,
  elementOpen,
  elementVoid,
  skip,
  symbols,
  text,
} from 'incremental-dom';
import { name as $name, ref as $ref } from '../util/symbols';
import { shadowDomV0, shadowDomV1 } from '../util/support';

const applyDefault = attributes[symbols.default];
const fallbackToV0 = !shadowDomV1 && shadowDomV0;

// A stack of children that corresponds to the current function helper being
// executed.
const stackChren = [];

const $skipCurrentElement = '__skip';
const $currentEventHandlers = '__events';
const $stackCurrentHelperProps = '__props';

// The current function helper in the stack.
let stackCurrentHelper;

// This is used for the Incremental DOM overrides to keep track of what args
// to pass the main elementOpen() function.
let overrideArgs;

// Whether or not to skip the current rendering tree.
let skipCurrentTree = false;

// Adds or removes an event listener for an element.
function applyEvent(elem, ename, newFunc) {
  let events = elem[$currentEventHandlers];

  if (!events) {
    events = elem[$currentEventHandlers] = {};
  }

  const oldFunc = events[ename];

  // Remove old listener so they don't double up.
  if (oldFunc) {
    elem.removeEventListener(ename, oldFunc);
  }

  // Bind new listener.
  if (newFunc) {
    elem.addEventListener(ename, events[ename] = newFunc);
  }
}

// Attributes that are not handled by Incremental DOM.
attributes.key = attributes.statics = function () {};

// Attributes that *must* be set via a property on all elements.
attributes.checked = attributes.className = attributes.disabled = attributes.value = applyProp;

// V0 Shadow DOM to V1 normalisation.
attributes.name = function (elem, name, value) {
  if (elem.tagName === 'CONTENT') {
    name = 'select';
    value = `[slot="${value}"]`;
  }
  applyDefault(elem, name, value);
};

// Ref handler.
attributes.ref = function (elem, name, value) {
  elem[$ref] = value;
};

// Skip handler.
attributes.skip = function (elem, name, value) {
  if (value) {
    elem[$skipCurrentElement] = true;
  }
};

// Default attribute applicator.
attributes[symbols.default] = function (elem, name, value) {
  // Custom element properties should be set as properties.
  const props = elem.constructor.props;
  if (props && name in props) {
    return applyProp(elem, name, value);
  }

  // Boolean false values should not set attributes at all.
  if (value === false) {
    return;
  }

  // Handle built-in and custom events.
  if (name.indexOf('on') === 0) {
    const firstChar = name[2];
    let eventName;

    if (firstChar === '-') {
      eventName = name.substring(3);
    } else if (firstChar === firstChar.toUpperCase()) {
      eventName = firstChar.toLowerCase() + name.substring(3);
    }

    if (eventName) {
      applyEvent(elem, eventName, value);
      return;
    }
  }

  // Set defined props on the element directly. This ensures properties like
  // "value" on <input> elements get set correctly. Setting those as attributes
  // doesn't always work and setting props is faster than attributes.
  //
  // However, certain props on SVG elements are readonly and error when you try
  // to set them.
  if (name in elem && !('ownerSVGElement' in elem)) {
    applyProp(elem, name, value);
    return;
  }

  // Fallback to default IncrementalDOM behaviour.
  applyDefault(elem, name, value);
};

function resolveTagName(tname) {
  // If the tag name is a function, a Skate constructor or a standard function
  // is supported.
  //
  // - If a Skate constructor, the tag name is extracted from that.
  // - If a standard function, it is used as a helper.
  if (typeof tname === 'function') {
    return tname[$name] || tname;
  }

  // Skate allows the consumer to use <slot /> and it will translate it to
  // <content /> if Shadow DOM V0 is preferred.
  if (tname === 'slot' && fallbackToV0) {
    return 'content';
  }

  // All other tag names are just passed through.
  return tname;
}

function wrapIdomFunc(func, tnameFuncHandler = () => {}) {
  return function wrap(...args) {
    args[0] = resolveTagName(args[0]);
    stackCurrentHelper = null;
    if (typeof args[0] === 'function') {
      // If we've encountered a function, handle it according to the type of
      // function that is being wrapped.
      stackCurrentHelper = args[0];
      return tnameFuncHandler(...args);
    } else if (stackChren.length) {
      // We pass the wrap() function in here so that when it's called as
      // children, it will queue up for the next stack, if there is one.
      stackChren[stackChren.length - 1].push([wrap, args]);
    } else {
      const isElementClosing = func === elementClose;
      const isElementOpening = func === elementOpen;

      if (skipCurrentTree && !isElementClosing) {
        return;
      }

      const elem = func(...args);

      if (isElementOpening && elem[$skipCurrentElement]) {
        skipCurrentTree = true;
      } else if (isElementClosing) {
        const eref = elem[$ref];

        // We delete so that it isn't called again for the same element. If the
        // ref changes, or the element changes, this will be defined again.
        delete elem[$ref];

        // Execute the saved ref after esuring we've cleand up after it.
        if (typeof eref === 'function') {
          eref(elem);
        }

        // If this element was skipped, we should stop skipping the tree since
        // the element is now closing.
        if (elem[$skipCurrentElement]) {
          skipCurrentTree = false;
        }
      }

      return elem;
    }
  };
}

function newAttr(...args) {
  if (stackCurrentHelper) {
    stackCurrentHelper[$stackCurrentHelperProps][args[0]] = args[1];
  } else if (stackChren.length) {
    stackChren[stackChren.length - 1].push([newAttr, args]);
  } else {
    overrideArgs.push(args[0]);
    overrideArgs.push(args[1]);
  }
}

function stackOpen(tname, key, statics, ...attrs) {
  const props = { key, statics };
  for (let a = 0; a < attrs.length; a += 2) {
    props[attrs[a]] = attrs[a + 1];
  }
  tname[$stackCurrentHelperProps] = props;
  stackChren.push([]);
}

function stackClose(tname) {
  const chren = stackChren.pop();
  const props = tname[$stackCurrentHelperProps];
  delete tname[$stackCurrentHelperProps];
  return tname(props, () => chren.forEach(args => args[0](...args[1])));
}

function stackVoid(...args) {
  stackOpen(...args);
  return stackClose(args[0]);
}

// Incremental DOM overrides
// -------------------------

// We must override internal functions that call internal Incremental DOM
// functions because we can't override the internal references. This means
// we must roughly re-implement their behaviour. Luckily, they're fairly
// simple.
const newElementOpenEnd = wrapIdomFunc(() => {
  const node = newElementOpen(...overrideArgs);
  overrideArgs = null;
  return node;
});
const newElementOpenStart = wrapIdomFunc((...args) => {
  overrideArgs = args;
}, stackOpen);

// Standard open / closed overrides don't need to reproduce internal behaviour
// because they are the ones referenced from *End and *Start.
const newElementOpen = wrapIdomFunc(elementOpen, stackOpen);
const newElementClose = wrapIdomFunc(elementClose, stackClose);

// Ensure we call our overridden functions instead of the internal ones.
const newElementVoid = wrapIdomFunc(elementVoid, stackVoid);

// Text override ensures their calls can queue if using function helpers.
const newText = wrapIdomFunc(text);

// Convenience function for declaring an Incremental DOM element using
// hyperscript-style syntax.
export function element(tname, attrs, chren) {
  const atype = typeof attrs;

  // If attributes are a function, then they should be treated as children.
  if (atype === 'function' || atype === 'string') {
    chren = attrs;
  }

  // Ensure the attributes are an object.
  if (atype !== 'object') {
    attrs = {};
  }

  // We open the element so we can set attrs after.
  newElementOpenStart(tname, attrs.key, attrs.statics);

  // Delete so special attrs don't actually get set.
  delete attrs.key;
  delete attrs.statics;

  // Set attributes.
  Object.keys(attrs).forEach(name => newAttr(name, attrs[name]));

  // Close before we render the descendant tree.
  newElementOpenEnd(tname);

  const ctype = typeof chren;
  if (ctype === 'function') {
    chren();
  } else if (ctype === 'string' || ctype === 'number') {
    newText(chren);
  }

  return newElementClose(tname);
}

// We don't have to do anything special for the text function; it's just a
// straight export from Incremental DOM.
export {
  newAttr as attr,
  newElementClose as elementClose,
  newElementOpen as elementOpen,
  newElementOpenEnd as elementOpenEnd,
  newElementOpenStart as elementOpenStart,
  newElementVoid as elementVoid,
  newText as text,
};
<|endoftext|>


<commit_before>var sanitizer = require('sanitizer')
	map = require('./map.js');

function objectToXML(obj, namespace) {
	var xml = [];

	map(obj, function (key, value) {
		var attributes = '';

		if (value && value['@']) {
			attributes = map(value['@'], function (key, value) {
				if (value && value.constructor.name == 'Date') {
					return key + '="' + fixupDate(value) + '"';
				}
				else {
					return key + '="' + value + '"';
				}
			}).join(' ');

			value = value['#'];
		}

		if (Array.isArray(value)) {
			map(value, function (ix, value) {
				var tmp = {};

				tmp[key] = value;

				xml.push(objectToXML(tmp));
			});
		}
		else if (value === null || value === undefined) {
			xml.push('<' + ((namespace) ? namespace + ':' : '') + key + ((attributes) ? ' ' + attributes : ''))

			//check to see if key is a ?something?
			if (/^\?.*\?$/.test(key)) {
				xml.push('>\n');
			}
			else {
				xml.push(' />');
			}
		}
		else {
			xml.push('<' + ((namespace) ? namespace + ':' : '') + key + ((attributes) ? ' ' + attributes : '') + '>')

			if (value && value.constructor.name == 'Date') {
				xml.push(fixupDate(value));
			}
			else if (typeof (value) == 'object') {
				xml.push(objectToXML(value, namespace));
			}
			else {
				if (value && typeof(value) == 'string') {
					value = sanitizer.escape(value);
				}

				xml.push(value);
			}

			xml.push('</' + ((namespace) ? namespace + ':' : '') + key.split(/\ /)[0] + '>')
		}
	});

	return xml.join('');
}

module.exports = objectToXML;

function fixupDate(date) {
	var newDate = new Date(date).toISOString();
	//strip off the milisecconds and the Z
	return newDate.substr(0, newDate.length -5);
}<commit_msg>objectToXML: add nice formatting<commit_after>var sanitizer = require('sanitizer')
	map = require('./map.js');

function objectToXML(obj, namespace, depth) {
	var xml = [];
	depth = depth || 0;

	map(obj, function (key, value) {
		var attributes = '';

		if (value && value['@']) {
			attributes = map(value['@'], function (key, value) {
				if (value && value.constructor.name == 'Date') {
					return key + '="' + fixupDate(value) + '"';
				}
				else {
					return key + '="' + value + '"';
				}
			}).join(' ');

			value = value['#'];
		}

		if (Array.isArray(value)) {
			map(value, function (ix, value) {
				var tmp = {};

				tmp[key] = value;

				xml.push(objectToXML(tmp, namespace, depth));
			});
		}
		else if (value === null || value === undefined) {
			for (var x = 0; x < depth; x++) {
				xml.push('  ');
			}

			xml.push('<' + ((namespace) ? namespace + ':' : '') + key + ((attributes) ? ' ' + attributes : ''))

			//check to see if key is a ?something?
			if (/^\?.*\?$/.test(key)) {
				xml.push('>\n');
			}
			else {
				xml.push(' />\n');
			}
		}
		else {
			for (var x = 0; x < depth; x++) {
				xml.push('  ');
			}

			xml.push('<' + ((namespace) ? namespace + ':' : '') + key + ((attributes) ? ' ' + attributes : '') + '>')

			if (value && value.constructor.name == 'Date') {
				xml.push(fixupDate(value));
			}
			else if (typeof (value) == 'object') {
				xml.push('\n');
				xml.push(objectToXML(value, namespace, depth + 1));

				for (var x = 0; x < depth; x++) {
					xml.push('  ');
				}
			}
			else {
				if (value && typeof(value) == 'string') {
					value = sanitizer.escape(value);
				}

				xml.push(value);
			}

			xml.push('</' + ((namespace) ? namespace + ':' : '') + key.split(/\ /)[0] + '>\n')
		}
	});

	return xml.join('');
}

module.exports = objectToXML;

function fixupDate(date) {
	var newDate = new Date(date).toISOString();
	//strip off the milisecconds and the Z
	return newDate.substr(0, newDate.length -5);
}<|endoftext|>


<commit_before>export default function tryRequire(path) {
  try {
    return require(path);
  } catch (e) {
    if (e.message === `Cannot find module '${ path }'`) {
      return false;
    } else {
      throw e;
    }
  }
}
<commit_msg>remove unnecessary else block<commit_after>export default function tryRequire(path) {
  try {
    return require(path);
  } catch (e) {
    if (e.message === `Cannot find module '${ path }'`) {
      return false;
    }
    throw e;
  }
}
<|endoftext|>


<commit_before>module.exports = function(headers){
	var validation = false
	if (headers instanceof Array) {
		headers.forEach(function(curr){
			if (curr instanceof Object) {
				if (curr.source) {
					if (curr.headers instanceof Array) {
						curr.headers.forEach(function(header){
							if (!header.key || !header.value)
								throw new Error('Each element in headers array must have key and value properties')
						})
						validation = headers
					} else {
						throw new Error('The source ' + curr.source + ' hasn\'t the headers array')
					}
				} else {
					throw new Error('Missing source key in an headers element')
				}
			} else {
				throw new Error('Each element in array headers must be an Object')
			}
		})
	} else {
		throw new Error('Headers must be an Array')
	}
	return validation
}<commit_msg>added whitelist of allowed headers<commit_after>var allowed_headers = ['cache-control', 'expires']

module.exports = function(headers){
	var validation = false
	if (headers instanceof Array) {
		headers.forEach(function(curr){
			if (curr instanceof Object) {
				if (curr.source) {
					if (curr.headers instanceof Array) {
						curr.headers.forEach(function(header){
							if (!header.key || !header.value)
								throw new Error('Each object in headers array must have key and value properties')
							if (allowed_headers.indexOf(header.key.toLowerCase()) == -1)
								throw new Error('Header ' + header.key + ' not allowed. You can only use this headers: ' + allowed_headers.toString())
						})
						validation = headers
					} else {
						throw new Error('The source ' + curr.source + ' hasn\'t the headers array')
					}
				} else {
					throw new Error('Missing source')
				}
			} else {
				throw new Error('Each element in array headers must be an Object')
			}
		})
	} else {
		throw new Error('Headers must be an Array')
	}
	return validation
}<|endoftext|>


<commit_before>var Viz = React.createClass({
    displayName: "pipeviz-graph",
    render: function() {
        return React.DOM.svg({
            className: "pipeviz",
            width: "83%",
            children: [React.DOM.g({
                id: 'commit-pipeline',
                children: [React.DOM.g({
                    id: 'commitview-edges'
                }), React.DOM.g({
                    id: 'commit-axis',
                    width: this.props.width,
                    height: 30,
                    transform: 'translate(0,' + (this.props.height - 30) + ')'
                })]
            })]
        });
    },
    shouldComponentUpdate: function(nextProps, prevProps) {
        return nextProps.vizdata !== undefined;
    },
    componentDidUpdate: function() {
        // x-coordinate space is the elided diameter as a factor of viewport width
        var selections = {},
            props = this.props,
            tf = createTransforms(props.width, props.height - 30, props.vizdata.ediam, props.vizdata.segments.length, props.opts.revx.selected);

        // Outer g first
        selections.outerg = d3.select(this.getDOMNode()).select('#commit-pipeline');

        // Vertices
        selections.vertices = selections.outerg.selectAll('.node')
            .data(props.vizdata.vertices, function(d) { return d.ref.id; });

        selections.vertices.exit().transition().remove(); // exit removes vertex
        // tons of stuff to do on enter
        selections.veg = selections.vertices.enter().append('g') // store the enter group and build it up
            .attr('class', function(d) { return 'node ' + d.ref.Typ(); })
            // so we don't transition from 0,0
            .attr('transform', function(d) { return 'translate(' + tf.x(d.x) + ',' + tf.y(d.y) + ')'; })
            // and start from invisible
            .style('opacity', 0)
            // attach click handler for infobar
            .on('click', props.selected);
        selections.veg.append('circle');
        selections.nte = selections.veg.append('text');
        selections.nte.append('tspan') // add vertex label tspan on enter
            .attr('class', 'vtx-label');
        selections.nte.append('tspan') // add commit info tspan on enter and position it
            .attr('dy', "1.4em")
            .attr('x', 0)
            .attr('class', function(d) {
                var output = 'commit-subtext',
                    commit = getCommit(props.graph, d.ref),
                    testState = getTestState(props.graph, commit);
                if (testState !== undefined) {
                    output += ' commit-' + testState;
                }

                return output;
            });

        // now, update
        selections.vertices.transition() // update assigns the position via transform
            .attr('transform', function(d) { return 'translate(' + tf.x(d.x) + ',' + tf.y(d.y) + ')'; })
            .style('opacity', 1);

        // now work within the g for each vtx
        selections.vertices.select('circle').transition()
            .attr('r', function(d) { return d.ref.Typ() === "commit" ? tf.unit()*0.03 : tf.unit()*0.3; });

        // and the info text
        selections.nodetext = selections.vertices.select('text').transition();
        selections.nodetext.select('.vtx-label')
            .text(function(d) { return d.ref.propv("lgroup"); }); // set text value to data from lgroup
        selections.nodetext.select('.commit-subtext') // set the commit text on update
            .text(function(d) { return getCommit(props.graph, d.ref).propv("sha1").slice(0, 7); });

        // Links
        selections.links = selections.outerg.select('#commitview-edges').selectAll('.link')
            .data(props.vizdata.links, function(d) {
                return d[0].ref.id + '-' +  d[1].ref.id;
            });

        selections.links.exit().transition()
            .style('opacity', 0)
            .remove(); // exit removes line
        selections.links.enter().append('line') // enter appends a line
            .attr('class', 'link')
            .style('opacity', 0)
            // set all these initially so that we don't transition from 0,0,0,0
            .attr('x1', function(d) { return tf.x(d[0].x); })
            .attr('y1', function(d) { return tf.y(d[0].y); })
            .attr('x2', function(d) { return tf.x(d[1].x); })
            .attr('y2', function(d) { return tf.y(d[1].y); });

        selections.links.transition() // update sets the line's x and y positions
            .attr('x1', function(d) { return tf.x(d[0].x); })
            .attr('y1', function(d) { return tf.y(d[0].y); })
            .attr('x2', function(d) { return tf.x(d[1].x); })
            .attr('y2', function(d) { return tf.y(d[1].y); })
            .style('opacity', 1);

        // commit elision markers
        selections.elisions = selections.outerg.selectAll('.elision-bar')
            .data(_.map(props.vizdata.elranges, function(range) {
                // creates the same string as what's used in vizdata.xmap
                return range[0] + ' - ' + range[range.length - 1];
            }), _.identity);

        selections.elisions.exit().transition().remove(); // remove on exit
        selections.elisions.enter().append('line')
            .attr('class', 'elision-bar')
            .style('opacity', 0)
            // set all these initially so that we don't transition from 0,0,0,0
            .attr('x1', function(d) { return tf.x(props.vizdata.xmap[d]); })
            .attr('y1', 0)
            .attr('x2', function(d) { return tf.x(props.vizdata.xmap[d]); })
            .attr('y2', props.height - 30);

        selections.elisions.transition() // update sets x position
            .style('opacity', 1)
            .attr('x1', function(d) { return tf.x(props.vizdata.xmap[d]); })
            .attr('y1', 0)
            .attr('x2', function(d) { return tf.x(props.vizdata.xmap[d]); })
            .attr('y2', props.height - 30)
            .attr('stroke-width', tf.unit() * 0.007);

        // Commit distance axis
        var xlbls = _.map(_.pairs(props.vizdata.xmap).sort(function(a, b) { return a[1] - b[1]; }), _.head),
            xscale = d3.scale.ordinal()
                .domain(xlbls)
                .range(_.map(xlbls, function(label) {
                    return tf.x(props.vizdata.xmap[label]);
                })),
            xaxis = d3.svg.axis()
                .scale(xscale)
                .orient('bottom')
                .ticks(props.vizdata.ediam);

        d3.select('#commit-axis').transition()
            .call(xaxis);
            //.append('text')
                //.attr('transform', 'translate(' + tf.x(0) + ',-5)')
                //.attr('text-anchor', 'start')
                //.text('distance to root');
    },
});

var VizPrep = React.createClass({
    getDefaultProps: function() {
        return {
            width: 0,
            height: 0,
            graph: pvGraph({id: 0, vertices: []}),
            focalRepo: "",
            opts: {},
        };
    },
    shouldComponentUpdate: function(nextProps) {
        // In the graph object, state is invariant with respect to the message id.
        return nextProps.graph.mid !== this.props.graph.mid ||
            JSON.stringify(this.props.opts) !== JSON.stringify(nextProps.opts);
    },
    render: function() {
        return React.createElement(Viz, {
            width: this.props.width,
            height: this.props.height,
            graph: this.props.graph,
            vizdata: extractVizGraph(this.props.graph, this.props.focalRepo),
            opts: this.props.opts,
            selected: this.props.selected,
        });
    },
});

var InfoBar = React.createClass({
    displayName: 'pipeviz-info',
    render: function() {
        var t = this.props.selected,
            cmp = this,
            pvg = this.props.pvg;

        var outer = {
            id: "infobar",
            children: []
        };

        if (_.isUndefined(t)) {
            outer.children = [React.DOM.p({}, "nothing selected")];
            // drop out early for the empty case
            return React.DOM.div(outer);
        }

        // TODO right now we only have two possibilities - commit or logic-state - but this will need to become its WHOLE own subsystem
        if (t.vertex.type === "logic-state") {
            // First, pick a title. Start with the nick
            var infotitle = "Instance of ",
                listitems = [];
            if (!_.isUndefined(t.propv('nick'))) {
                // TODO nick is not great since it's actually set per logic-state
                infotitle += "'" + t.propv('nick') + "'";
                // since we're not showing the repo addr in the title, put it in here
                listitems.push(React.DOM.li({}, "From repository " + getRepositoryName(pvg, t)));
            } else {
                // No nick, so grab the repo addr
                infotitle += "'" + getRepositoryName(pvg, t) + "'";
            }
            outer.children.push(React.DOM.h3({}, infotitle));

            var env = getEnvironment(pvg, t),
                commit = getCommit(pvg, t);

            listitems.push(React.DOM.li({}, "Located on " + getEnvName(env) + " at " + t.propv("path")));
            listitems.push(React.DOM.li({}, "Commit info:"));
            listitems.push(React.DOM.ul({children: [
                React.DOM.li({}, "Sha1: " + commit.propv("sha1")),
                React.DOM.li({}, "Author: " + commit.propv("author")),
                React.DOM.li({}, "Date: " + commit.propv("date")),
                React.DOM.li({}, "Subject: " + commit.propv("subject")),
            ]}));

            outer.children.push(React.DOM.ul({children: listitems}));
        } else { // can only be a commit, for now
            outer.children.push(React.DOM.h3({}, "Commit from " + getRepositoryName(pvg, t)));
            outer.children.push(React.DOM.ul({children: [
                React.DOM.li({}, "Sha1: " + t.propv("sha1")),
                React.DOM.li({}, "Author: " + t.propv("author")),
                React.DOM.li({}, "Date: " + t.propv("date")),
                React.DOM.li({}, "Subject: " + t.propv("subject")),
            ]}));
        }

        return React.DOM.div(outer);
    }
});

var ControlBar = React.createClass({
    displayName: 'pipeviz-control',
    render: function() {
        var oc = this.props.changeOpts;
            var boxes = _.map(this.props.opts, function(v, opt) {
            return (React.createElement("input", {
                key: opt,
                type: "checkbox",
                checked: v.selected,
                onChange: oc.bind(this, opt, v)
            }, v.label));
        });

        return (
            React.createElement("div", {id: "controlbar"},
                "Options: ", boxes
            )
        );
    },
});

var App = React.createClass({
    dispayName: "pipeviz",
    getInitialState: function() {
        return {
            selected: undefined,
            opts: {
                revx: {label: "Reverse x positions", selected: false},
                noelide: {label: "No commit elision", selected: false},
            },
        };
    },
    changeOpts: function(opt, v) {
        v.selected = !v.selected;
        this.setState({opts: _.merge(this.state.opts, _.zipObject([[opt, v]]))});
    },
    setSelected: function(tgt) {
        this.setState({selected: tgt.ref});
    },
    getDefaultProps: function() {
        return {
            // TODO uggghhh lol hardcoding
            vizWidth: window.innerWidth * 0.83,
            vizHeight: window.innerHeight - 30,
            graph: pvGraph({id: 0, vertices: []}),
        };
    },
    render: function() {
        return React.createElement("div", {id: "pipeviz"},
            React.createElement(ControlBar, {opts: this.state.opts, changeOpts: this.changeOpts}),
            React.createElement(VizPrep, {
                width: this.props.vizWidth,
                height: this.props.vizHeight,
                graph: this.props.graph,
                focalRepo: vizExtractor.mostCommonRepo(this.props.graph),
                opts: JSON.parse(JSON.stringify(this.state.opts)),
                selected: this.setSelected,
            }),
            React.createElement(InfoBar, {
                selected: this.state.selected,
                pvg: this.props.graph,
            })
        );
    },
});

var e = React.render(React.createElement(App), document.body);
var genesis = new WebSocket("ws://" + window.location.hostname + ":" + window.location.port + "/sock");
var lastg;
genesis.onmessage = function(m) {
    lastg = pvGraph(JSON.parse(m.data));
    e.setProps({graph: lastg});
};
<commit_msg>Rename opt bool for less naming confusion<commit_after>var Viz = React.createClass({
    displayName: "pipeviz-graph",
    render: function() {
        return React.DOM.svg({
            className: "pipeviz",
            width: "83%",
            children: [React.DOM.g({
                id: 'commit-pipeline',
                children: [React.DOM.g({
                    id: 'commitview-edges'
                }), React.DOM.g({
                    id: 'commit-axis',
                    width: this.props.width,
                    height: 30,
                    transform: 'translate(0,' + (this.props.height - 30) + ')'
                })]
            })]
        });
    },
    shouldComponentUpdate: function(nextProps, prevProps) {
        return nextProps.vizdata !== undefined;
    },
    componentDidUpdate: function() {
        // x-coordinate space is the elided diameter as a factor of viewport width
        var selections = {},
            props = this.props,
            tf = createTransforms(props.width, props.height - 30, props.vizdata.ediam, props.vizdata.segments.length, props.opts.revx.flag);

        // Outer g first
        selections.outerg = d3.select(this.getDOMNode()).select('#commit-pipeline');

        // Vertices
        selections.vertices = selections.outerg.selectAll('.node')
            .data(props.vizdata.vertices, function(d) { return d.ref.id; });

        selections.vertices.exit().transition().remove(); // exit removes vertex
        // tons of stuff to do on enter
        selections.veg = selections.vertices.enter().append('g') // store the enter group and build it up
            .attr('class', function(d) { return 'node ' + d.ref.Typ(); })
            // so we don't transition from 0,0
            .attr('transform', function(d) { return 'translate(' + tf.x(d.x) + ',' + tf.y(d.y) + ')'; })
            // and start from invisible
            .style('opacity', 0)
            // attach click handler for infobar
            .on('click', props.selected);
        selections.veg.append('circle');
        selections.nte = selections.veg.append('text');
        selections.nte.append('tspan') // add vertex label tspan on enter
            .attr('class', 'vtx-label');
        selections.nte.append('tspan') // add commit info tspan on enter and position it
            .attr('dy', "1.4em")
            .attr('x', 0)
            .attr('class', function(d) {
                var output = 'commit-subtext',
                    commit = getCommit(props.graph, d.ref),
                    testState = getTestState(props.graph, commit);
                if (testState !== undefined) {
                    output += ' commit-' + testState;
                }

                return output;
            });

        // now, update
        selections.vertices.transition() // update assigns the position via transform
            .attr('transform', function(d) { return 'translate(' + tf.x(d.x) + ',' + tf.y(d.y) + ')'; })
            .style('opacity', 1);

        // now work within the g for each vtx
        selections.vertices.select('circle').transition()
            .attr('r', function(d) { return d.ref.Typ() === "commit" ? tf.unit()*0.03 : tf.unit()*0.3; });

        // and the info text
        selections.nodetext = selections.vertices.select('text').transition();
        selections.nodetext.select('.vtx-label')
            .text(function(d) { return d.ref.propv("lgroup"); }); // set text value to data from lgroup
        selections.nodetext.select('.commit-subtext') // set the commit text on update
            .text(function(d) { return getCommit(props.graph, d.ref).propv("sha1").slice(0, 7); });

        // Links
        selections.links = selections.outerg.select('#commitview-edges').selectAll('.link')
            .data(props.vizdata.links, function(d) {
                return d[0].ref.id + '-' +  d[1].ref.id;
            });

        selections.links.exit().transition()
            .style('opacity', 0)
            .remove(); // exit removes line
        selections.links.enter().append('line') // enter appends a line
            .attr('class', 'link')
            .style('opacity', 0)
            // set all these initially so that we don't transition from 0,0,0,0
            .attr('x1', function(d) { return tf.x(d[0].x); })
            .attr('y1', function(d) { return tf.y(d[0].y); })
            .attr('x2', function(d) { return tf.x(d[1].x); })
            .attr('y2', function(d) { return tf.y(d[1].y); });

        selections.links.transition() // update sets the line's x and y positions
            .attr('x1', function(d) { return tf.x(d[0].x); })
            .attr('y1', function(d) { return tf.y(d[0].y); })
            .attr('x2', function(d) { return tf.x(d[1].x); })
            .attr('y2', function(d) { return tf.y(d[1].y); })
            .style('opacity', 1);

        // commit elision markers
        selections.elisions = selections.outerg.selectAll('.elision-bar')
            .data(_.map(props.vizdata.elranges, function(range) {
                // creates the same string as what's used in vizdata.xmap
                return range[0] + ' - ' + range[range.length - 1];
            }), _.identity);

        selections.elisions.exit().transition().remove(); // remove on exit
        selections.elisions.enter().append('line')
            .attr('class', 'elision-bar')
            .style('opacity', 0)
            // set all these initially so that we don't transition from 0,0,0,0
            .attr('x1', function(d) { return tf.x(props.vizdata.xmap[d]); })
            .attr('y1', 0)
            .attr('x2', function(d) { return tf.x(props.vizdata.xmap[d]); })
            .attr('y2', props.height - 30);

        selections.elisions.transition() // update sets x position
            .style('opacity', 1)
            .attr('x1', function(d) { return tf.x(props.vizdata.xmap[d]); })
            .attr('y1', 0)
            .attr('x2', function(d) { return tf.x(props.vizdata.xmap[d]); })
            .attr('y2', props.height - 30)
            .attr('stroke-width', tf.unit() * 0.007);

        // Commit distance axis
        var xlbls = _.map(_.pairs(props.vizdata.xmap).sort(function(a, b) { return a[1] - b[1]; }), _.head),
            xscale = d3.scale.ordinal()
                .domain(xlbls)
                .range(_.map(xlbls, function(label) {
                    return tf.x(props.vizdata.xmap[label]);
                })),
            xaxis = d3.svg.axis()
                .scale(xscale)
                .orient('bottom')
                .ticks(props.vizdata.ediam);

        d3.select('#commit-axis').transition()
            .call(xaxis);
            //.append('text')
                //.attr('transform', 'translate(' + tf.x(0) + ',-5)')
                //.attr('text-anchor', 'start')
                //.text('distance to root');
    },
});

var VizPrep = React.createClass({
    getDefaultProps: function() {
        return {
            width: 0,
            height: 0,
            graph: pvGraph({id: 0, vertices: []}),
            focalRepo: "",
            opts: {},
        };
    },
    shouldComponentUpdate: function(nextProps) {
        // In the graph object, state is invariant with respect to the message id.
        return nextProps.graph.mid !== this.props.graph.mid ||
            JSON.stringify(this.props.opts) !== JSON.stringify(nextProps.opts);
    },
    render: function() {
        return React.createElement(Viz, {
            width: this.props.width,
            height: this.props.height,
            graph: this.props.graph,
            vizdata: extractVizGraph(this.props.graph, this.props.focalRepo, this.props.opts.noelide.flag),
            opts: this.props.opts,
            selected: this.props.selected,
        });
    },
});

var InfoBar = React.createClass({
    displayName: 'pipeviz-info',
    render: function() {
        var t = this.props.selected,
            cmp = this,
            pvg = this.props.pvg;

        var outer = {
            id: "infobar",
            children: []
        };

        if (_.isUndefined(t)) {
            outer.children = [React.DOM.p({}, "nothing selected")];
            // drop out early for the empty case
            return React.DOM.div(outer);
        }

        // TODO right now we only have two possibilities - commit or logic-state - but this will need to become its WHOLE own subsystem
        if (t.vertex.type === "logic-state") {
            // First, pick a title. Start with the nick
            var infotitle = "Instance of ",
                listitems = [];
            if (!_.isUndefined(t.propv('nick'))) {
                // TODO nick is not great since it's actually set per logic-state
                infotitle += "'" + t.propv('nick') + "'";
                // since we're not showing the repo addr in the title, put it in here
                listitems.push(React.DOM.li({}, "From repository " + getRepositoryName(pvg, t)));
            } else {
                // No nick, so grab the repo addr
                infotitle += "'" + getRepositoryName(pvg, t) + "'";
            }
            outer.children.push(React.DOM.h3({}, infotitle));

            var env = getEnvironment(pvg, t),
                commit = getCommit(pvg, t);

            listitems.push(React.DOM.li({}, "Located on " + getEnvName(env) + " at " + t.propv("path")));
            listitems.push(React.DOM.li({}, "Commit info:"));
            listitems.push(React.DOM.ul({children: [
                React.DOM.li({}, "Sha1: " + commit.propv("sha1")),
                React.DOM.li({}, "Author: " + commit.propv("author")),
                React.DOM.li({}, "Date: " + commit.propv("date")),
                React.DOM.li({}, "Subject: " + commit.propv("subject")),
            ]}));

            outer.children.push(React.DOM.ul({children: listitems}));
        } else { // can only be a commit, for now
            outer.children.push(React.DOM.h3({}, "Commit from " + getRepositoryName(pvg, t)));
            outer.children.push(React.DOM.ul({children: [
                React.DOM.li({}, "Sha1: " + t.propv("sha1")),
                React.DOM.li({}, "Author: " + t.propv("author")),
                React.DOM.li({}, "Date: " + t.propv("date")),
                React.DOM.li({}, "Subject: " + t.propv("subject")),
            ]}));
        }

        return React.DOM.div(outer);
    }
});

var ControlBar = React.createClass({
    displayName: 'pipeviz-control',
    render: function() {
        var oc = this.props.changeOpts;
            var boxes = _.map(this.props.opts, function(v, opt) {
            return (React.createElement("input", {
                key: opt,
                type: "checkbox",
                checked: v.flag,
                onChange: oc.bind(this, opt, v)
            }, v.label));
        });

        return (
            React.createElement("div", {id: "controlbar"},
                "Options: ", boxes
            )
        );
    },
});

var App = React.createClass({
    dispayName: "pipeviz",
    getInitialState: function() {
        return {
            selected: undefined,
            opts: {
                revx: {label: "Reverse x positions", flag: false},
                noelide: {label: "No commit elision", flag: false},
            },
        };
    },
    changeOpts: function(opt, v) {
        v.flag = !v.flag;
        this.setState({opts: _.merge(this.state.opts, _.zipObject([[opt, v]]))});
    },
    setSelected: function(tgt) {
        this.setState({selected: tgt.ref});
    },
    getDefaultProps: function() {
        return {
            // TODO uggghhh lol hardcoding
            vizWidth: window.innerWidth * 0.83,
            vizHeight: window.innerHeight - 30,
            graph: pvGraph({id: 0, vertices: []}),
        };
    },
    render: function() {
        return React.createElement("div", {id: "pipeviz"},
            React.createElement(ControlBar, {opts: this.state.opts, changeOpts: this.changeOpts}),
            React.createElement(VizPrep, {
                width: this.props.vizWidth,
                height: this.props.vizHeight,
                graph: this.props.graph,
                focalRepo: vizExtractor.mostCommonRepo(this.props.graph),
                opts: JSON.parse(JSON.stringify(this.state.opts)),
                selected: this.setSelected,
            }),
            React.createElement(InfoBar, {
                selected: this.state.selected,
                pvg: this.props.graph,
            })
        );
    },
});

var e = React.render(React.createElement(App), document.body);
var genesis = new WebSocket("ws://" + window.location.hostname + ":" + window.location.port + "/sock");
var lastg;
genesis.onmessage = function(m) {
    lastg = pvGraph(JSON.parse(m.data));
    e.setProps({graph: lastg});
};
<|endoftext|>


<commit_before>import Head from "next/head";
import Meta from "../components/Meta";
import Link from "next/link";
import {
  Container,
  SingleColumn,
  Section,
  IntraNav,
} from "foundation-design-system";
import Footer from "../components/Footer";
import Header from "../components/Header";
import BackgroundImage from "../components/BackgroundImage";
import { getAllPosts, formatDate, generateDisplayDate } from "../lib/lib";
import { contact } from "../lib/constants";

export default function Blog({ posts, search }) {
  const post = {
    title: "Blog",
    description:
      "Stories from the broader Urbit community, the Urbit Foundation, and the many people contributing to Urbit.",
  };
  return (
    <Container>

        <title>Blog • urbit.org</title>
        {Meta(post)}

      <IntraNav ourSite="https://urbit.org" search={search} />
      <SingleColumn>

Blog

              Stories from the broader Urbit community, the Urbit Foundation,
              and the many people contributing to Urbit.

              Subscribe to the Urbit Newsletter
              for regular updates, including new blog posts and events.

          {posts.map((post) => {
            const date = generateDisplayDate(post.date);
            return (

                <Link href={`/blog/${post.slug}`}>

                    {
                      // Not all blog posts have images
                      post.extra.image ? (
                        <BackgroundImage
                          src={post.extra.image}
                          className="rounded-lg aspect-w-5 aspect-h-4"
                        />
                      ) : null
                    }

{post.title}

                      {post.extra.author ? (

                          {post.extra.author}

                      ) : null}
                      {post.extra.ship ? (
                        <Link href={`/ids/${post.extra.ship}`} passHref>

                            {post.extra.ship}

                        </Link>
                      ) : null}

                      {formatDate(date)}

                </Link>

            );
          })}

      </SingleColumn>

    </Container>
  );
}

export async function getStaticProps() {
  const posts = getAllPosts(
    ["title", "slug", "date", "description", "extra"],
    "blog",
    "date"
  );

  return {
    props: { posts },
  };
}
<commit_msg>updated blog index<commit_after>import Head from "next/head";
import Meta from "../components/Meta";
import Link from "next/link";
import {
  Container,
  SingleColumn,
  Section,
  IntraNav,
} from "foundation-design-system";
import Footer from "../components/Footer";
import Header from "../components/Header";
import BackgroundImage from "../components/BackgroundImage";
import { getAllPosts, formatDate, generateDisplayDate } from "../lib/lib";
import { contact } from "../lib/constants";

export default function Blog({ posts, search }) {
  const post = {
    title: "Blog",
    description:
      "Stories from the broader Urbit community, the Urbit Foundation, and the many people contributing to Urbit.",
  };
  return (
    <Container>

        <title>Blog • urbit.org</title>
        {Meta(post)}

      <IntraNav ourSite="https://urbit.org" search={search} />
      <SingleColumn>

Blog

              Stories from the broader Urbit community, the Urbit Foundation,
              and the many people contributing to Urbit.

              Subscribe to the Urbit Newsletter
              for regular updates, including new blog posts and events.

          {posts.map((post) => {
            const date = generateDisplayDate(post.date);
            return (

      <Link href={`/blog/${post.slug}`}>

          {
            // Not all blog posts have images
            post.extra.image ? (
              <BackgroundImage
                src={post.extra.image}
                className="rounded-lg aspect-w-5 aspect-h-4 w-full"
              />
            ) :

          }

{post.title}

                {post.extra.author ? (

{post.extra.author}

                ) : null}
                {post.extra.ship ? (
                  <Link
                    href={`https://urbit.org/ids/${post.extra.ship}`}
                    passHref
                  >

                      {post.extra.ship}

                  </Link>
                ) : null}

{formatDate(date)}

            {post?.description &&
{post.description}
}

      </Link>

            );
          })}

      </SingleColumn>

    </Container>
  );
}

export async function getStaticProps() {
  const posts = getAllPosts(
    ["title", "slug", "date", "description", "extra"],
    "blog",
    "date"
  );

  return {
    props: { posts },
  };
}
<|endoftext|>


<commit_before>const Broker = require('../index')
const COORDINATOR_TYPES = require('../../protocol/coordinatorTypes')
const {
  secureRandom,
  createTopic,
  createConnection,
  newLogger,
  retryProtocol,
} = require('testHelpers')

describe('Broker > AddPartitionsToTxn', () => {
  let broker, seedBroker, transactionalId, producerId, producerEpoch, topicName

  beforeEach(async () => {
    transactionalId = `producer-group-id-${secureRandom()}`
    topicName = `test-topic-${secureRandom()}`

    seedBroker = new Broker({
      connection: createConnection(),
      logger: newLogger(),
    })
    await seedBroker.connect()
    await createTopic({ topic: topicName, partitions: 4 })

    const {
      coordinator: { host, port },
    } = await retryProtocol(
      'GROUP_COORDINATOR_NOT_AVAILABLE',
      async () =>
        await seedBroker.findGroupCoordinator({
          groupId: transactionalId,
          coordinatorType: COORDINATOR_TYPES.TRANSACTION,
        })
    )

    broker = new Broker({
      connection: createConnection({ host, port }),
      logger: newLogger(),
    })
    await broker.connect()
    ;({ producerId, producerEpoch } = await broker.initProducerId({
      transactionalId,
      transactionTimeout: 30000,
    }))
  })

  afterEach(async () => {
    await seedBroker.disconnect()
    await broker.disconnect()
  })

  test('request', async () => {
    const result = await broker.addPartitionsToTxn({
      transactionalId,
      producerId,
      producerEpoch,
      topics: [
        {
          topic: topicName,
          partitions: [1, 2],
        },
      ],
    })

    expect(result).toEqual({
      throttleTime: 0,
      errors: [
        {
          topic: topicName,
          partitionErrors: [{ errorCode: 0, partition: 1 }, { errorCode: 0, partition: 2 }],
        },
      ],
    })
  })

  test('throws for invalid producer id', async () => {
    expect(
      broker.addPartitionsToTxn({
        transactionalId,
        producerId: 'foo',
        producerEpoch,
        topics: [
          {
            topic: topicName,
            partitions: [1, 2],
          },
        ],
      })
    ).rejects.toEqual({
      error:
        'The producer attempted to use a producer id which is not currently assigned to its transactional id',
    })
  })
})
<commit_msg>Remove corner case for semicolon on initProducerId broker tests<commit_after>const Broker = require('../index')
const COORDINATOR_TYPES = require('../../protocol/coordinatorTypes')
const {
  secureRandom,
  createTopic,
  createConnection,
  newLogger,
  retryProtocol,
} = require('testHelpers')

describe('Broker > AddPartitionsToTxn', () => {
  let broker, seedBroker, transactionalId, producerId, producerEpoch, topicName

  beforeEach(async () => {
    transactionalId = `producer-group-id-${secureRandom()}`
    topicName = `test-topic-${secureRandom()}`

    seedBroker = new Broker({
      connection: createConnection(),
      logger: newLogger(),
    })

    await seedBroker.connect()
    await createTopic({ topic: topicName, partitions: 4 })

    const {
      coordinator: { host, port },
    } = await retryProtocol(
      'GROUP_COORDINATOR_NOT_AVAILABLE',
      async () =>
        await seedBroker.findGroupCoordinator({
          groupId: transactionalId,
          coordinatorType: COORDINATOR_TYPES.TRANSACTION,
        })
    )

    broker = new Broker({
      connection: createConnection({ host, port }),
      logger: newLogger(),
    })

    await broker.connect()
    const result = await broker.initProducerId({
      transactionalId,
      transactionTimeout: 30000,
    })

    producerId = result.producerId
    producerEpoch = result.producerEpoch
  })

  afterEach(async () => {
    await seedBroker.disconnect()
    await broker.disconnect()
  })

  test('request', async () => {
    const result = await broker.addPartitionsToTxn({
      transactionalId,
      producerId,
      producerEpoch,
      topics: [
        {
          topic: topicName,
          partitions: [1, 2],
        },
      ],
    })

    expect(result).toEqual({
      throttleTime: 0,
      errors: [
        {
          topic: topicName,
          partitionErrors: [{ errorCode: 0, partition: 1 }, { errorCode: 0, partition: 2 }],
        },
      ],
    })
  })

  test('throws for invalid producer id', async () => {
    expect(
      broker.addPartitionsToTxn({
        transactionalId,
        producerId: 'foo',
        producerEpoch,
        topics: [
          {
            topic: topicName,
            partitions: [1, 2],
          },
        ],
      })
    ).rejects.toEqual({
      error:
        'The producer attempted to use a producer id which is not currently assigned to its transactional id',
    })
  })
})
<|endoftext|>