<commit_before>import React from 'react';
import { compose, graphql } from 'react-apollo';
import { connect } from 'react-redux';
import { stopSubmit, startSubmit, reset, change } from 'redux-form';
import { set } from 'react-redux-values';
import ReduxForm from 'declarative-redux-form';
import forceArray from 'force-array';
import get from 'lodash.get';
import intercept from 'apr-intercept';
import find from 'lodash.find';
import sort from 'lodash.sortby';
import remcalc from 'remcalc';

import {
  ViewContainer,
  Message,
  MessageDescription,
  MessageTitle,
  StatusLoader,
  Divider
} from 'joyent-ui-toolkit';

import ListInstances from '@graphql/list-instances.gql';
import StopInstance from '@graphql/stop-instance.gql';
import StartInstance from '@graphql/start-instance.gql';
import RebootInstance from '@graphql/reboot-instance.gql';
import RemoveInstance from '@graphql/remove-instance.gql';
import ToolbarForm from '@components/instances/toolbar';
import Index from '@state/gen-index';
import parseError from '@state/parse-error';

import {
  default as InstanceList,
  Item as InstanceListItem
} from '@components/instances/list';

import InstanceListActions from '@components/instances/footer';

const TABLE_FORM_NAME = 'instance-list-table';
const MENU_FORM_NAME = 'instance-list-menu';

export const List = ({
  instances = [],
  selected = [],
  allowedActions,
  statuses,
  sortBy = 'name',
  sortOrder = 'desc',
  loading = false,
  error = null,
  mutationError = null,
  submitting,
  handleAction,
  toggleSelectAll,
  handleSortBy
}) => {
  const _instances = forceArray(instances);

  const _loading =
    loading && !_instances.length
      ? [
          <Divider key="divider" height={remcalc(30)} transparent />,
          <StatusLoader key="spinner" />
        ]
      : null;

  const _error =
    error && !_instances.length && !_loading ? (
      <Message error>
        <MessageTitle>Ooops!</MessageTitle>
        <MessageDescription>
          An error occurred while loading your instances
        </MessageDescription>
      </Message>
    ) : null;

  const _mutationError = mutationError && (
    <Message error>
      <MessageTitle>Ooops!</MessageTitle>
      <MessageDescription>{mutationError}</MessageDescription>
    </Message>
  );

  const handleStart = selected => handleAction({ name: 'start', selected });
  const handleStop = selected => handleAction({ name: 'stop', selected });
  const handleReboot = selected => handleAction({ name: 'reboot', selected });
  const handleRemove = selected => handleAction({ name: 'remove', selected });

  const _table = !loading ? (
    <ReduxForm form={TABLE_FORM_NAME}>
      {props => (
        <InstanceList
          {...props}
          allSelected={instances.length && selected.length === instances.length}
          sortBy={sortBy}
          sortOrder={sortOrder}
          toggleSelectAll={toggleSelectAll}
          onSortBy={handleSortBy}
        >
          {_instances.map(({ id, ...rest }) => (
            <InstanceListItem
              key={id}
              id={id}
              {...rest}
              onStart={() => handleStart([{ id }])}
              onStop={() => handleStop([{ id }])}
              onReboot={() => handleReboot([{ id }])}
              onRemove={() => handleRemove([{ id }])}
            />
          ))}
        </InstanceList>
      )}
    </ReduxForm>
  ) : null;

  const _footer =
    !loading && selected.length ? (
      <InstanceListActions
        allowedActions={allowedActions}
        statuses={statuses}
        submitting={submitting}
        onStart={() => handleStart(selected)}
        onStop={() => handleStop(selected)}
        onReboot={() => handleReboot(selected)}
        onRemove={() => handleRemove(selected)}
      />
    ) : null;

  return (
    <ViewContainer main>
      <Divider height={remcalc(30)} transparent />
      <ReduxForm form={MENU_FORM_NAME}>
        {props => (
          <ToolbarForm
            {...props}
            searchLabel="Filter instances"
            searchPlaceholder="Search for name, state, tags, etc..."
            searchable={!_loading}
            actionLabel="Create Instance"
            actionable={false}
          />
        )}
      </ReduxForm>
      {!_mutationError ? _error : null}
      {_mutationError}
      {_loading}
      {_table}
      {_footer}
    </ViewContainer>
  );
};

export default compose(
  graphql(StopInstance, { name: 'stop' }),
  graphql(StartInstance, { name: 'start' }),
  graphql(RebootInstance, { name: 'reboot' }),
  graphql(RemoveInstance, { name: 'remove' }),
  graphql(ListInstances, {
    options: () => ({
      pollInterval: 1000
    }),
    props: ({ data: { machines, loading, error, refetch } }) => {
      const instances = forceArray(machines).map(({ state, ...machine }) => ({
        ...machine,
        state,
        allowedActions: {
          start: state !== 'RUNNING',
          stop: state === 'RUNNING',
          reboot: state === 'RUNNING',
          remove: state !== 'PROVISIONING'
        }
      }));

      return {
        instances,
        loading,
        error,
        index: Index(instances),
        refetch
      };
    }
  }),
  connect(
    ({ form, values }, { index, error, instances = [] }) => {
      // get search value
      const filter = get(form, `${MENU_FORM_NAME}.values.filter`, false);
      // check checked items ids
      const checked = get(form, `${TABLE_FORM_NAME}.values`, {});
      // check whether the main form is submitting
      const submitting = get(form, `${TABLE_FORM_NAME}.submitting`, false);
      // check whether the main form has an error
      const mutationError = get(form, `${TABLE_FORM_NAME}.error`, null);
      // get sort values
      const sortBy = get(values, 'instance-list-sort-by', 'name');
      const sortOrder = get(values, 'instance-list-sort-order', 'asc');

      // if user is searching something, get items that match that query
      const filtered = filter
        ? index.search(filter).map(({ ref }) => find(instances, ['id', ref]))
        : instances;

      // from filtered instances, sort asc
      // set's mutating flag
      const ascSorted = sort(filtered, [sortBy]).map(({ id, ...item }) => ({
        ...item,
        id,
        mutating: get(values, `${id}-mutating`, false)
      }));

      // if "select-all" is checked, all the instances are selected
      // otherwise, map through the checked ids and get the instance value
      const selected = Object.keys(checked)
        .filter(id => Boolean(checked[id]))
        .map(id => find(ascSorted, ['id', id]))
        .filter(Boolean);

      const allowedActions = {
        start: selected.every(({ state }) => state === 'STOPPED'),
        stop: selected.every(({ state }) => state === 'RUNNING'),
        reboot: selected.every(({ state }) => state === 'RUNNING'),
        remove: selected.every(({ state }) => state !== 'PROVISIONING')
      };

      // get mutating statuses
      const statuses = {
        starting: get(values, 'instance-list-starting', false),
        stopping: get(values, 'instance-list-stoping', false),
        rebooting: get(values, 'instance-list-rebooting', false),
        removing: get(values, 'instance-list-removeing', false)
      };

      return {
        // is sortOrder !== asc, reverse order
        instances: sortOrder === 'asc' ? ascSorted : ascSorted.reverse(),
        allowedActions,
        selected,
        statuses,
        submitting,
        mutationError,
        index,
        sortOrder,
        sortBy
      };
    },
    (dispatch, { refetch, ...ownProps }) => ({
      handleSortBy: ({ sortBy: currentSortBy, sortOrder }) => newSortBy => {
        // sort prop is the same, toggle
        if (currentSortBy === newSortBy) {
          return dispatch(
            set({
              name: `instance-list-sort-order`,
              value: sortOrder === 'desc' ? 'asc' : 'desc'
            })
          );
        }

        dispatch([
          set({
            name: `instance-list-sort-order`,
            value: 'desc'
          }),
          set({
            name: `instance-list-sort-by`,
            value: newSortBy
          })
        ]);
      },
      toggleSelectAll: ({ selected = [], instances = [] }) => () => {
        const same = selected.length === instances.length;
        const hasSelected = selected.length > 0;

        // none are selected, toggle to all
        if (!hasSelected) {
          return dispatch(
            instances.map(({ id }) => change(TABLE_FORM_NAME, id, true))
          );
        }

        // all are selected, toggle to none
        if (hasSelected && same) {
          return dispatch(
            instances.map(({ id }) => change(TABLE_FORM_NAME, id, false))
          );
        }

        // some are selected, toggle to all
        if (hasSelected && !same) {
          return dispatch(
            instances.map(({ id }) => change(TABLE_FORM_NAME, id, true))
          );
        }
      },
      handleAction: async ({ selected, name }) => {
        const action = ownProps[name];
        const gerund = `${name}ing`;

        // flips submitting flag to true so that we can disable everything
        const flipSubmitTrue = startSubmit(TABLE_FORM_NAME);

        // sets (starting/rebooting/etc) to true so that we can, for instance,
        // have a spinner on the correct button
        const setIngTrue = set({
          name: `instance-list-${gerund}`,
          value: true
        });

        // sets the individual item mutation flags so that we can show a
        // spinner in the row
        const setMutatingTrue = selected.map(({ id }) =>
          set({ name: `${id}-mutating`, value: true })
        );

        // wait for everything to finish and catch the error
        const [err] = await intercept(
          Promise.resolve(
            dispatch([flipSubmitTrue, setIngTrue, ...setMutatingTrue])
          ).then(() => {
            // starts all the mutations for all the selected items
            return Promise.all(
              selected.map(({ id }) => action({ variables: { id } }))
            );
          })
        );

        // reverts submitting flag to false and propagates the error if it exists
        const flipSubmitFalse = stopSubmit(TABLE_FORM_NAME, {
          _error: err && parseError(err)
        });

        // if no error, clears selected
        const clearSelected = !err && reset(TABLE_FORM_NAME);

        // reverts (starting/rebooting/etc) to false
        const setIngFalse = set({
          name: `instance-list-${gerund}`,
          value: false
        });

        // reverts the individual item mutation flags
        const setMutatingFalse = selected.map(({ id }) =>
          set({ name: `${id}-mutating`, value: false })
        );

        const actions = [
          flipSubmitFalse,
          clearSelected,
          setIngFalse,
          ...setMutatingFalse
        ].filter(Boolean);

        // refetch list - even though we poll anyway - after clearing everything
        return Promise.resolve(dispatch(actions)).then(() => refetch());
      }
    }),
    (stateProps, dispatchProps, ownProps) => {
      const { selected, instances, sortBy, sortOrder } = stateProps;
      const { toggleSelectAll, handleSortBy } = dispatchProps;

      return {
        ...ownProps,
        ...stateProps,
        selected,
        instances,
        ...dispatchProps,
        toggleSelectAll: toggleSelectAll({ selected, instances }),
        handleSortBy: handleSortBy({ sortBy, sortOrder })
      };
    }
  )
)(List);
<commit_msg>fix(my-joy-beta): keep loading when removing<commit_after>import React from 'react';
import { compose, graphql } from 'react-apollo';
import { connect } from 'react-redux';
import { stopSubmit, startSubmit, reset, change } from 'redux-form';
import { set } from 'react-redux-values';
import ReduxForm from 'declarative-redux-form';
import forceArray from 'force-array';
import get from 'lodash.get';
import intercept from 'apr-intercept';
import find from 'lodash.find';
import sort from 'lodash.sortby';
import remcalc from 'remcalc';

import {
  ViewContainer,
  Message,
  MessageDescription,
  MessageTitle,
  StatusLoader,
  Divider
} from 'joyent-ui-toolkit';

import ListInstances from '@graphql/list-instances.gql';
import StopInstance from '@graphql/stop-instance.gql';
import StartInstance from '@graphql/start-instance.gql';
import RebootInstance from '@graphql/reboot-instance.gql';
import RemoveInstance from '@graphql/remove-instance.gql';
import ToolbarForm from '@components/instances/toolbar';
import Index from '@state/gen-index';
import parseError from '@state/parse-error';

import {
  default as InstanceList,
  Item as InstanceListItem
} from '@components/instances/list';

import InstanceListActions from '@components/instances/footer';

const TABLE_FORM_NAME = 'instance-list-table';
const MENU_FORM_NAME = 'instance-list-menu';

export const List = ({
  instances = [],
  selected = [],
  allowedActions,
  statuses,
  sortBy = 'name',
  sortOrder = 'desc',
  loading = false,
  error = null,
  mutationError = null,
  submitting,
  handleAction,
  toggleSelectAll,
  handleSortBy
}) => {
  const _instances = forceArray(instances);

  const _loading =
    loading && !_instances.length
      ? [
          <Divider key="divider" height={remcalc(30)} transparent />,
          <StatusLoader key="spinner" />
        ]
      : null;

  const _error =
    error && !_instances.length && !_loading ? (
      <Message error>
        <MessageTitle>Ooops!</MessageTitle>
        <MessageDescription>
          An error occurred while loading your instances
        </MessageDescription>
      </Message>
    ) : null;

  const _mutationError = mutationError && (
    <Message error>
      <MessageTitle>Ooops!</MessageTitle>
      <MessageDescription>{mutationError}</MessageDescription>
    </Message>
  );

  const handleStart = selected => handleAction({ name: 'start', selected });
  const handleStop = selected => handleAction({ name: 'stop', selected });
  const handleReboot = selected => handleAction({ name: 'reboot', selected });
  const handleRemove = selected => handleAction({ name: 'remove', selected });

  const _table = !loading ? (
    <ReduxForm form={TABLE_FORM_NAME}>
      {props => (
        <InstanceList
          {...props}
          allSelected={instances.length && selected.length === instances.length}
          sortBy={sortBy}
          sortOrder={sortOrder}
          toggleSelectAll={toggleSelectAll}
          onSortBy={handleSortBy}
        >
          {_instances.map(({ id, ...rest }) => (
            <InstanceListItem
              key={id}
              id={id}
              {...rest}
              onStart={() => handleStart([{ id }])}
              onStop={() => handleStop([{ id }])}
              onReboot={() => handleReboot([{ id }])}
              onRemove={() => handleRemove([{ id }])}
            />
          ))}
        </InstanceList>
      )}
    </ReduxForm>
  ) : null;

  const _footer =
    !loading && selected.length ? (
      <InstanceListActions
        allowedActions={allowedActions}
        statuses={statuses}
        submitting={submitting}
        onStart={() => handleStart(selected)}
        onStop={() => handleStop(selected)}
        onReboot={() => handleReboot(selected)}
        onRemove={() => handleRemove(selected)}
      />
    ) : null;

  return (
    <ViewContainer main>
      <Divider height={remcalc(30)} transparent />
      <ReduxForm form={MENU_FORM_NAME}>
        {props => (
          <ToolbarForm
            {...props}
            searchLabel="Filter instances"
            searchPlaceholder="Search for name, state, tags, etc..."
            searchable={!_loading}
            actionLabel="Create Instance"
            actionable={false}
          />
        )}
      </ReduxForm>
      {!_mutationError ? _error : null}
      {_mutationError}
      {_loading}
      {_table}
      {_footer}
    </ViewContainer>
  );
};

export default compose(
  graphql(StopInstance, { name: 'stop' }),
  graphql(StartInstance, { name: 'start' }),
  graphql(RebootInstance, { name: 'reboot' }),
  graphql(RemoveInstance, { name: 'remove' }),
  graphql(ListInstances, {
    options: () => ({
      pollInterval: 1000
    }),
    props: ({ data: { machines, loading, error, refetch } }) => {
      const instances = forceArray(machines).map(({ state, ...machine }) => ({
        ...machine,
        state,
        allowedActions: {
          start: state !== 'RUNNING',
          stop: state === 'RUNNING',
          reboot: state === 'RUNNING',
          remove: state !== 'PROVISIONING'
        }
      }));

      return {
        instances,
        loading,
        error,
        index: Index(instances),
        refetch
      };
    }
  }),
  connect(
    ({ form, values }, { index, error, instances = [] }) => {
      // get search value
      const filter = get(form, `${MENU_FORM_NAME}.values.filter`, false);
      // check checked items ids
      const checked = get(form, `${TABLE_FORM_NAME}.values`, {});
      // check whether the main form is submitting
      const submitting = get(form, `${TABLE_FORM_NAME}.submitting`, false);
      // check whether the main form has an error
      const mutationError = get(form, `${TABLE_FORM_NAME}.error`, null);
      // get sort values
      const sortBy = get(values, 'instance-list-sort-by', 'name');
      const sortOrder = get(values, 'instance-list-sort-order', 'asc');

      // if user is searching something, get items that match that query
      const filtered = filter
        ? index.search(filter).map(({ ref }) => find(instances, ['id', ref]))
        : instances;

      // from filtered instances, sort asc
      // set's mutating flag
      const ascSorted = sort(filtered, [sortBy]).map(({ id, ...item }) => ({
        ...item,
        id,
        mutating: get(values, `${id}-mutating`, false)
      }));

      // if "select-all" is checked, all the instances are selected
      // otherwise, map through the checked ids and get the instance value
      const selected = Object.keys(checked)
        .filter(id => Boolean(checked[id]))
        .map(id => find(ascSorted, ['id', id]))
        .filter(Boolean);

      const allowedActions = {
        start: selected.every(({ state }) => state === 'STOPPED'),
        stop: selected.every(({ state }) => state === 'RUNNING'),
        reboot: selected.every(({ state }) => state === 'RUNNING'),
        remove: selected.every(({ state }) => state !== 'PROVISIONING')
      };

      // get mutating statuses
      const statuses = {
        starting: get(values, 'instance-list-starting', false),
        stopping: get(values, 'instance-list-stoping', false),
        rebooting: get(values, 'instance-list-rebooting', false),
        removing: get(values, 'instance-list-removeing', false)
      };

      return {
        // is sortOrder !== asc, reverse order
        instances: sortOrder === 'asc' ? ascSorted : ascSorted.reverse(),
        allowedActions,
        selected,
        statuses,
        submitting,
        mutationError,
        index,
        sortOrder,
        sortBy
      };
    },
    (dispatch, { refetch, ...ownProps }) => ({
      handleSortBy: ({ sortBy: currentSortBy, sortOrder }) => newSortBy => {
        // sort prop is the same, toggle
        if (currentSortBy === newSortBy) {
          return dispatch(
            set({
              name: `instance-list-sort-order`,
              value: sortOrder === 'desc' ? 'asc' : 'desc'
            })
          );
        }

        dispatch([
          set({
            name: `instance-list-sort-order`,
            value: 'desc'
          }),
          set({
            name: `instance-list-sort-by`,
            value: newSortBy
          })
        ]);
      },
      toggleSelectAll: ({ selected = [], instances = [] }) => () => {
        const same = selected.length === instances.length;
        const hasSelected = selected.length > 0;

        // none are selected, toggle to all
        if (!hasSelected) {
          return dispatch(
            instances.map(({ id }) => change(TABLE_FORM_NAME, id, true))
          );
        }

        // all are selected, toggle to none
        if (hasSelected && same) {
          return dispatch(
            instances.map(({ id }) => change(TABLE_FORM_NAME, id, false))
          );
        }

        // some are selected, toggle to all
        if (hasSelected && !same) {
          return dispatch(
            instances.map(({ id }) => change(TABLE_FORM_NAME, id, true))
          );
        }
      },
      handleAction: async ({ selected, name }) => {
        const action = ownProps[name];
        const gerund = `${name}ing`;

        // flips submitting flag to true so that we can disable everything
        const flipSubmitTrue = startSubmit(TABLE_FORM_NAME);

        // sets (starting/rebooting/etc) to true so that we can, for instance,
        // have a spinner on the correct button
        const setIngTrue = set({
          name: `instance-list-${gerund}`,
          value: true
        });

        // sets the individual item mutation flags so that we can show a
        // spinner in the row
        const setMutatingTrue = selected.map(({ id }) =>
          set({ name: `${id}-mutating`, value: true })
        );

        // wait for everything to finish and catch the error
        const [err] = await intercept(
          Promise.resolve(
            dispatch([flipSubmitTrue, setIngTrue, ...setMutatingTrue])
          ).then(() => {
            // starts all the mutations for all the selected items
            return Promise.all(
              selected.map(({ id }) => action({ variables: { id } }))
            );
          })
        );

        // reverts submitting flag to false and propagates the error if it exists
        const flipSubmitFalse = stopSubmit(TABLE_FORM_NAME, {
          _error: err && parseError(err)
        });

        // if no error, clears selected
        const clearSelected = !err && reset(TABLE_FORM_NAME);

        // reverts (starting/rebooting/etc) to false
        const setIngFalse = set({
          name: `instance-list-${gerund}`,
          value: false
        });

        // reverts the individual item mutation flags
        const setMutatingFalse = name !== 'remove' && selected.map(({ id }) =>
          set({ name: `${id}-mutating`, value: false })
        );

        const actions = [
          flipSubmitFalse,
          clearSelected,
          setIngFalse,
          ...setMutatingFalse
        ].filter(Boolean);

        // refetch list - even though we poll anyway - after clearing everything
        return Promise.resolve(dispatch(actions)).then(() => refetch());
      }
    }),
    (stateProps, dispatchProps, ownProps) => {
      const { selected, instances, sortBy, sortOrder } = stateProps;
      const { toggleSelectAll, handleSortBy } = dispatchProps;

      return {
        ...ownProps,
        ...stateProps,
        selected,
        instances,
        ...dispatchProps,
        toggleSelectAll: toggleSelectAll({ selected, instances }),
        handleSortBy: handleSortBy({ sortBy, sortOrder })
      };
    }
  )
)(List);
<|endoftext|>


<commit_before>var xpath = require("xpath");

var name="Unused variables",
	description="Look for variables that were defined but not referenced";

// This plugin does **NOT** check for variables that are used incorrectly.
// TODO: FaultRules

// basic regex for finding variables
// TODO: handle objects -- right now just verify the highest level variable.
var varFinder = /{([^}\.]+?)(\.[^}]+?)??}/g;

// preload the symbol table with framework globals
var globalSymtab = [
	"proxy",
	"request",
	"response"
];

// global bundle ... until I objectize this...
// TODO Objectize.
var glBundle;

var usageMetrics = {};

// errors that will be reported at the end of the process
var errors = [];

// warnings that will be reported at the end of the process
var warnings = [];

// Process proxyendpoints in the following order:
// 1. preflow - request [steps]
// 2. flow - request [steps]
// 3. postflow - request [steps]
// 4. routerules
//    - targetendpoint
//       . pre/flow/post
//       . pre - response
//       . flow - response
//       . post - response
// TODO: inspect things referenced by steps to populate symbol table and check for bad var references.
var onBundle = function (bundle) {
	glBundle = bundle;
	bundle.getProxyEndpoints().forEach(function(endpoint){
		var localSymtab = [];
		evaluateSteps(endpoint.getPreFlow().getFlowRequest().getSteps(), localSymtab);
		endpoint.getFlows().forEach(function(flow) {
			evaluateSteps(flow.getFlowRequest().getSteps(), localSymtab);
		});
		evaluateSteps(endpoint.getPostFlow().getFlowRequest().getSteps(), localSymtab);

		// TODO: evalute routrule conditions

		var intermediateSymtab = localSymtab.slice(0); // don't update orig array references!
		var intermediateUsage = JSON.parse(JSON.stringify(usageMetrics)); // save usage metrics
		// iterate through routerules now ...
		bundle.getTargetEndpoints().forEach(function(target){
			localSymtab = intermediateSymtab.slice(0); // reset the local symbol table
			usageMetrics = JSON.parse(JSON.stringify(intermediateUsage)); // reset usage for this iteration

			// evaluate the target's inbound request flow(s)
			evaluateSteps(target.getPreFlow().getFlowRequest().getSteps(), localSymtab)
			target.getFlows().forEach(function(flow){
				evaluateSteps(flow.getFlowRequest().getSteps(), localSymtab);
			});
			evaluateSteps(target.getPostFlow().getFlowRequest().getSteps(), localSymtab);

			// assume the target was called, evalute the response flow(s)
			evaluateSteps(target.getPreFlow().getFlowResponse().getSteps(), localSymtab)
			target.getFlows().forEach(function(flow){
				evaluateSteps(flow.getFlowResponse().getSteps(), localSymtab);
			});
			evaluateSteps(target.getPostFlow().getFlowResponse().getSteps(), localSymtab);

			// finally, evalute the response flow(s) for the endpoint with this set of
			// 	local symbols...
			evaluateSteps(endpoint.getPreFlow().getFlowResponse().getSteps(), localSymtab)
			endpoint.getFlows().forEach(function(flow){
				evaluateSteps(flow.getFlowResponse().getSteps(), localSymtab);
			});
			evaluateSteps(endpoint.getPostFlow().getFlowResponse().getSteps(), localSymtab);

			localSymtab.forEach(function(symbol){
				if( !usageMetrics[symbol]) {
					target.warn("Target flow defines but does not use symbol '" + symbol + "'");
				}
			});
		});
	});
}

// TODO: evalute where symbols are added, and record them in our symbol table.
var evaluateSteps = function(steps, localSymtab) {
	steps.forEach( function(step) {
		if( step.getName()) {
			var badVars = analyzeVariables(step.getName(), localSymtab);
			badVars.forEach(function(badvar){
				step.err("Variable {" + badvar + "} was used in step name, but not previously defined");
			});
		} else {
			step.warn("Step does not seem to call anything (empty <Name> node)");
		}
		if( step.getCondition()) {
			var badVars = analyzeVariables(step.getCondition().getExpression());
			badVars.forEach(function(badvar){
				step.err("Variable {" + badvar + "} was used in step condition, but not previously defined");
			});
		}

		// TODO: dispatch to handlers to evaluate the assignment and use of variables.
		var policy = glBundle.getPolicyByName(step.getName());
		policy && handlers[policy.getType()] && handlers[policy.getType()](policy, localSymtab);
		policy && !handlers[policy.getType()] && step.warn("No handler for policy type '" + policy.getType() + "'");
	});
}

// return a list of variables referenced in this string
// that are undefined (may be empty)
var analyzeVariables = function (value, localSymtab) {
	var symtab = globalSymtab.concat(localSymtab);
	var undefinedVars = [];
	while((match = varFinder.exec(value)) != null) {
		var variable = match[1];
		usageMetrics[variable] = (usageMetrics[variable]||0) + 1;
		if( ! (variable in symtab)) {
			undefinedVars.push(variable)
		}
	}
	return undefinedVars;
}

var _identity = function(policy, localSymtab) {};
var handlers = {
	// TODO: lots more handlers!
	ExtractVariables: function( policy, localSymtab ) {
		var payloadVariablesXpath = "/ExtractVariables/*[self::JSONPayload or self::XMLPayload]/Variable/@name";
		var payloadVariables = policy.select(payloadVariablesXpath);
		payloadVariables.forEach( function(variableDecl){
			var variableName = variableDecl.value
			console.log(variableName);
			localSymtab.push(variableName);
		});
	},
	JSONThreatProtection: _identity
}

module.exports = {
	name,
	description,
	onBundle
};<commit_msg>test if value exists before trying to get data from it<commit_after>var xpath = require("xpath");

var name="Unused variables",
	description="Look for variables that were defined but not referenced";

// This plugin does **NOT** check for variables that are used incorrectly.
// TODO: FaultRules

// basic regex for finding variables
// TODO: handle objects -- right now just verify the highest level variable.
var varFinder = /{([^}\.]+?)(\.[^}]+?)??}/g;

// preload the symbol table with framework globals
var globalSymtab = [
	"proxy",
	"request",
	"response"
];

// global bundle ... until I objectize this...
// TODO Objectize.
var glBundle;

var usageMetrics = {};

// errors that will be reported at the end of the process
var errors = [];

// warnings that will be reported at the end of the process
var warnings = [];

// Process proxyendpoints in the following order:
// 1. preflow - request [steps]
// 2. flow - request [steps]
// 3. postflow - request [steps]
// 4. routerules
//    - targetendpoint
//       . pre/flow/post
//       . pre - response
//       . flow - response
//       . post - response
// TODO: inspect things referenced by steps to populate symbol table and check for bad var references.
var onBundle = function (bundle) {
	glBundle = bundle;
	bundle.getProxyEndpoints().forEach(function(endpoint){
		var localSymtab = [];
		evaluateSteps(endpoint.getPreFlow().getFlowRequest().getSteps(), localSymtab);
		endpoint.getFlows().forEach(function(flow) {
			evaluateSteps(flow.getFlowRequest().getSteps(), localSymtab);
		});
		evaluateSteps(endpoint.getPostFlow().getFlowRequest().getSteps(), localSymtab);

		// TODO: evalute routrule conditions

		var intermediateSymtab = localSymtab.slice(0); // don't update orig array references!
		var intermediateUsage = JSON.parse(JSON.stringify(usageMetrics)); // save usage metrics
		// iterate through routerules now ...
		bundle.getTargetEndpoints().forEach(function(target){
			localSymtab = intermediateSymtab.slice(0); // reset the local symbol table
			usageMetrics = JSON.parse(JSON.stringify(intermediateUsage)); // reset usage for this iteration

			// evaluate the target's inbound request flow(s)
			evaluateSteps(target.getPreFlow().getFlowRequest().getSteps(), localSymtab)
			target.getFlows().forEach(function(flow){
				evaluateSteps(flow.getFlowRequest().getSteps(), localSymtab);
			});
			evaluateSteps(target.getPostFlow().getFlowRequest().getSteps(), localSymtab);

			// assume the target was called, evalute the response flow(s)
			evaluateSteps(target.getPreFlow().getFlowResponse().getSteps(), localSymtab)
			target.getFlows().forEach(function(flow){
				flow.getFlowResponse() && evaluateSteps(flow.getFlowResponse().getSteps(), localSymtab);
			});
			evaluateSteps(target.getPostFlow().getFlowResponse().getSteps(), localSymtab);

			// finally, evalute the response flow(s) for the endpoint with this set of
			// 	local symbols...
			evaluateSteps(endpoint.getPreFlow().getFlowResponse().getSteps(), localSymtab)
			endpoint.getFlows().forEach(function(flow){
				flow.getFlowResponse() && evaluateSteps(flow.getFlowResponse().getSteps(), localSymtab);
			});
			evaluateSteps(endpoint.getPostFlow().getFlowResponse().getSteps(), localSymtab);

			localSymtab.forEach(function(symbol){
				if( !usageMetrics[symbol]) {
					target.warn("Target flow defines but does not use symbol '" + symbol + "'");
				}
			});
		});
	});
}

// TODO: evalute where symbols are added, and record them in our symbol table.
var evaluateSteps = function(steps, localSymtab) {
	steps.forEach( function(step) {
		if( step.getName()) {
			var badVars = analyzeVariables(step.getName(), localSymtab);
			badVars.forEach(function(badvar){
				step.err("Variable {" + badvar + "} was used in step name, but not previously defined");
			});
		} else {
			step.warn("Step does not seem to call anything (empty <Name> node)");
		}
		if( step.getCondition()) {
			var badVars = analyzeVariables(step.getCondition().getExpression());
			badVars.forEach(function(badvar){
				step.err("Variable {" + badvar + "} was used in step condition, but not previously defined");
			});
		}

		// TODO: dispatch to handlers to evaluate the assignment and use of variables.
		var policy = glBundle.getPolicyByName(step.getName());
		policy && handlers[policy.getType()] && handlers[policy.getType()](policy, localSymtab);
		policy && !handlers[policy.getType()] && step.warn("No handler for policy type '" + policy.getType() + "'");
	});
}

// return a list of variables referenced in this string
// that are undefined (may be empty)
var analyzeVariables = function (value, localSymtab) {
	var symtab = globalSymtab.concat(localSymtab);
	var undefinedVars = [];
	while((match = varFinder.exec(value)) != null) {
		var variable = match[1];
		usageMetrics[variable] = (usageMetrics[variable]||0) + 1;
		if( ! (variable in symtab)) {
			undefinedVars.push(variable)
		}
	}
	return undefinedVars;
}

var _identity = function(policy, localSymtab) {};
var handlers = {
	// TODO: lots more handlers!
	ExtractVariables: function( policy, localSymtab ) {
		var payloadVariablesXpath = "/ExtractVariables/*[self::JSONPayload or self::XMLPayload]/Variable/@name";
		var payloadVariables = policy.select(payloadVariablesXpath);
		payloadVariables.forEach( function(variableDecl){
			var variableName = variableDecl.value
			console.log(variableName);
			localSymtab.push(variableName);
		});
	},
	JSONThreatProtection: _identity
}

module.exports = {
	name,
	description,
	onBundle
};<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var inherits = require('util').inherits;

var InResponse = require('./in_response');
var OutResponse = require('./out_response');
var StreamingInResponse = require('./streaming_in_response');
var StreamingOutResponse = require('./streaming_out_response');
var v2 = require('./v2');

function SelfOutResponse(conn, inreq, id, options) {
    var self = this;
    OutResponse.call(self, id, options);
    self.conn = conn;
    self.inreq = inreq;
    self.first = true;
    self.makeInres(id, options);
}
inherits(SelfOutResponse, OutResponse);

function SelfStreamingOutResponse(conn, inreq, id, options) {
    var self = this;
    OutResponse.call(self, id, options);
    self.conn = conn;
    self.inreq = inreq;
    self.first = true;
    self.makeInres(id, options);
}
inherits(SelfStreamingOutResponse, StreamingOutResponse);

SelfOutResponse.prototype.makeInres =
SelfStreamingOutResponse.prototype.makeInres =
function makeInres(id, options) {
    var self = this;
    if (options.streamed) {
        self.inres = new StreamingInResponse(self.id, options);
    } else {
        self.inres = new InResponse(self.id, options);
    }
};

SelfOutResponse.prototype._sendCallResponse =
SelfStreamingOutResponse.prototype._sendCallResponse =
SelfOutResponse.prototype._sendCallResponseCont =
SelfStreamingOutResponse.prototype._sendCallResponseCont =
function passResponse(args, isLast ) {
    var self = this;
    self.inres.handleFrame(args, isLast);
    if (self.first) {
        self.inres.code = self.code;
        self.inres.ok = self.ok;
        self.first = false;
        process.nextTick(emitResponse);
    }
    if (!self.closing) self.conn.ops.lastTimeoutTime = 0;

    function emitResponse() {
        self.inreq.responseEvent.emit(self, self.inres);
    }
};

SelfOutResponse.prototype._sendError =
SelfStreamingOutResponse.prototype._sendError =
function passError(codeString, message) {
    var self = this;
    var code = v2.ErrorResponse.Codes[codeString];
    var err = v2.ErrorResponse.CodeErrors[code]({
        originalId: self.id,
        message: message
    });
    if (!self.closing) self.conn.ops.lastTimeoutTime = 0;
    process.nextTick(emitError);

    function emitError() {
        self.inreq.outreq.emitError(err);
    }
};

module.exports.OutResponse = SelfOutResponse;
module.exports.StreamingOutResponse = SelfStreamingOutResponse;
<commit_msg>linting: [self_out_response] comply with space-in-parens rule<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var inherits = require('util').inherits;

var InResponse = require('./in_response');
var OutResponse = require('./out_response');
var StreamingInResponse = require('./streaming_in_response');
var StreamingOutResponse = require('./streaming_out_response');
var v2 = require('./v2');

function SelfOutResponse(conn, inreq, id, options) {
    var self = this;
    OutResponse.call(self, id, options);
    self.conn = conn;
    self.inreq = inreq;
    self.first = true;
    self.makeInres(id, options);
}
inherits(SelfOutResponse, OutResponse);

function SelfStreamingOutResponse(conn, inreq, id, options) {
    var self = this;
    OutResponse.call(self, id, options);
    self.conn = conn;
    self.inreq = inreq;
    self.first = true;
    self.makeInres(id, options);
}
inherits(SelfStreamingOutResponse, StreamingOutResponse);

SelfOutResponse.prototype.makeInres =
SelfStreamingOutResponse.prototype.makeInres =
function makeInres(id, options) {
    var self = this;
    if (options.streamed) {
        self.inres = new StreamingInResponse(self.id, options);
    } else {
        self.inres = new InResponse(self.id, options);
    }
};

SelfOutResponse.prototype._sendCallResponse =
SelfStreamingOutResponse.prototype._sendCallResponse =
SelfOutResponse.prototype._sendCallResponseCont =
SelfStreamingOutResponse.prototype._sendCallResponseCont =
function passResponse(args, isLast) {
    var self = this;
    self.inres.handleFrame(args, isLast);
    if (self.first) {
        self.inres.code = self.code;
        self.inres.ok = self.ok;
        self.first = false;
        process.nextTick(emitResponse);
    }
    if (!self.closing) self.conn.ops.lastTimeoutTime = 0;

    function emitResponse() {
        self.inreq.responseEvent.emit(self, self.inres);
    }
};

SelfOutResponse.prototype._sendError =
SelfStreamingOutResponse.prototype._sendError =
function passError(codeString, message) {
    var self = this;
    var code = v2.ErrorResponse.Codes[codeString];
    var err = v2.ErrorResponse.CodeErrors[code]({
        originalId: self.id,
        message: message
    });
    if (!self.closing) self.conn.ops.lastTimeoutTime = 0;
    process.nextTick(emitError);

    function emitError() {
        self.inreq.outreq.emitError(err);
    }
};

module.exports.OutResponse = SelfOutResponse;
module.exports.StreamingOutResponse = SelfStreamingOutResponse;
<|endoftext|>


<commit_before>let its = [];

let it = (description, test) => its.push([description, test]);
it.skip = () => '';

it.run  = () => {
  for(let it of its){
      let [description, test] = it;
      try {
          test();
          console.log(`Test Ok: ${description}`);
      } catch(e){
          console.log(`Failed in: ${description}, Message: ${e}`);
      }
  }
};

export {
    it,
}<commit_msg>postcss-parse-atrule-events: refactor: add only fetaure<commit_after>let its  = [];
let only = false;

let it  = (description, test) => its.push([description, test, false]);
it.only = (description, test) => its.push([description, test, true]);
it.skip = () => 1;

let testSuccLog = value => console.log(`Test Ok: ${value}`);
let testFailLog = (value, e) => console.log(`Failed in: ${value}, Message: ${e}`);

it.run = () => {

  if(only) {
      return;
  }

  let _its = its.filter(item => item[2]);
  _its.length && (its = _its);

  for(let [description, test] of its){
      try {
          test();
          testSuccLog(description);
      } catch(e){
          testFailLog(description, JSON.stringify(e));
      }
  }
};

export { it }<|endoftext|>


<commit_before>var express = require('express');
var path = require('path');
var bodyParser = require('body-parser')
var cookieParser = require('cookie-parser')
var fs = require('fs');
var cp = require('child_process');
var irc = require('irc');
var AWS = require('aws-sdk');
var app = express();

var have_aws = true;
try {
  AWS.config.loadFromPath('./aws.json');
} catch(err) {
  console.log('Starting without AWS support.');
}

app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser())

var config = require('./config.json');

var channel = config.channel;

var ircclient = new irc.Client('irc.freenode.net', 'XiphAWCY', {
    channels: [channel],
});
ircclient.addListener('error', function(message) {
    console.log('error: ', message);
});

var job;
var job_queue = [];
var job_in_progress = false;
var job_child_process = null;
var job_log = ''
var last_job_completed_time = Date.now();

var key = fs.readFileSync('secret_key', {encoding: 'utf8'}).trim();

function check_key(req,res,next) {
  if (req.cookies.key == key) {
    next();
    return;
  } else if (key == req.body.key) {
    next();
    return;
  } else {
    res.status(403).send('Key verification failed.\n');
    return;
  }
};

function process_queue() {
  cp.exec('node generate_list.js');
  if (job_in_progress) { return; };
  if (job_queue.length > 0) {
    job_in_progress = true;
    job = job_queue.shift();
    console.log('Starting job '+job.run_id);
    ircclient.say(channel,job.nick+': Starting '+job.run_id);
    var env = process.env;
    env['LANG'] = 'en_US.UTF-8';
    env['CODEC'] = job.codec;
    env['EXTRA_OPTIONS'] = job.extra_options;
    env['BUILD_OPTIONS'] = job.build_options;
    env['RUN_ID'] = job.run_id;
    if (job.qualities) {
      env['QUALITIES'] = job.qualities;
    } else {
      env['QUALITIES'] = '';
    }
    if (job.videos) {
      job_child_process = cp.spawn('./run_video_test2.sh',
        [job.commit,job.run_id].concat(job.videos),
        { env: env });
    } else {
      job_child_process = cp.spawn('./run_video_test.sh',
        [job.commit,job.run_id,job.task],
        { env: env });
    }
    job_log = ''
    job_child_process.stdout.on('data', function(data) {
      console.log(data.toString());
      job_log += data;
    });
    job_child_process.stderr.on('data', function(data) {
      console.log(data.toString());
      job_log += data;
    });
    job_child_process.on('close', function(error) {
      if (error == 0) {
        console.log('video test succeeded');
        ircclient.say(channel,job.nick+': Finished '+job.run_id);
      } else {
        ircclient.say(channel,job.nick+': Exploded '+job.run_id+
          ' see https://arewecompressedyet.com/error.txt');
      }
      fs.writeFile('runs/'+job.run_id+'/output.txt',job_log);
      fs.writeFile('error.txt',job_log);
      job_in_progress = false;
      job = null;
      last_job_completed_time = Date.now();
      process_queue();
    });
  }
};

app.use(express.static(__dirname + '/www'));
app.use('/runs',express.static(__dirname + '/runs'));
app.use('/sets.json',express.static(__dirname + '/rd_tool/sets.json'));
app.use('/error.txt',express.static(__dirname + '/error.txt'));
app.use('/list.json',express.static(__dirname + '/list.json'));
app.use('/ab_paths.json',express.static(__dirname + '/ab_paths.json'));
app.use('/time_series.json',express.static(__dirname + '/time_series.json'));
app.use('/watermark.json',express.static(__dirname + '/watermark.json'));

app.get('/run_list.json',function(req,res) {
  fs.readdir('runs',function(err,files) {
    res.send(files);
  });
});

app.get('/job_queue.json',function(req,res) {
  res.json(job_queue);
});

app.get('/job',function(req,res) {
  res.json(job);
});

app.get('/job_log',function(req,res) {
  res.send(job_log);
});

autoScalingInstances = null;
autoScalingGroups = null;

function shutdownAmazon() {
  var autoscaling = new AWS.AutoScaling();
  autoscaling.setDesiredCapacity({
    AutoScalingGroupName: config.scaling_group,
    DesiredCapacity: 0,
    HonorCooldown: true
  }, function (err, data) {
  });
}

function pollAmazon() {
  var autoscaling = new AWS.AutoScaling();
  autoscaling.describeAutoScalingInstances({},function(err,data) {
    autoScalingInstances = data;
  });
  autoscaling.describeAutoScalingGroups({AutoScalingGroupNames: [config.scaling_group]}, function(err,data) {
    autoScalingGroups = data;
  });
  if ((!job_in_progress) && (job_queue.length == 0)) {
    var shutdown_threshold = 1000*60*5; // 5 minutes
    if ((Date.now() - last_job_completed_time) > shutdown_threshold) {
      console.log("Shutting down all Amazon instances because idle.");
      shutdownAmazon();
    }
  }
}

if (have_aws) {
  setInterval(pollAmazon, 60*1*1000);
}

app.get('/describeAutoScalingGroups',function(req,res) {
  res.send(autoScalingGroups);
});

app.get('/describeAutoScalingInstances',function(req,res) {
  res.send(autoScalingInstances);
});

app.get('/bd_rate',function(req,res) {
  var a = path.basename(req.query['a']);
  var b = path.basename(req.query['b']);
  var min_bpp = req.query['min_bpp'];
  var max_bpp = req.query['max_bpp'];
  var metric_score = req.query['metric_score'];
  var file = path.basename(req.query['file']);
  var set = path.basename(req.query['set']);
  var a_file = __dirname+'/runs/'+a+'/'+set+'/'+file;
  var b_file = __dirname+'/runs/'+b+'/'+set+'/'+file;
  if (req.query['method'] == 'jm') {
    cp.execFile('./bd_rate_jm.m',[a_file,b_file],
                {},
                function(error,stdout,stderr) {
      res.send(stdout);
    });
  } else if (req.query['method'] == 'report') {
    cp.execFile('./bd_rate_report.py',[__dirname+'/runs/'+a,__dirname+'/runs/'+b,'--anchordir',__dirname+'/runs/','--suffix=-daala.out'],
                {},
                function(error,stdout,stderr) {
      if (error) {
        res.send(stderr);
      } else {
        res.send(stdout);
      }
    });
  } else if (req.query['method'] == 'report-overlap') {
    cp.execFile('./bd_rate_report.py',[__dirname+'/runs/'+a,__dirname+'/runs/'+b,'--anchordir',__dirname+'/runs/','--suffix=-daala.out','--overlap'],
                {},
                function(error,stdout,stderr) {
      if (error) {
        res.send(stderr);
      } else {
        res.send(stdout);
      }
    });
  } else if (req.query['method'] == 'metric-point') {
    cp.execFile('./rate_delta_point.py',[a_file,b_file,metric_score],
                {},
                function(error,stdout,stderr) {
      if (error) {
        res.send(stderr);
      } else {
        res.send(stdout);
      }
    });
  } else {
    cp.execFile('./bd_rate.m',[a_file,b_file],
                {env: {'BUILD_ROOT': 'daalatool/', 'MIN_BPP': min_bpp, 'MAX_BPP': max_bpp}, cwd: __dirname+'/daalatool/tools/matlab/'},
                function(error,stdout,stderr) {
      res.send(stdout);
    });
  }
});

app.use('/submit',check_key);

app.post('/submit/job',function(req,res) {
  var job = {};
  job.codec = 'daala';
  job.commit = req.body.commit;
  job.run_id = req.body.run_id.replace(' ','_');
  if (req.body.task) {
    if (req.body.task == 'custom') {
      job.videos = req.body.custom_videos;
    } else {
      job.task = req.body.task;
    }
  } else {
    job.task = 'ntt-short-1';
  }
  if (req.body.extra_options) {
    job.extra_options = req.body.extra_options;
  } else {
    job.extra_options = '';
  }
  if (req.body.build_options) {
    job.build_options = req.body.build_options;
  } else {
    job.build_options = '';
  }
  if (req.body.qualities) {
    job.qualities = req.body.qualities;
  }
  if (req.body.codec) {
    job.codec = req.body.codec;
  } else {
    job.codec = 'daala';
  }
  if (req.body.nick) {
    job.nick = req.body.nick;
  } else {
    job.nick = 'AWCY';
  }
  if (req.body.master) {
    job.master = req.body.master;
  }
  job.task_type = 'video';
  if (job.run_id.length > 256) {
    res.status(400).send('Choose a shorter run id, silly.\n');
  }
  if (fs.existsSync('runs/'+job.run_id)) {
    res.status(400).send('ID is not unique! Choose another.\n');
    return;
  }
  fs.mkdirSync('runs/'+job.run_id);
  fs.writeFile('runs/'+job.run_id+'/info.json',JSON.stringify(job));
  job_queue.push(job);
  process_queue();
  res.send('ok');
});

app.post('/submit/delete',function(req,res) {
  var run = path.basename(req.body.run_id);
  cp.execFile('nuke_branch.sh',[run],
              function(error,stdout,stderr) {
    res.send(stderr+stdout);
  });
});

app.post('/submit/cancel',function(req,res) {
  var run = req.body.run_id;
  job_queue.forEach(function(job, index) {
    if (job.run_id == run) {
      job_queue.splice(index, 1);
    }
  });
  res.send('ok');
});

app.post('/submit/kill',function(req,res) {
  job_child_process.kill('SIGTERM');
  job_child_process.kill('SIGKILL');
  res.send(job_child_process.pid);
});

app.post('/submit/restart', function(req,res) {
  process.exit();
  res.send('ok');
});

app.post('/submit/setDesiredCapacity',function(req,res) {
  var autoscaling = new AWS.AutoScaling();
  autoscaling.setDesiredCapacity({
    AutoScalingGroupName: config.scaling_group,
    DesiredCapacity: req.body.DesiredCapacity,
    HonorCooldown: false
  }, function (err, data) {
    res.send(data);
  });
});

app.listen(3000);
<commit_msg>Send both stderr and stdout for bdrate report<commit_after>var express = require('express');
var path = require('path');
var bodyParser = require('body-parser')
var cookieParser = require('cookie-parser')
var fs = require('fs');
var cp = require('child_process');
var irc = require('irc');
var AWS = require('aws-sdk');
var app = express();

var have_aws = true;
try {
  AWS.config.loadFromPath('./aws.json');
} catch(err) {
  console.log('Starting without AWS support.');
}

app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser())

var config = require('./config.json');

var channel = config.channel;

var ircclient = new irc.Client('irc.freenode.net', 'XiphAWCY', {
    channels: [channel],
});
ircclient.addListener('error', function(message) {
    console.log('error: ', message);
});

var job;
var job_queue = [];
var job_in_progress = false;
var job_child_process = null;
var job_log = ''
var last_job_completed_time = Date.now();

var key = fs.readFileSync('secret_key', {encoding: 'utf8'}).trim();

function check_key(req,res,next) {
  if (req.cookies.key == key) {
    next();
    return;
  } else if (key == req.body.key) {
    next();
    return;
  } else {
    res.status(403).send('Key verification failed.\n');
    return;
  }
};

function process_queue() {
  cp.exec('node generate_list.js');
  if (job_in_progress) { return; };
  if (job_queue.length > 0) {
    job_in_progress = true;
    job = job_queue.shift();
    console.log('Starting job '+job.run_id);
    ircclient.say(channel,job.nick+': Starting '+job.run_id);
    var env = process.env;
    env['LANG'] = 'en_US.UTF-8';
    env['CODEC'] = job.codec;
    env['EXTRA_OPTIONS'] = job.extra_options;
    env['BUILD_OPTIONS'] = job.build_options;
    env['RUN_ID'] = job.run_id;
    if (job.qualities) {
      env['QUALITIES'] = job.qualities;
    } else {
      env['QUALITIES'] = '';
    }
    if (job.videos) {
      job_child_process = cp.spawn('./run_video_test2.sh',
        [job.commit,job.run_id].concat(job.videos),
        { env: env });
    } else {
      job_child_process = cp.spawn('./run_video_test.sh',
        [job.commit,job.run_id,job.task],
        { env: env });
    }
    job_log = ''
    job_child_process.stdout.on('data', function(data) {
      console.log(data.toString());
      job_log += data;
    });
    job_child_process.stderr.on('data', function(data) {
      console.log(data.toString());
      job_log += data;
    });
    job_child_process.on('close', function(error) {
      if (error == 0) {
        console.log('video test succeeded');
        ircclient.say(channel,job.nick+': Finished '+job.run_id);
      } else {
        ircclient.say(channel,job.nick+': Exploded '+job.run_id+
          ' see https://arewecompressedyet.com/error.txt');
      }
      fs.writeFile('runs/'+job.run_id+'/output.txt',job_log);
      fs.writeFile('error.txt',job_log);
      job_in_progress = false;
      job = null;
      last_job_completed_time = Date.now();
      process_queue();
    });
  }
};

app.use(express.static(__dirname + '/www'));
app.use('/runs',express.static(__dirname + '/runs'));
app.use('/sets.json',express.static(__dirname + '/rd_tool/sets.json'));
app.use('/error.txt',express.static(__dirname + '/error.txt'));
app.use('/list.json',express.static(__dirname + '/list.json'));
app.use('/ab_paths.json',express.static(__dirname + '/ab_paths.json'));
app.use('/time_series.json',express.static(__dirname + '/time_series.json'));
app.use('/watermark.json',express.static(__dirname + '/watermark.json'));

app.get('/run_list.json',function(req,res) {
  fs.readdir('runs',function(err,files) {
    res.send(files);
  });
});

app.get('/job_queue.json',function(req,res) {
  res.json(job_queue);
});

app.get('/job',function(req,res) {
  res.json(job);
});

app.get('/job_log',function(req,res) {
  res.send(job_log);
});

autoScalingInstances = null;
autoScalingGroups = null;

function shutdownAmazon() {
  var autoscaling = new AWS.AutoScaling();
  autoscaling.setDesiredCapacity({
    AutoScalingGroupName: config.scaling_group,
    DesiredCapacity: 0,
    HonorCooldown: true
  }, function (err, data) {
  });
}

function pollAmazon() {
  var autoscaling = new AWS.AutoScaling();
  autoscaling.describeAutoScalingInstances({},function(err,data) {
    autoScalingInstances = data;
  });
  autoscaling.describeAutoScalingGroups({AutoScalingGroupNames: [config.scaling_group]}, function(err,data) {
    autoScalingGroups = data;
  });
  if ((!job_in_progress) && (job_queue.length == 0)) {
    var shutdown_threshold = 1000*60*5; // 5 minutes
    if ((Date.now() - last_job_completed_time) > shutdown_threshold) {
      console.log("Shutting down all Amazon instances because idle.");
      shutdownAmazon();
    }
  }
}

if (have_aws) {
  setInterval(pollAmazon, 60*1*1000);
}

app.get('/describeAutoScalingGroups',function(req,res) {
  res.send(autoScalingGroups);
});

app.get('/describeAutoScalingInstances',function(req,res) {
  res.send(autoScalingInstances);
});

app.get('/bd_rate',function(req,res) {
  var a = path.basename(req.query['a']);
  var b = path.basename(req.query['b']);
  var min_bpp = req.query['min_bpp'];
  var max_bpp = req.query['max_bpp'];
  var metric_score = req.query['metric_score'];
  var file = path.basename(req.query['file']);
  var set = path.basename(req.query['set']);
  var a_file = __dirname+'/runs/'+a+'/'+set+'/'+file;
  var b_file = __dirname+'/runs/'+b+'/'+set+'/'+file;
  if (req.query['method'] == 'jm') {
    cp.execFile('./bd_rate_jm.m',[a_file,b_file],
                {},
                function(error,stdout,stderr) {
      res.send(stdout);
    });
  } else if (req.query['method'] == 'report') {
    cp.execFile('./bd_rate_report.py',[__dirname+'/runs/'+a,__dirname+'/runs/'+b,'--anchordir',__dirname+'/runs/','--suffix=-daala.out'],
                {},
                function(error,stdout,stderr) {
      if (error) {
        res.send(stderr + stdout);
      } else {
        res.send(stdout);
      }
    });
  } else if (req.query['method'] == 'report-overlap') {
    cp.execFile('./bd_rate_report.py',[__dirname+'/runs/'+a,__dirname+'/runs/'+b,'--anchordir',__dirname+'/runs/','--suffix=-daala.out','--overlap'],
                {},
                function(error,stdout,stderr) {
      if (error) {
        res.send(stderr + stdout);
      } else {
        res.send(stdout);
      }
    });
  } else if (req.query['method'] == 'metric-point') {
    cp.execFile('./rate_delta_point.py',[a_file,b_file,metric_score],
                {},
                function(error,stdout,stderr) {
      if (error) {
        res.send(stderr);
      } else {
        res.send(stdout);
      }
    });
  } else {
    cp.execFile('./bd_rate.m',[a_file,b_file],
                {env: {'BUILD_ROOT': 'daalatool/', 'MIN_BPP': min_bpp, 'MAX_BPP': max_bpp}, cwd: __dirname+'/daalatool/tools/matlab/'},
                function(error,stdout,stderr) {
      res.send(stdout);
    });
  }
});

app.use('/submit',check_key);

app.post('/submit/job',function(req,res) {
  var job = {};
  job.codec = 'daala';
  job.commit = req.body.commit;
  job.run_id = req.body.run_id.replace(' ','_');
  if (req.body.task) {
    if (req.body.task == 'custom') {
      job.videos = req.body.custom_videos;
    } else {
      job.task = req.body.task;
    }
  } else {
    job.task = 'ntt-short-1';
  }
  if (req.body.extra_options) {
    job.extra_options = req.body.extra_options;
  } else {
    job.extra_options = '';
  }
  if (req.body.build_options) {
    job.build_options = req.body.build_options;
  } else {
    job.build_options = '';
  }
  if (req.body.qualities) {
    job.qualities = req.body.qualities;
  }
  if (req.body.codec) {
    job.codec = req.body.codec;
  } else {
    job.codec = 'daala';
  }
  if (req.body.nick) {
    job.nick = req.body.nick;
  } else {
    job.nick = 'AWCY';
  }
  if (req.body.master) {
    job.master = req.body.master;
  }
  job.task_type = 'video';
  if (job.run_id.length > 256) {
    res.status(400).send('Choose a shorter run id, silly.\n');
  }
  if (fs.existsSync('runs/'+job.run_id)) {
    res.status(400).send('ID is not unique! Choose another.\n');
    return;
  }
  fs.mkdirSync('runs/'+job.run_id);
  fs.writeFile('runs/'+job.run_id+'/info.json',JSON.stringify(job));
  job_queue.push(job);
  process_queue();
  res.send('ok');
});

app.post('/submit/delete',function(req,res) {
  var run = path.basename(req.body.run_id);
  cp.execFile('nuke_branch.sh',[run],
              function(error,stdout,stderr) {
    res.send(stderr+stdout);
  });
});

app.post('/submit/cancel',function(req,res) {
  var run = req.body.run_id;
  job_queue.forEach(function(job, index) {
    if (job.run_id == run) {
      job_queue.splice(index, 1);
    }
  });
  res.send('ok');
});

app.post('/submit/kill',function(req,res) {
  job_child_process.kill('SIGTERM');
  job_child_process.kill('SIGKILL');
  res.send(job_child_process.pid);
});

app.post('/submit/restart', function(req,res) {
  process.exit();
  res.send('ok');
});

app.post('/submit/setDesiredCapacity',function(req,res) {
  var autoscaling = new AWS.AutoScaling();
  autoscaling.setDesiredCapacity({
    AutoScalingGroupName: config.scaling_group,
    DesiredCapacity: req.body.DesiredCapacity,
    HonorCooldown: false
  }, function (err, data) {
    res.send(data);
  });
});

app.listen(3000);
<|endoftext|>


<commit_before>// Development module that is only loaded on dev and staging
// Dependencies: moj, _, jQuery

(function () {
  'use strict';

  moj.Modules.Development = {
    el: 'body',
    template: CLA.templates.Development.fillLinks,

    init: function () {
      _.bindAll(this, 'render', 'fillForm');
      this.cacheEls();
      this.bindEvents();
    },

    cacheEls: function () {
      this.$el = $(this.el);
      this.$form = ('#content form', this.$el);
      this.step = $('#id_checker_wizard-current_step').val();
    },

    bindEvents: function () {
      moj.Events.on('render', this.render);
      this.$el.on('click', '.js-FillForm', this.fillForm);
    },

    render: function () {
      $('.indicator').after(this.template({step: this.step}));
    },

    fillForm: function (e) {
      e.preventDefault();

      var $el = $(e.target),
          eligible = $el.data('eligible');

      switch(this.step) {
        case 'your_problem':
          this.fillProblem(eligible);
          break;
        case 'your_details':
          this.fillDetails(eligible);
          break;
        case 'your_capital':
          this.fillCapital();
          break;
        case 'your_income':
          this.fillIncome(eligible);
          break;
        case 'your_allowances':
          this.fillAllowances();
          break;
        default:
          this.fillBasic();
      }

      this.$form.find('[type=submit]').focus();
    },

    fillBasic: function () {
      var $fields = $('form').find('input:not([type=submit], [type=hidden]), textarea, select');

      $fields.each(this.completeField);
    },

    completeField: function (i, el) {
      var $this = $(el),
          $label = $('label[for=' + $this.attr('id') + ']'),
          type = $this.prop('type'),
          val;

      if (type === 'text' || type === 'textarea') {
        val = $.trim($label.text().replace(/cannot be blank/g,''));
        $this.val(val);
      } else if (type === 'select-one') {
        $this.find('option:first').prop('selected', true);
      }
    },

    fillProblem: function (eligible) {
      if (eligible) {
        $('#id_your_problem-category_2').click();
      } else {
        $('#id_your_problem-category_0').click();
      }
    },

    fillDetails: function (eligible) {
      if (eligible) {
        $('input[value=1][type=radio]').click();
      } else {
        $('input[value=0][type=radio]').click();
      }
    },

    fillCapital: function () {
      $('input[type=number]').val(0);
      $('input[value=1][name=property-0-owner]').click();
      $('input[value=0][name=property-0-disputed]').click();
    },

    fillIncome: function (eligible) {
      $('input[type=number]').val(0);
      $('input[value=1][type=radio]').click();

      if (eligible) {
        $('#id_your_income-earnings_0').val(732.99+(285.13*3));
        $('#id_dependants-dependants_old').val(2);
        $('#id_dependants-dependants_young').val(1);
      } else {
        $('#id_your_income-earnings_0').val(910.51);
      }
    },

    fillAllowances: function () {
      $('input[type=number]').val(0);
    }
  };

})();<commit_msg>Update debug helper with benefits fill<commit_after>// Development module that is only loaded on dev and staging
// Dependencies: moj, _, jQuery

(function () {
  'use strict';

  moj.Modules.Development = {
    el: 'body',
    template: CLA.templates.Development.fillLinks,

    init: function () {
      _.bindAll(this, 'render', 'fillForm');
      this.cacheEls();
      this.bindEvents();
    },

    cacheEls: function () {
      this.$el = $(this.el);
      this.$form = ('#content form', this.$el);
      this.step = $('#id_checker_wizard-current_step').val();
    },

    bindEvents: function () {
      moj.Events.on('render', this.render);
      this.$el.on('click', '.js-FillForm', this.fillForm);
    },

    render: function () {
      $('.indicator').after(this.template({step: this.step}));
    },

    fillForm: function (e) {
      e.preventDefault();

      var $el = $(e.target),
          eligible = $el.data('eligible');

      switch(this.step) {
        case 'your_problem':
          this.fillProblem(eligible);
          break;
        case 'your_details':
          this.fillDetails(eligible);
          break;
        case 'your_benefits':
          this.fillBenefits(eligible);
          break;
        case 'your_capital':
          this.fillCapital();
          break;
        case 'your_income':
          this.fillIncome(eligible);
          break;
        case 'your_allowances':
          this.fillAllowances();
          break;
        default:
          this.fillBasic();
      }

      this.$form.find('[type=submit]').focus();
    },

    fillBasic: function () {
      var $fields = $('form').find('input:not([type=submit], [type=hidden]), textarea, select');

      $fields.each(this.completeField);
    },

    completeField: function (i, el) {
      var $this = $(el),
          $label = $('label[for=' + $this.attr('id') + ']'),
          type = $this.prop('type'),
          val;

      if (type === 'text' || type === 'textarea') {
        val = $.trim($label.text().replace(/cannot be blank/g,''));
        $this.val(val);
      } else if (type === 'select-one') {
        $this.find('option:first').prop('selected', true);
      }
    },

    fillProblem: function (eligible) {
      if (eligible) {
        $('#id_your_problem-category_2').click();
      } else {
        $('#id_your_problem-category_0').click();
      }
    },

    fillDetails: function (eligible) {
      if (eligible) {
        $('input[value=1][type=radio]').click();
      } else {
        $('input[value=0][type=radio]').click();
      }
    },

    fillBenefits: function (eligible) {
      $('input[name=your_benefits-income_support]').prop('checked', true);
    },

    fillCapital: function () {
      $('input[type=number]').val(0);
      $('input[value=1][name=property-0-owner]').click();
      $('input[value=0][name=property-0-disputed]').click();
    },

    fillIncome: function (eligible) {
      $('input[type=number]').val(0);
      $('input[value=1][type=radio]').click();

      if (eligible) {
        $('#id_your_income-earnings_0').val(732.99+(285.13*3));
        $('#id_dependants-dependants_old').val(2);
        $('#id_dependants-dependants_young').val(1);
      } else {
        $('#id_your_income-earnings_0').val(910.51);
      }
    },

    fillAllowances: function () {
      $('input[type=number]').val(0);
    }
  };

})();<|endoftext|>


<commit_before>/*
 * Author: CM
 */

(function(global) {

  /**
   * @callback PromiseThrottled
   * @param {...Object|String|Number} any number of optional params
   * @return {Promise}
   */

  /**
   * @param {PromiseThrottled} fn
   * @param {Object|null} [options]
   * @param {Boolean} options.cancel Whether to cancel the previous promise if it is still running.
   * @returns {PromiseThrottled}
   */
  function throttleFunction(fn, options) {
    options = _.defaults(options || {}, {cancel: false});
    var promise;
    var laterPromiseToCancel;

    return function() {
      console.log('promise is ', promise);
      if (promise && promise.isPending()) {
        if (options.cancel && promise.isCancellable()) {
          console.log('promise cancelled');
          promise.cancel();
          promise = null;
        }
      }

      if (!promise || !promise.isPending()) {
        promise = fn.apply(null, arguments);
        console.log('promise created ', promise);
        if (!promise instanceof Promise) {
          console.log('promise resolved');
          promise = Promise.resolve();
        }
      } else if (!options.cancel) {
        if (!laterPromiseToCancel) {
          console.log('create redundant promise');
          laterPromiseToCancel = promise.finally(function() {
            console.log('cancel redundant promise');
            //redundantPromise.cancel();
            laterPromiseToCancel = null;
            promise = null;
            throw new Promise.CancellationError();
          });
        }
        console.log('return redundant promise');
        return laterPromiseToCancel;
      }
      console.log('return promise');
      return promise;
    };
  }

  var throttlersStorage = {};

  /**
   * @param {String} namespace
   * @param {PromiseThrottled} fn
   * @param {Object|null} options
   * @param {Boolean} options.cancel Whether to cancel the previous promise if it is still running
   * @returns {Promise}
   */
  function throttle(namespace, fn, options) {
    if (!throttlersStorage[namespace]) {
      throttlersStorage[namespace] = throttleFunction(fn, options);

    }
    return throttlersStorage[namespace]();
  }

  global.throttleFunction = throttleFunction;
  global.throttle = throttle;

  // temporary backward compatibility
  global.promiseThrottler = throttleFunction;

  /**
   * TODO to discuss.
   * It still has the problems.
   * If you make `test` cancellable then the console window in web inspector will tremble for real like it is under the fever.
   * If you make the difference between second .then timeout 500 and the Promise timeout 1500 then there is a chance that both .then will be executed cause
   * cancellation of the second .then will happen later than .then itself.
   */
  var test = throttleFunction(function() {
    return new Promise(function(resolve, reject) {
      setTimeout(function() {
        resolve(5);
      }, 1500);
    }).cancellable();
  }/*, {cancel: true}*/);

  test().then(function(result) {
    console.log('first test is finished ' + result);
  });

  setTimeout(function() {
    test().then(function(result) {
      console.log('second test is finished ' + result);
    });
  }, 500);

  test().then(function(result) {
    console.log('third test is finished ' + result);
  });

})(window);
<commit_msg>Revert "Add an option to ignore later calls in promiseThrottler."<commit_after>/*
 * Author: CM
 */

(function(global) {

  /**
   * @callback PromiseThrottled
   * @param {...Object|String|Number} any number of optional params
   * @return {Promise}
   */

  /**
   * @param {PromiseThrottled} fn
   * @param {Object|null} options
   * @param {Boolean} options.cancel Whether to cancel the previous promise if it is still running.
   * @returns {PromiseThrottled}
   */
  function throttleFunction(fn, options) {
    options = _.defaults(options || {}, {cancel: false});
    var promise;

    return function() {
      if (promise && promise.isPending()) {
        if (options.cancel && promise.isCancellable()) {
          promise.cancel();
          promise = null;
        }
      }

      if (!promise || !promise.isPending()) {
        var result = fn.apply(null, arguments);
        if (!result instanceof Promise) {
          result = Promise.resolve(result);
        }
      }
      result.then(function() {
        promise = null;
      });
      return result;
    };
  }

  var throttlersStorage = {};

  /**
   * @param {String} namespace
   * @param {PromiseThrottled} fn
   * @param {Object|null} options
   * @param {Boolean} options.cancel Whether to cancel the previous promise if it is still running
   * @returns {Promise}
   */
  function throttle(namespace, fn, options) {
    if (!throttlersStorage[namespace]) {
      throttlersStorage[namespace] = throttleFunction(fn, options);

    }
    return throttlersStorage[namespace]();
  }

  global.throttleFunction = throttleFunction;
  global.throttle = throttle;

  // temporary backward compatibility
  global.promiseThrottler = throttleFunction;

})(window);
<|endoftext|>


<commit_before>(function () {
  'use strict';

  /**
   * Service for querying MapBox geocoder
   */
  angular
    .module('core')
    .factory('LocationService', LocationService);

  /* @ngInject */
  function LocationService($log, $http, SettingsFactory) {

    var appSettings = SettingsFactory.get();

    // Defaults location to be used with maps (Europe)
    var defaultLocation = {
      lat: 48.6908333333,
      lng: 9.14055555556,
      zoom: 6
    };

    var service = {
      getDefaultLocation: getDefaultLocation,
      getBounds: getBounds,
      getCenter: getCenter,
      shortTitle: shortTitle,
      suggestions: suggestions
    };

    /**
     * Default map center
     * Return Angular-UI-Leaflet compatible map center with optionally pre-set zoom level
     *
     * Leaflet expects center to be:
     * {
     *   lat: Float,
     *   lng: Float,
     *   center: Int
     * }
     */
    function getDefaultLocation(zoom) {
      return {
        lat: defaultLocation.lat,
        lng: defaultLocation.lng,
        zoom: parseInt(zoom || defaultLocation.zoom, 10)
      };
    }

    /**
     * Return Angular-UI-Leaflet compatible bounding box object from Carmen Geojson object
     * @link https://github.com/mapbox/carmen/blob/master/carmen-geojson.md
     *
     * Leaflet expects bounds object to be:
     * {
     *   'northEast': {
     *     'lat':59.60109549032134,
     *     'lng':42.099609375
     *   },
     *   'southWest':{
     *     'lat':52.796119005678506,
     *     'lng':25.24658203125
     *   }
     * }
     */
    function getBounds(geolocation) {
      if (!geolocation || !geolocation.bbox || !angular.isArray(geolocation.bbox) || geolocation.bbox.length !== 4) {
        return false;
      }
      return {
        'northEast': {
          'lat': parseFloat(geolocation.bbox[3]),
          'lng': parseFloat(geolocation.bbox[2])
        },
        'southWest': {
          'lat': parseFloat(geolocation.bbox[1]),
          'lng': parseFloat(geolocation.bbox[0])
        }
      };
    }

    /**
     * Return Angular-UI-Leaflet compatible center object from Carmen Geojson object
     * @link https://github.com/mapbox/carmen/blob/master/carmen-geojson.md
     *
     * Leaflet expects center to be:
     * {
     *   lat: Float,
     *   lng: Float,
     *   center: Int
     * }
     */
    function getCenter(geolocation) {
      var coords;

      if (geolocation.center) {
        coords = geolocation.center;
      } else if (geolocation.geometry && geolocation.geometry.coordinates) {
        coords = geolocation.geometry.coordinates;
      }

      // Nothing found, return old or false
      if (!coords || !angular.isArray(coords) || coords.length !== 2) {
        return false;
      }

      // Return coordinates
      return {
        lng: parseFloat(coords[0]),
        lat: parseFloat(coords[1])
      };
    }

    /**
     * Search field's typeahead -suggestions
     *
     * @link https://www.mapbox.com/api-documentation/#geocoding
     *
     * @param val String Search query
     * @param types String (optional) Filter results by one or more type.
     *                     Options are  country,  region,  postcode,  place,  locality,  neighborhood,  address,  poi.
     *                     Multiple options can be comma-separated.
     *                     Defaults to `country,region,place,locality,neighborhood`
     */
    function suggestions(val, types) {
      if (!appSettings.mapbox || !appSettings.mapbox.publicKey) {
        $log.warn('No Mapbox settings found; cannot do geocoding!');
        return [];
      }

      return $http.get(
        'https://api.mapbox.com/geocoding/v5/mapbox.places/' + encodeURIComponent(val) + '.json'
        + '?access_token=' + appSettings.mapbox.publicKey
        + '&language=en'
        + '&types=' + (types || 'country,region,place,locality,neighborhood'),
        {
          // Tells Angular-Loading-Bar to ignore this http request
          // @link https://github.com/chieffancypants/angular-loading-bar#ignoring-particular-xhr-requests
          ignoreLoadingBar: true
        })
        .then(function (response) {
          if (response.status === 200 && response.data.features && response.data.features.length > 0) {
            return response.data.features.map(function (geolocation) {
              geolocation.trTitle = shortTitle(geolocation);
              return geolocation;
            });
          } else {
            return [];
          }
        });
    }

    /**
     * Compile a nice title from geolocation, eg. "Jyväskylä, Finland"
     * @link https://www.mapbox.com/api-documentation/#geocoding
     * @link https://github.com/mapbox/carmen/blob/master/carmen-geojson.md
     *
     * @param geolocation Object Carmen GeoJSON
     * @return String
     */
    function shortTitle(geolocation) {
      var title = '';

      if (geolocation.text) {
        title = geolocation.text;

        // Relevant context strings
        if (geolocation.context) {
          var contextLength = geolocation.context.length;
          for (var i = 0; i < contextLength; i++) {
            if (geolocation.context[i].id.substring(0, 6) === 'place.') {
              title += ', ' + geolocation.context[i].text;
            } else if (geolocation.context[i].id.substring(0, 8) === 'country.') {
              title += ', ' + geolocation.context[i].text;
            }
          }
        }

      } else if (geolocation.place_name) {
        title = geolocation.place_name;
      }

      return title;
    }

    return service;
  }

}());
<commit_msg>Validate the length of location value before mapbox api call (#824)<commit_after>(function () {
  'use strict';

  /**
   * Service for querying MapBox geocoder
   */
  angular
    .module('core')
    .factory('LocationService', LocationService);

  /* @ngInject */
  function LocationService($log, $http, SettingsFactory) {

    var appSettings = SettingsFactory.get();

    // Defaults location to be used with maps (Europe)
    var defaultLocation = {
      lat: 48.6908333333,
      lng: 9.14055555556,
      zoom: 6
    };

    var service = {
      getDefaultLocation: getDefaultLocation,
      getBounds: getBounds,
      getCenter: getCenter,
      shortTitle: shortTitle,
      suggestions: suggestions
    };

    /**
     * Default map center
     * Return Angular-UI-Leaflet compatible map center with optionally pre-set zoom level
     *
     * Leaflet expects center to be:
     * {
     *   lat: Float,
     *   lng: Float,
     *   center: Int
     * }
     */
    function getDefaultLocation(zoom) {
      return {
        lat: defaultLocation.lat,
        lng: defaultLocation.lng,
        zoom: parseInt(zoom || defaultLocation.zoom, 10)
      };
    }

    /**
     * Return Angular-UI-Leaflet compatible bounding box object from Carmen Geojson object
     * @link https://github.com/mapbox/carmen/blob/master/carmen-geojson.md
     *
     * Leaflet expects bounds object to be:
     * {
     *   'northEast': {
     *     'lat':59.60109549032134,
     *     'lng':42.099609375
     *   },
     *   'southWest':{
     *     'lat':52.796119005678506,
     *     'lng':25.24658203125
     *   }
     * }
     */
    function getBounds(geolocation) {
      if (!geolocation || !geolocation.bbox || !angular.isArray(geolocation.bbox) || geolocation.bbox.length !== 4) {
        return false;
      }
      return {
        'northEast': {
          'lat': parseFloat(geolocation.bbox[3]),
          'lng': parseFloat(geolocation.bbox[2])
        },
        'southWest': {
          'lat': parseFloat(geolocation.bbox[1]),
          'lng': parseFloat(geolocation.bbox[0])
        }
      };
    }

    /**
     * Return Angular-UI-Leaflet compatible center object from Carmen Geojson object
     * @link https://github.com/mapbox/carmen/blob/master/carmen-geojson.md
     *
     * Leaflet expects center to be:
     * {
     *   lat: Float,
     *   lng: Float,
     *   center: Int
     * }
     */
    function getCenter(geolocation) {
      var coords;

      if (geolocation.center) {
        coords = geolocation.center;
      } else if (geolocation.geometry && geolocation.geometry.coordinates) {
        coords = geolocation.geometry.coordinates;
      }

      // Nothing found, return old or false
      if (!coords || !angular.isArray(coords) || coords.length !== 2) {
        return false;
      }

      // Return coordinates
      return {
        lng: parseFloat(coords[0]),
        lat: parseFloat(coords[1])
      };
    }

    /**
     * Search field's typeahead -suggestions
     *
     * @link https://www.mapbox.com/api-documentation/#geocoding
     *
     * @param val String Search query
     * @param types String (optional) Filter results by one or more type.
     *                     Options are  country,  region,  postcode,  place,  locality,  neighborhood,  address,  poi.
     *                     Multiple options can be comma-separated.
     *                     Defaults to `country,region,place,locality,neighborhood`
     */
    function suggestions(val, types) {
      if (!appSettings.mapbox || !appSettings.mapbox.publicKey) {
        $log.warn('No Mapbox settings found; cannot do geocoding!');
        return Promise.resolve([]);
      }

      if (val == null || val.length <= 1) {
        return Promise.resolve([]);
      }

      return $http.get(
        'https://api.mapbox.com/geocoding/v5/mapbox.places/' + encodeURIComponent(val) + '.json'
        + '?access_token=' + appSettings.mapbox.publicKey
        + '&language=en'
        + '&types=' + (types || 'country,region,place,locality,neighborhood'),
        {
          // Tells Angular-Loading-Bar to ignore this http request
          // @link https://github.com/chieffancypants/angular-loading-bar#ignoring-particular-xhr-requests
          ignoreLoadingBar: true
        })
        .then(function (response) {
          if (response.status === 200 && response.data.features && response.data.features.length > 0) {
            return response.data.features.map(function (geolocation) {
              geolocation.trTitle = shortTitle(geolocation);
              return geolocation;
            });
          } else {
            return Promise.resolve([]);
          }
        });
    }

    /**
     * Compile a nice title from geolocation, eg. "Jyväskylä, Finland"
     * @link https://www.mapbox.com/api-documentation/#geocoding
     * @link https://github.com/mapbox/carmen/blob/master/carmen-geojson.md
     *
     * @param geolocation Object Carmen GeoJSON
     * @return String
     */
    function shortTitle(geolocation) {
      var title = '';

      if (geolocation.text) {
        title = geolocation.text;

        // Relevant context strings
        if (geolocation.context) {
          var contextLength = geolocation.context.length;
          for (var i = 0; i < contextLength; i++) {
            if (geolocation.context[i].id.substring(0, 6) === 'place.') {
              title += ', ' + geolocation.context[i].text;
            } else if (geolocation.context[i].id.substring(0, 8) === 'country.') {
              title += ', ' + geolocation.context[i].text;
            }
          }
        }

      } else if (geolocation.place_name) {
        title = geolocation.place_name;
      }

      return title;
    }

    return service;
  }

}());
<|endoftext|>