<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// @flow
import SymbolStoreDB from './symbol-store-db';
import { SymbolsNotFoundError } from './errors';
import bisection from 'bisection';

const demangleModulePromise = import('gecko-profiler-demangle');

import type { RequestedLib } from '../types/actions';
import type { SymbolTableAsTuple } from './symbol-store-db';

export type LibSymbolicationRequest = {
  lib: RequestedLib,
  addresses: Set<number>,
};

export type AddressResult = {|
  // The name of the function that this address belongs to.
  name: string,
  // The offset (in bytes) between the start of the function and the address.
  functionOffset: number,
|};

interface SymbolProvider {
  // Cheap, should be called first.
  requestSymbolsFromServer(
    requests: LibSymbolicationRequest[]
  ): Promise<Map<number, AddressResult>>[];

  // Expensive, should be called if requestSymbolsFromServer was unsuccessful.
  requestSymbolTableFromAddon(lib: RequestedLib): Promise<SymbolTableAsTuple>;
}

export interface AbstractSymbolStore {
  getSymbols(
    requests: LibSymbolicationRequest[],
    successCb: (LibSymbolicationRequest, Map<number, AddressResult>) => void,
    errorCb: (LibSymbolicationRequest, Error) => void
  ): Promise<void>;
}

// Partition the array into "chunks".
// Every element in the array is assigned a numeric value using the computeValue
// callback function. The chunks are chosen in such a way that the accumulated
// value in each chunk does not exceed maxValue, if possible.
// In other words, for each chunk, the following will hold:
// sum(chunk.map(computeValue)) <= maxValue or chunk.length == 1.
// The array is allowed to contain elements which are larger than the maximum
// value on their own; such elements will get a single chunk for themselves.
function _partitionIntoChunksOfMaxValue<T>(
  array: T[],
  maxValue: number,
  computeValue: T => number
): T[][] {
  const chunks = [];
  for (const element of array) {
    const elementValue = computeValue(element);
    // Find an existing chunk that still has enough "value space" left to
    // accomodate this element.
    let chunk = chunks.find(({ value }) => value + elementValue <= maxValue);
    if (chunk === undefined) {
      // If no chunk was found, create a new chunk.
      chunk = { value: 0, elements: [] };
      chunks.push(chunk);
    }
    chunk.elements.push(element);
    chunk.value += elementValue;
  }
  return chunks.map(({ elements }) => elements);
}

/**
 * The SymbolStore implements efficient lookup of symbols for a set of addresses.
 * It consults multiple sources of symbol information and caches some results.
 * It only implements one public method: getSymbols.
 * @class SymbolStore
 */
export class SymbolStore {
  _symbolProvider: SymbolProvider;
  _db: SymbolStoreDB;

  constructor(dbNamePrefix: string, symbolProvider: SymbolProvider) {
    this._symbolProvider = symbolProvider;
    this._db = new SymbolStoreDB(`${dbNamePrefix}-symbol-tables`);
  }

  async closeDb() {
    await this._db.close();
  }

  // Store a symbol table in the database. This is only used for symbol tables
  // and not for partial symbol results. Symbol tables are generated by the
  // geckoProfiler WebExtension API, so these are symbol tables we get from the
  // add-on.
  // We do not store results from the Mozilla symbolication API, because those
  // only contain the symbols we requested and not all the symbols of a given
  // library.
  _storeSymbolTableInDB(
    lib: RequestedLib,
    symbolTable: SymbolTableAsTuple
  ): Promise<void> {
    return this._db
      .storeSymbolTable(lib.debugName, lib.breakpadId, symbolTable)
      .catch(error => {
        console.log(
          `Failed to store the symbol table for ${
            lib.debugName
          } in the database:`,
          error
        );
      });
  }

  // Look up the symbols for the given addresses in the symbol table.
  // The symbol table is given in the [addrs, index, buffer] format.
  // This format is documented at the SymbolTableAsTuple flow type definition.
  _readSymbolsFromSymbolTable(
    addresses: Set<number>,
    symbolTable: SymbolTableAsTuple,
    demangleCallback: string => string
  ): Map<number, AddressResult> {
    const [symbolTableAddrs, symbolTableIndex, symbolTableBuffer] = symbolTable;
    const addressArray = Uint32Array.from(addresses);
    addressArray.sort();

    // Iterate over all addresses in addressArray and look them up in the
    // symbolTableAddrs array. The index at which a match is found can be used
    // to obtain the start and end position of its string in the buffer, using
    // the symbolTableIndex array.
    // Both addressArray and symbolTableAddrs are sorted in ascending order.
    const decoder = new TextDecoder();
    const results = new Map();
    let currentSymbolIndex = undefined;
    let currentSymbol = '';
    for (let i = 0; i < addressArray.length; i++) {
      const address = addressArray[i];

      // Look up address in symbolTableAddrs. symbolTableAddrs is sorted, so we
      // can do the lookup using bisection. And address is >= the previously
      // looked up address, so we can use the last found index as a lower bound
      // during the bisection.
      // We're not looking for an exact match here. We're looking for the
      // largest symbolIndex for which symbolTableAddrs[symbolIndex] <= address.
      // bisection() returns the insertion index, which is one position after
      // the index that we consider the match, so we need to subtract 1 from the
      // result.
      const symbolIndex =
        bisection(symbolTableAddrs, address, currentSymbolIndex) - 1;

      if (symbolIndex >= 0) {
        if (symbolIndex !== currentSymbolIndex) {
          // Get the corresponding string from symbolTableBuffer. The start and
          // end positions are recorded in symbolTableIndex.
          const startOffset = symbolTableIndex[symbolIndex];
          const endOffset = symbolTableIndex[symbolIndex + 1];
          const subarray = symbolTableBuffer.subarray(startOffset, endOffset);
          // C++ or rust symbols in the symbol table may have mangled names.
          // Demangle them here.
          currentSymbol = demangleCallback(decoder.decode(subarray));
          currentSymbolIndex = symbolIndex;
        }
        results.set(address, {
          functionOffset: address - symbolTableAddrs[symbolIndex],
          name: currentSymbol,
        });
      } else {
        results.set(address, {
          functionOffset: address,
          name: '<before first symbol>',
        });
      }
    }
    return results;
  }

  /**
   * Look up symbols for the given addresses in the given libraries.
   * For each LibSymbolicationRequest in requests, either errorCb or successCb
   * will be called with that LibSymbolicationRequest and the result / error.
   * This method returns a promise that resolves when the callbacks for all
   * requests have been called.
   */
  async getSymbols(
    requests: LibSymbolicationRequest[],
    successCb: (LibSymbolicationRequest, Map<number, AddressResult>) => void,
    errorCb: (LibSymbolicationRequest, Error) => void
  ): Promise<void> {
    // For each library, we have three options to obtain symbol information for
    // it. We try all options in order, advancing to the next option on failure.
    // Option 1: Symbol tables cached in the database, this._db.
    // Option 2: Obtain symbols from the symbol server.
    // Option 3: Obtain symbol tables from the add-on.

    // Check requests for validity first.
    requests = requests.filter(request => {
      const { debugName, breakpadId } = request.lib;
      if (debugName === '' || breakpadId === '') {
        errorCb(
          request,
          new SymbolsNotFoundError(
            `Failed to symbolicate library ${debugName}`,
            request.lib,
            new Error('Invalid debugName or breakpadId')
          )
        );
        return false;
      }
      return true;
    });

    // First, try option 1 for all libraries and partition them by whether it
    // was successful.
    const requestsForNonCachedLibs = [];
    const requestsForCachedLibs = [];
    await Promise.all(
      requests.map(async request => {
        const { debugName, breakpadId } = request.lib;
        try {
          // Try to get the symbol table from the database.
          // This call will throw if the symbol table is not present.
          const symbolTable = await this._db.getSymbolTable(
            debugName,
            breakpadId
          );

          // Did not throw, option 1 was successful!
          requestsForCachedLibs.push({
            request,
            symbolTable,
          });
        } catch (e) {
          if (!(e instanceof SymbolsNotFoundError)) {
            // rethrow JavaScript programming error
            throw e;
          }
          requestsForNonCachedLibs.push(request);
        }
      })
    );

    // First phase of option 2:
    // Try to service requestsForNonCachedLibs using the symbolication API,
    // requesting chunks of max 10000 addresses each. In reality, this usually
    // means that all addresses for libxul get processed in one chunk, and the
    // addresses from all other libraries get processed in a second chunk.
    // The driving idea behind this is to minimize latency: If symbolication for
    // all libraries is blocked on getting symbols for libxul, latency suffers.
    // On the other hand, if we fire off a separate request for each library,
    // latency also suffers because of per-request overhead and pipelining limits.
    const chunks = _partitionIntoChunksOfMaxValue(
      requestsForNonCachedLibs,
      10000,
      ({ addresses }) => addresses.size
    );

    // Kick off the requests to the symbolication API, and create a flattened
    // list of promises, one promise per library. Even for libraries that are
    // handled within the same request to the symbolication API, each library's
    // promise can fail independently if the symbol server does not have symbols
    // for this library.
    const libraryPromiseChunks = chunks.map(requests =>
      this._symbolProvider
        .requestSymbolsFromServer(requests)
        .map((resultsPromise, i) => ({
          request: requests[i],
          resultsPromise,
        }))
    );

    const libraryPromises = [].concat(...libraryPromiseChunks);

    // Finalize requests for which option 1 was successful:
    // Now that the requests to the server have been kicked off, process
    // symbolication for the libraries for which we found symbol tables in the
    // database. This is delayed until after the request has been kicked off
    // because it can take some time.

    // We also need a demangling function for this, which is in an async module.
    const demangleCallback = await demangleModulePromise.then(
      demangleModule => demangleModule.demangle_any,
      error => {
        // Module loading can fail (for example in browsers without WebAssembly
        // support, or due to bad server configuration), so we will fall back
        // to a pass-through function if that happens.
        console.error('Demangling module could not be imported.', error);
        return mangledString => mangledString;
      }
    );

    for (const { request, symbolTable } of requestsForCachedLibs) {
      successCb(
        request,
        this._readSymbolsFromSymbolTable(
          request.addresses,
          symbolTable,
          demangleCallback
        )
      );
    }

    // Process the results from the symbolication API request, as they arrive.
    // For each library that was not successfully symbolicated, fall back to
    // requesting a whole symbol table from the add-on. The add-on will attempt
    // to dump symbols from the binary.
    await Promise.all(
      libraryPromises.map(async ({ request, resultsPromise }) => {
        try {
          // Await the results for this library. This call will throw if the
          // symbol server did not have symbol information for this library.
          const results = await resultsPromise;

          // Did not throw, option 2 was successful!
          successCb(request, results);
        } catch (error) {
          // The symbolication API did not have any symbols for this library,
          // or an error occurred when parsing the results. We want to continue
          // to search for symbol information from other sources in both cases,
          // so we swallow the error and keep going. But in order to catch
          // problems with the API we should still log these errors.
          console.log(
            `The symbolication API request was not successful for ${
              request.lib.debugName
            }/${request.lib.breakpadId}:`,
            error
          );

          const { lib, addresses } = request;
          try {
            // Option 3: Request a symbol table from the add-on.
            // This call will throw if the add-on cannot obtain the symbol table.
            const symbolTable = await this._symbolProvider.requestSymbolTableFromAddon(
              lib
            );

            // Did not throw, option 3 was successful!
            successCb(
              request,
              this._readSymbolsFromSymbolTable(
                addresses,
                symbolTable,
                demangleCallback
              )
            );

            // Store the symbol table in the database.
            await this._storeSymbolTableInDB(lib, symbolTable);
          } catch (error) {
            // None of the symbolication methods were successful.
            // Call the error callback.
            errorCb(
              request,
              new SymbolsNotFoundError(
                `Failed to symbolicate library ${lib.debugName}`,
                lib,
                error
              )
            );
          }
        }
      })
    );
  }
}
<commit_msg>Properly works around issues with WebAssembly loading (#1565)<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// @flow
import SymbolStoreDB from './symbol-store-db';
import { SymbolsNotFoundError } from './errors';
import bisection from 'bisection';

import type { RequestedLib } from '../types/actions';
import type { SymbolTableAsTuple } from './symbol-store-db';

export type LibSymbolicationRequest = {
  lib: RequestedLib,
  addresses: Set<number>,
};

export type AddressResult = {|
  // The name of the function that this address belongs to.
  name: string,
  // The offset (in bytes) between the start of the function and the address.
  functionOffset: number,
|};

interface SymbolProvider {
  // Cheap, should be called first.
  requestSymbolsFromServer(
    requests: LibSymbolicationRequest[]
  ): Promise<Map<number, AddressResult>>[];

  // Expensive, should be called if requestSymbolsFromServer was unsuccessful.
  requestSymbolTableFromAddon(lib: RequestedLib): Promise<SymbolTableAsTuple>;
}

export interface AbstractSymbolStore {
  getSymbols(
    requests: LibSymbolicationRequest[],
    successCb: (LibSymbolicationRequest, Map<number, AddressResult>) => void,
    errorCb: (LibSymbolicationRequest, Error) => void
  ): Promise<void>;
}

// Partition the array into "chunks".
// Every element in the array is assigned a numeric value using the computeValue
// callback function. The chunks are chosen in such a way that the accumulated
// value in each chunk does not exceed maxValue, if possible.
// In other words, for each chunk, the following will hold:
// sum(chunk.map(computeValue)) <= maxValue or chunk.length == 1.
// The array is allowed to contain elements which are larger than the maximum
// value on their own; such elements will get a single chunk for themselves.
function _partitionIntoChunksOfMaxValue<T>(
  array: T[],
  maxValue: number,
  computeValue: T => number
): T[][] {
  const chunks = [];
  for (const element of array) {
    const elementValue = computeValue(element);
    // Find an existing chunk that still has enough "value space" left to
    // accomodate this element.
    let chunk = chunks.find(({ value }) => value + elementValue <= maxValue);
    if (chunk === undefined) {
      // If no chunk was found, create a new chunk.
      chunk = { value: 0, elements: [] };
      chunks.push(chunk);
    }
    chunk.elements.push(element);
    chunk.value += elementValue;
  }
  return chunks.map(({ elements }) => elements);
}

type DemangleFunction = string => string;

/**
 * This function returns a function that can demangle function name using a
 * WebAssembly module, but falls back on the identity function if the
 * WebAssembly module isn't available for some reason.
 */
async function _getDemangleCallback(): Promise<DemangleFunction> {
  try {
    // When this module imports some WebAssembly module, Webpack's mechanism
    // invokes the WebAssembly object which might be absent in some browsers,
    // therefore `import` can throw. Also some browsers might refuse to load a
    // wasm module because of our CSP.
    // See webpack bug https://github.com/webpack/webpack/issues/8517
    const demangleModule = await import('gecko-profiler-demangle');
    return demangleModule.demangle_any;
  } catch (error) {
    // Module loading can fail (for example in browsers without WebAssembly
    // support, or due to bad server configuration), so we will fall back
    // to a pass-through function if that happens.
    console.error('Demangling module could not be imported.', error);
    return mangledString => mangledString;
  }
}

/**
 * The SymbolStore implements efficient lookup of symbols for a set of addresses.
 * It consults multiple sources of symbol information and caches some results.
 * It only implements one public method: getSymbols.
 * @class SymbolStore
 */
export class SymbolStore {
  _symbolProvider: SymbolProvider;
  _db: SymbolStoreDB;

  constructor(dbNamePrefix: string, symbolProvider: SymbolProvider) {
    this._symbolProvider = symbolProvider;
    this._db = new SymbolStoreDB(`${dbNamePrefix}-symbol-tables`);
  }

  async closeDb() {
    await this._db.close();
  }

  // Store a symbol table in the database. This is only used for symbol tables
  // and not for partial symbol results. Symbol tables are generated by the
  // geckoProfiler WebExtension API, so these are symbol tables we get from the
  // add-on.
  // We do not store results from the Mozilla symbolication API, because those
  // only contain the symbols we requested and not all the symbols of a given
  // library.
  _storeSymbolTableInDB(
    lib: RequestedLib,
    symbolTable: SymbolTableAsTuple
  ): Promise<void> {
    return this._db
      .storeSymbolTable(lib.debugName, lib.breakpadId, symbolTable)
      .catch(error => {
        console.log(
          `Failed to store the symbol table for ${
            lib.debugName
          } in the database:`,
          error
        );
      });
  }

  // Look up the symbols for the given addresses in the symbol table.
  // The symbol table is given in the [addrs, index, buffer] format.
  // This format is documented at the SymbolTableAsTuple flow type definition.
  _readSymbolsFromSymbolTable(
    addresses: Set<number>,
    symbolTable: SymbolTableAsTuple,
    demangleCallback: string => string
  ): Map<number, AddressResult> {
    const [symbolTableAddrs, symbolTableIndex, symbolTableBuffer] = symbolTable;
    const addressArray = Uint32Array.from(addresses);
    addressArray.sort();

    // Iterate over all addresses in addressArray and look them up in the
    // symbolTableAddrs array. The index at which a match is found can be used
    // to obtain the start and end position of its string in the buffer, using
    // the symbolTableIndex array.
    // Both addressArray and symbolTableAddrs are sorted in ascending order.
    const decoder = new TextDecoder();
    const results = new Map();
    let currentSymbolIndex = undefined;
    let currentSymbol = '';
    for (let i = 0; i < addressArray.length; i++) {
      const address = addressArray[i];

      // Look up address in symbolTableAddrs. symbolTableAddrs is sorted, so we
      // can do the lookup using bisection. And address is >= the previously
      // looked up address, so we can use the last found index as a lower bound
      // during the bisection.
      // We're not looking for an exact match here. We're looking for the
      // largest symbolIndex for which symbolTableAddrs[symbolIndex] <= address.
      // bisection() returns the insertion index, which is one position after
      // the index that we consider the match, so we need to subtract 1 from the
      // result.
      const symbolIndex =
        bisection(symbolTableAddrs, address, currentSymbolIndex) - 1;

      if (symbolIndex >= 0) {
        if (symbolIndex !== currentSymbolIndex) {
          // Get the corresponding string from symbolTableBuffer. The start and
          // end positions are recorded in symbolTableIndex.
          const startOffset = symbolTableIndex[symbolIndex];
          const endOffset = symbolTableIndex[symbolIndex + 1];
          const subarray = symbolTableBuffer.subarray(startOffset, endOffset);
          // C++ or rust symbols in the symbol table may have mangled names.
          // Demangle them here.
          currentSymbol = demangleCallback(decoder.decode(subarray));
          currentSymbolIndex = symbolIndex;
        }
        results.set(address, {
          functionOffset: address - symbolTableAddrs[symbolIndex],
          name: currentSymbol,
        });
      } else {
        results.set(address, {
          functionOffset: address,
          name: '<before first symbol>',
        });
      }
    }
    return results;
  }

  /**
   * Look up symbols for the given addresses in the given libraries.
   * For each LibSymbolicationRequest in requests, either errorCb or successCb
   * will be called with that LibSymbolicationRequest and the result / error.
   * This method returns a promise that resolves when the callbacks for all
   * requests have been called.
   */
  async getSymbols(
    requests: LibSymbolicationRequest[],
    successCb: (LibSymbolicationRequest, Map<number, AddressResult>) => void,
    errorCb: (LibSymbolicationRequest, Error) => void
  ): Promise<void> {
    // For each library, we have three options to obtain symbol information for
    // it. We try all options in order, advancing to the next option on failure.
    // Option 1: Symbol tables cached in the database, this._db.
    // Option 2: Obtain symbols from the symbol server.
    // Option 3: Obtain symbol tables from the add-on.

    // Check requests for validity first.
    requests = requests.filter(request => {
      const { debugName, breakpadId } = request.lib;
      if (debugName === '' || breakpadId === '') {
        errorCb(
          request,
          new SymbolsNotFoundError(
            `Failed to symbolicate library ${debugName}`,
            request.lib,
            new Error('Invalid debugName or breakpadId')
          )
        );
        return false;
      }
      return true;
    });

    // First, try option 1 for all libraries and partition them by whether it
    // was successful.
    const requestsForNonCachedLibs = [];
    const requestsForCachedLibs = [];
    await Promise.all(
      requests.map(async request => {
        const { debugName, breakpadId } = request.lib;
        try {
          // Try to get the symbol table from the database.
          // This call will throw if the symbol table is not present.
          const symbolTable = await this._db.getSymbolTable(
            debugName,
            breakpadId
          );

          // Did not throw, option 1 was successful!
          requestsForCachedLibs.push({
            request,
            symbolTable,
          });
        } catch (e) {
          if (!(e instanceof SymbolsNotFoundError)) {
            // rethrow JavaScript programming error
            throw e;
          }
          requestsForNonCachedLibs.push(request);
        }
      })
    );

    // First phase of option 2:
    // Try to service requestsForNonCachedLibs using the symbolication API,
    // requesting chunks of max 10000 addresses each. In reality, this usually
    // means that all addresses for libxul get processed in one chunk, and the
    // addresses from all other libraries get processed in a second chunk.
    // The driving idea behind this is to minimize latency: If symbolication for
    // all libraries is blocked on getting symbols for libxul, latency suffers.
    // On the other hand, if we fire off a separate request for each library,
    // latency also suffers because of per-request overhead and pipelining limits.
    const chunks = _partitionIntoChunksOfMaxValue(
      requestsForNonCachedLibs,
      10000,
      ({ addresses }) => addresses.size
    );

    // Kick off the requests to the symbolication API, and create a flattened
    // list of promises, one promise per library. Even for libraries that are
    // handled within the same request to the symbolication API, each library's
    // promise can fail independently if the symbol server does not have symbols
    // for this library.
    const libraryPromiseChunks = chunks.map(requests =>
      this._symbolProvider
        .requestSymbolsFromServer(requests)
        .map((resultsPromise, i) => ({
          request: requests[i],
          resultsPromise,
        }))
    );

    const libraryPromises = [].concat(...libraryPromiseChunks);

    // Finalize requests for which option 1 was successful:
    // Now that the requests to the server have been kicked off, process
    // symbolication for the libraries for which we found symbol tables in the
    // database. This is delayed until after the request has been kicked off
    // because it can take some time.

    // We also need a demangling function for this, which is in an async module.
    const demangleCallback = await _getDemangleCallback();

    for (const { request, symbolTable } of requestsForCachedLibs) {
      successCb(
        request,
        this._readSymbolsFromSymbolTable(
          request.addresses,
          symbolTable,
          demangleCallback
        )
      );
    }

    // Process the results from the symbolication API request, as they arrive.
    // For each library that was not successfully symbolicated, fall back to
    // requesting a whole symbol table from the add-on. The add-on will attempt
    // to dump symbols from the binary.
    await Promise.all(
      libraryPromises.map(async ({ request, resultsPromise }) => {
        try {
          // Await the results for this library. This call will throw if the
          // symbol server did not have symbol information for this library.
          const results = await resultsPromise;

          // Did not throw, option 2 was successful!
          successCb(request, results);
        } catch (error) {
          // The symbolication API did not have any symbols for this library,
          // or an error occurred when parsing the results. We want to continue
          // to search for symbol information from other sources in both cases,
          // so we swallow the error and keep going. But in order to catch
          // problems with the API we should still log these errors.
          console.log(
            `The symbolication API request was not successful for ${
              request.lib.debugName
            }/${request.lib.breakpadId}:`,
            error
          );

          const { lib, addresses } = request;
          try {
            // Option 3: Request a symbol table from the add-on.
            // This call will throw if the add-on cannot obtain the symbol table.
            const symbolTable = await this._symbolProvider.requestSymbolTableFromAddon(
              lib
            );

            // Did not throw, option 3 was successful!
            successCb(
              request,
              this._readSymbolsFromSymbolTable(
                addresses,
                symbolTable,
                demangleCallback
              )
            );

            // Store the symbol table in the database.
            await this._storeSymbolTableInDB(lib, symbolTable);
          } catch (error) {
            // None of the symbolication methods were successful.
            // Call the error callback.
            errorCb(
              request,
              new SymbolsNotFoundError(
                `Failed to symbolicate library ${lib.debugName}`,
                lib,
                error
              )
            );
          }
        }
      })
    );
  }
}
<|endoftext|>


<commit_before>import React from 'react';
import { shallow } from 'enzyme';

import AccountAddress from './accountAddress';

test('AccountAddress shows address', () => {
    const accountAddr = shallow(
        <AccountAddress id="0x123" />
    );
    expect(accountAddr.find('div').children().find('div').text()).toEqual('0x123');
});
<commit_msg>Fixed test<commit_after>import React from 'react';
import { shallow } from 'enzyme';

import AccountAddress from './accountAddress';

test('AccountAddress shows address', () => {
    const accountAddr = shallow(
        <AccountAddress id="0x123" />
    );
    expect(accountAddr.find('div').children().find('div').first().text()).toEqual('0x123');
});
<|endoftext|>


<commit_before>'use strict';

var inquirer = require('inquirer');

var validate = {
	required: function(value) {
		return !value ? 'This field is required' : true;
	}
};

inquirer.prompt([

	{
		name: 'username',
		message: 'Username',
		type: 'input',
		validate: validate.required
	},
	{
		name: 'password',
		message: 'Password',
		type: 'password',
		validate: validate.required
	}

], function(answers) {

	var UserModel = require('../models/User');

	UserModel.create(answers, function(error, user) {

		if (error) {
			console.error(error);
			return process.exit(1);
		}

		console.log('Success! A new admin user has been created.');
		process.exit(0);
	});
});
<commit_msg>Catch error in inquirer prompt<commit_after>'use strict';

var inquirer = require('inquirer');

var validate = {
	required: function(value) {
		return !value ? 'This field is required' : true;
	}
};

inquirer.prompt([

	{
		name: 'username',
		message: 'Username',
		type: 'input',
		validate: validate.required
	},
	{
		name: 'password',
		message: 'Password',
		type: 'password',
		validate: validate.required
	}

]).then(function(answers) {

	var UserModel = require('../models/User');

	UserModel.create(answers, function(error, user) {

		if (error) {
			console.error(error);
			return process.exit(1);
		}

		console.log('Success! A new admin user has been created.');
		process.exit(0);
	});
}).catch(function(error) {
	console.log(error);
});
<|endoftext|>


<commit_before>const db = require('sqlite')
const squel = require('squel')
const debug = require('debug')
const log = debug('app:media')

class Media {
/**
 * Get artists and "songs" in a format suitable for sending to clients
 * as quickly as possible. Only lists one media item per song (the
 * preferred item, if one is set) and does not include providerData
 *
 * @return {Promise} Object with artist and media results
 */
  static async getLibrary () {
    const artists = {
      result: [],
      entities: {}
    }
    const media = {
      result: [],
      entities: {}
    }

    try {
      const q = squel.select()
        .field('media.mediaId, media.title, media.duration, media.artistId')
        .field('artists.name AS artist')
        .field('MAX(media.isPreferred) AS isPreferred')
        .field('COUNT(*) AS numMedia')
        .field('COUNT(stars.userId) AS numStars')
        .from('media')
        .join(squel.select()
          .from('providers')
          .where('providers.isEnabled = 1')
          .order('priority'),
        'providers', 'media.provider = providers.name')
        .join('artists USING (artistId)')
        .left_join('stars USING(mediaId)')
        .group('artistId')
        .group('title')
        .order('artists.name')
        .order('media.title')

      const { text, values } = q.toParam()
      const rows = await db.all(text, values)

      for (const row of rows) {
        // no need to send over the wire but we needed it
        // in the query to show the correct mediaId
        delete row.isPreferred

        // new artist?
        if (typeof artists.entities[row.artistId] === 'undefined') {
          artists.result.push(row.artistId)
          artists.entities[row.artistId] = {
            artistId: row.artistId,
            name: row.artist,
            mediaIds: [],
          }
        }

        // add mediaId to artist's LUT
        artists.entities[row.artistId].mediaIds.push(row.mediaId)

        media.result.push(row.mediaId)
        media.entities[row.mediaId] = row
      }
    } catch (err) {
      return Promise.reject(err)
    }

    return { artists, media }
  }

  /**
   * Get media items matching all search criteria
   *
   * @param  {object}  fields Search criteria
   * @return {Promise}        Object with media results
   */
  static async getMedia (fields) {
    let rows
    const media = {
      result: [],
      entities: {}
    }

    const q = squel.select()
      .field('media.*')
      .from('media')
      .join(squel.select()
        .from('providers')
        .where('providers.isEnabled = 1')
        .order('priority'),
      'providers', 'media.provider = providers.name')
      .group('artistId')
      .group('title')

    // filters
    Object.keys(fields).map(key => {
      if (key === 'providerData' && typeof fields.providerData === 'object') {
        Object.keys(fields.providerData).map(i => {
          q.where(`json_extract(providerData, '$.${i}') = ?`, fields.providerData[i])
        })
      } else {
        q.where(`${key} = ?`, fields[key])
      }
    })

    try {
      const { text, values } = q.toParam()
      rows = await db.all(text, values)
    } catch (err) {
      return Promise.reject(err)
    }

    for (const row of rows) {
      media.result.push(row.mediaId)
      media.entities[row.mediaId] = row
    }

    return media
  }

  /**
   * Add media item to the library, matching or adding artist
   *
   * @param  {object}  media Media item
   * @return {Promise}       Newly added item's mediaId (number)
   */
  static async add (media) {
    if (!media.artist || !media.title || !media.duration || !media.provider) {
      return Promise.reject(new Error('Invalid media data: ' + JSON.stringify(media)))
    }

    // does the artist already exist?
    let row

    try {
      const q = squel.select()
        .from('artists')
        .where('name = ?', media.artist)

      const { text, values } = q.toParam()
      row = await db.get(text, values)
    } catch (err) {
      return Promise.reject(err)
    }

    if (row) {
      log('matched artist: %s', row.name)
      media.artistId = row.artistId
    } else {
      log('new artist: %s', media.artist)

      try {
        const q = squel.insert()
          .into('artists')
          .set('name', media.artist)

        const { text, values } = q.toParam()
        const res = await db.run(text, values)

        if (!Number.isInteger(res.stmt.lastID)) {
          throw new Error('invalid lastID after artist insert')
        }

        media.artistId = res.stmt.lastID
      } catch (err) {
        return Promise.reject(err)
      }
    }

    // prep for insert; we have the artistId now
    delete media.artist
    media.duration = Math.round(media.duration)
    media.providerData = JSON.stringify(media.providerData || {})

    try {
      const q = squel.insert()
        .into('media')

      Object.keys(media).forEach(key => {
        q.set(key, media[key])
      })

      const { text, values } = q.toParam()
      const res = await db.run(text, values)

      if (!Number.isInteger(res.stmt.lastID)) {
        throw new Error('got invalid lastID after song insert')
      }

      // return mediaId
      return Promise.resolve(res.stmt.lastID)
    } catch (err) {
      log(err)
      return Promise.reject(err)
    }
  }
}

module.exports = Media
<commit_msg>Support array of values when searching providerData<commit_after>const db = require('sqlite')
const squel = require('squel')
const debug = require('debug')
const log = debug('app:media')

class Media {
/**
 * Get artists and "songs" in a format suitable for sending to clients
 * as quickly as possible. Only lists one media item per song (the
 * preferred item, if one is set) and does not include providerData
 *
 * @return {Promise} Object with artist and media results
 */
  static async getLibrary () {
    const artists = {
      result: [],
      entities: {}
    }
    const media = {
      result: [],
      entities: {}
    }

    try {
      const q = squel.select()
        .field('media.mediaId, media.title, media.duration, media.artistId')
        .field('artists.name AS artist')
        .field('MAX(media.isPreferred) AS isPreferred')
        .field('COUNT(*) AS numMedia')
        .field('COUNT(stars.userId) AS numStars')
        .from('media')
        .join(squel.select()
          .from('providers')
          .where('providers.isEnabled = 1')
          .order('priority'),
        'providers', 'media.provider = providers.name')
        .join('artists USING (artistId)')
        .left_join('stars USING(mediaId)')
        .group('artistId')
        .group('title')
        .order('artists.name')
        .order('media.title')

      const { text, values } = q.toParam()
      const rows = await db.all(text, values)

      for (const row of rows) {
        // no need to send over the wire but we needed it
        // in the query to show the correct mediaId
        delete row.isPreferred

        // new artist?
        if (typeof artists.entities[row.artistId] === 'undefined') {
          artists.result.push(row.artistId)
          artists.entities[row.artistId] = {
            artistId: row.artistId,
            name: row.artist,
            mediaIds: [],
          }
        }

        // add mediaId to artist's LUT
        artists.entities[row.artistId].mediaIds.push(row.mediaId)

        media.result.push(row.mediaId)
        media.entities[row.mediaId] = row
      }
    } catch (err) {
      return Promise.reject(err)
    }

    return { artists, media }
  }

  /**
   * Get media items matching all search criteria
   *
   * @param  {object}  fields Search criteria
   * @return {Promise}        Object with media results
   */
  static async getMedia (fields) {
    let rows
    const media = {
      result: [],
      entities: {}
    }

    const q = squel.select()
      .field('media.*')
      .from('media')
      .join(squel.select()
        .from('providers')
        .where('providers.isEnabled = 1')
        .order('priority'),
      'providers', 'media.provider = providers.name')
      .group('artistId')
      .group('title')

    // filters
    Object.keys(fields).map(key => {
      if (key === 'providerData' && typeof fields.providerData === 'object') {
        Object.keys(fields.providerData).map(pKey => {
          const val = fields.providerData[pKey]

          if (Array.isArray(val)) {
            q.where(`json_extract(providerData, '$.${pKey}') IN ?`, val)
          } else {
            q.where(`json_extract(providerData, '$.${pKey}') = ?`, val)
          }
        })
      } else {
        q.where(`${key} = ?`, fields[key])
      }
    })

    try {
      const { text, values } = q.toParam()
      rows = await db.all(text, values)
    } catch (err) {
      return Promise.reject(err)
    }

    for (const row of rows) {
      media.result.push(row.mediaId)
      media.entities[row.mediaId] = row
    }

    return media
  }

  /**
   * Add media item to the library, matching or adding artist
   *
   * @param  {object}  media Media item
   * @return {Promise}       Newly added item's mediaId (number)
   */
  static async add (media) {
    if (!media.artist || !media.title || !media.duration || !media.provider) {
      return Promise.reject(new Error('Invalid media data: ' + JSON.stringify(media)))
    }

    // does the artist already exist?
    let row

    try {
      const q = squel.select()
        .from('artists')
        .where('name = ?', media.artist)

      const { text, values } = q.toParam()
      row = await db.get(text, values)
    } catch (err) {
      return Promise.reject(err)
    }

    if (row) {
      log('matched artist: %s', row.name)
      media.artistId = row.artistId
    } else {
      log('new artist: %s', media.artist)

      try {
        const q = squel.insert()
          .into('artists')
          .set('name', media.artist)

        const { text, values } = q.toParam()
        const res = await db.run(text, values)

        if (!Number.isInteger(res.stmt.lastID)) {
          throw new Error('invalid lastID after artist insert')
        }

        media.artistId = res.stmt.lastID
      } catch (err) {
        return Promise.reject(err)
      }
    }

    // prep for insert; we have the artistId now
    delete media.artist
    media.duration = Math.round(media.duration)
    media.providerData = JSON.stringify(media.providerData || {})

    try {
      const q = squel.insert()
        .into('media')

      Object.keys(media).forEach(key => {
        q.set(key, media[key])
      })

      const { text, values } = q.toParam()
      const res = await db.run(text, values)

      if (!Number.isInteger(res.stmt.lastID)) {
        throw new Error('got invalid lastID after song insert')
      }

      // return mediaId
      return Promise.resolve(res.stmt.lastID)
    } catch (err) {
      log(err)
      return Promise.reject(err)
    }
  }
}

module.exports = Media
<|endoftext|>


<commit_before>var url = require('url')
var util = require('util')
var zlib = require('zlib')
var http = require('http')
var https = require('https')
var Netrc = require('netrc')
var write = require('write-to')
var status = require('statuses')
var rawBody = require('raw-body')
var qs = require('querystring')
var debug = require('debug')('cogent')

var inspect = util.inspect

exports = module.exports = extend()
exports.extend = extend

function extend(defaults) {
  defaults = defaults || {}
  defaults.retries = defaults.retries || 0
  defaults.redirects = 'redirects' in defaults ? defaults.redirects : 3
  defaults.timeout = defaults.timeout || 5000
  defaults.method = defaults.method || 'GET'
  defaults.gunzip = defaults.gunzip === false ? false : true
  defaults.netrc = Netrc(defaults.netrc)

  return cogent

  function* cogent(uri, options, params) {
    // options type checking stuff
    if (options === true)
      options = { json: true }
    else if (typeof options === 'string')
      options = { destination: options }
    else if (!options)
      options = {}

    if(params && typeof params !== 'object')
      params = false

    // setup defaults
    var redirects = options.redirects || ( options.redirects !== 0 ? defaults.redirects : 0 )
    var timeout = options.timeout || ( options.timeout !== 0 ? defaults.timeout : 0 )
    var netrc = options.netrc ? Netrc(options.netrc) : defaults.netrc

    // setup headers
    var headers = options.headers = options.headers || {}
    headers['accept-encoding'] = headers['accept-encoding'] || 'gzip'
    headers['user-agent'] = headers['user-agent'] || 'https://github.com/cojs/cogent'
    headers['content-type'] = headers['content-type'] || 'application/json'
    if (options.json) headers.accept = 'application/json'

    // keep a history of redirect urls
    var urls = []

    var o, req, res, code, stream, securrrr, retries , paramsstr
    // while loop to handle redirects
    while (true) {
      var method = (options.method || defaults.method).toUpperCase()
      switch(method){
        case 'PUT':
        case 'POST':
        case 'DELETE':
          headers['transfer-encoding'] = 'chunked';
          if(params){
            paramsstr = JSON.stringify(params);
            headers['content-length'] = paramsstr.length;
          }
          break;
        default:
          if(params){
            uri = uri.lastIndexOf('?') == -1
            ? (uri + '?' + qs.stringify(params))
            : (uri + '&' + qs.stringify(params))
          }
          break;
      }

      // create the request options object
      urls.push(o = url.parse(uri))
      securrrr = o.protocol === 'https:'
      o.headers = options.headers
      o.method = options.method || defaults.method

      // auth, either by .auth or by .netrc
      if (options.auth || defaults.auth) {
        o.auth = options.auth || defaults.auth
      } else {
        var auth = netrc[o.hostname]
        if (auth) o.auth =
            (auth.login || auth.user || auth.username)
          + ':'
          + (auth.pass || auth.password)
      }

      // setup agent or proxy agent
      if ('agent' in options) {
        o.agent = options.agent
      } else if (defaults.agent != null) {
        o.agent = defaults.agent
      }

      // retries is on a per-URL-request basis
      retries = options.retries || defaults.retries

      debug('options: %s', inspect(o))

      res = yield request()
      code = res.statusCode

      // redirect
      if (redirects-- && status.redirect[code]) {
        debug('redirecting from %s to %s', uri, res.headers.location)
        uri = url.resolve(uri, res.headers.location)
        res.resume() // dump this stream
        continue
      }

      // return early on HEAD requests
      if (o.method.toUpperCase() === 'HEAD') {
        res.req = req
        res.resume()
        return res
      }

      // unzip
      var gunzip = typeof options.gunzip === 'boolean'
        ? options.gunzip
        : defaults.gunzip
      if (!gunzip && (options.buffer || options.string || options.json))
        throw new Error('must gunzip if buffering the response')
      if (res.headers['content-encoding'] === 'gzip' && gunzip) {
        stream = res.pipe(zlib.createGunzip())
        stream.res = res
        // pass useful response stuff
        stream.statusCode = code
        stream.headers = res.headers
        // forward errors
        res.on('error', stream.emit.bind(stream, 'error'))
        // forward close
        // creates the following error:
        // Assertion failed: (!write_in_progress_ && "write in progress"), function Close, file ../src/node_zlib.cc, line 99.
        // make: *** [test] Abort trap: 6
        // res.on('close', stream.close.bind(stream))
        // forward destroy
        // note: if zlib adds a .destroy method, we have to change this
        stream.destroy = res.destroy.bind(res)
        res = stream
      } else {
        res.res = res
      }

      res.req = req
      res.urls = urls

      // save the file
      if (code === 200 && options.destination) {
        yield write(res, options.destination)
        res.destination = options.destination
        return res
      }

      // buffer the response
      if (options.buffer)
        res.buffer = yield rawBody(res)
      // buffer the response as a string or object
      if (options.string || options.json)
        res.text = res.buffer
          ? res.buffer.toString('utf8')
          : yield rawBody(res, { encoding: options.string || true })
      // buffer the response as JSON
      if (options.json) try {
        res.body = JSON.parse(res.text)
      } catch (err) {
        debug('"%s" is not valid JSON', uri)
      }

      return res
    }

    function request() {
      return new Promise(function (resolve, reject) {
        var called = false

        // timeout
        // note: timeout is only for the response,
        // not the entire request
        var id = setTimeout(function () {
          debug('timeout exceeded for %s %s', o.method, o.href)
          var err = new Error('timeout of ' + timeout + 'ms exceeded for "' + o.href + '"')
          err.url = o
          next(err)
        }, timeout)

        req = (securrrr ? https : http).request(o)
        if(paramsstr && paramsstr.length > 0)
          req.write(paramsstr)
        req.once('response', next)
        req.once('error', next)
        req.end()

        function next(err, res) {
          if (called) {
            // dump the stream in case there are any
            // to avoid any possible leaks
            if (res) res.resume()
            return
          }

          called = true
          clearTimeout(id)

          if (!(err instanceof Error)) {
            res = err
            err = null
          }

          // kill the request, specifically for timeouts
          // to do: tests for this #7
          if (err) req.abort()

          if (retries && (err
            || (res && status.retry[res.statusCode])
          )) {
            debug('retrying %s %s', o.method, o.href)
            retries--
            resolve(request())
          } else if (err) {
            debug('received error "%s" with "%s"', err.message, o.href)
            reject(err)
          } else {
            resolve(res)
          }
        }
      })
    }
  }
}
<commit_msg>Update cogent.js<commit_after>var url = require('url')
var util = require('util')
var zlib = require('zlib')
var http = require('http')
var https = require('https')
var Netrc = require('netrc')
var write = require('write-to')
var status = require('statuses')
var rawBody = require('raw-body')
var qs = require('querystring')
var debug = require('debug')('cogent')

var inspect = util.inspect

exports = module.exports = extend()
exports.extend = extend

function extend(defaults) {
  defaults = defaults || {}
  defaults.retries = defaults.retries || 0
  defaults.redirects = 'redirects' in defaults ? defaults.redirects : 3
  defaults.timeout = defaults.timeout || 5000
  defaults.method = defaults.method || 'GET'
  defaults.gunzip = defaults.gunzip === false ? false : true
  defaults.netrc = Netrc(defaults.netrc)

  return cogent

  function* cogent(uri, options, params) {
    // options type checking stuff
    if (options === true)
      options = { json: true }
    else if (typeof options === 'string')
      options = { destination: options }
    else if (!options)
      options = {}

    if(params && typeof params !== 'object')
      params = false

    // setup defaults
    var redirects = options.redirects || ( options.redirects !== 0 ? defaults.redirects : 0 )
    var timeout = options.timeout || ( options.timeout !== 0 ? defaults.timeout : 0 )
    var netrc = options.netrc ? Netrc(options.netrc) : defaults.netrc

    // setup headers
    var headers = options.headers = options.headers || {}
    headers['accept-encoding'] = headers['accept-encoding'] || 'gzip'
    headers['user-agent'] = headers['user-agent'] || 'https://github.com/cojs/cogent'
    headers['content-type'] = headers['content-type'] || 'application/json'
    if (options.json) headers.accept = 'application/json'

    // keep a history of redirect urls
    var urls = []

    var o, req, res, code, stream, securrrr, retries , paramsstr
    // while loop to handle redirects
    while (true) {
      var method = (options.method || defaults.method).toUpperCase()
      switch(method){
        case 'PUT':
        case 'POST':
        case 'DELETE':
          headers['transfer-encoding'] = 'chunked';
          if(params){
            paramsstr = JSON.stringify(params);
          }
          break;
        default:
          if(params){
            uri = uri.lastIndexOf('?') == -1
            ? (uri + '?' + qs.stringify(params))
            : (uri + '&' + qs.stringify(params))
          }
          break;
      }

      // create the request options object
      urls.push(o = url.parse(uri))
      securrrr = o.protocol === 'https:'
      o.headers = options.headers
      o.method = options.method || defaults.method

      // auth, either by .auth or by .netrc
      if (options.auth || defaults.auth) {
        o.auth = options.auth || defaults.auth
      } else {
        var auth = netrc[o.hostname]
        if (auth) o.auth =
            (auth.login || auth.user || auth.username)
          + ':'
          + (auth.pass || auth.password)
      }

      // setup agent or proxy agent
      if ('agent' in options) {
        o.agent = options.agent
      } else if (defaults.agent != null) {
        o.agent = defaults.agent
      }

      // retries is on a per-URL-request basis
      retries = options.retries || defaults.retries

      debug('options: %s', inspect(o))

      res = yield request()
      code = res.statusCode

      // redirect
      if (redirects-- && status.redirect[code]) {
        debug('redirecting from %s to %s', uri, res.headers.location)
        uri = url.resolve(uri, res.headers.location)
        res.resume() // dump this stream
        continue
      }

      // return early on HEAD requests
      if (o.method.toUpperCase() === 'HEAD') {
        res.req = req
        res.resume()
        return res
      }

      // unzip
      var gunzip = typeof options.gunzip === 'boolean'
        ? options.gunzip
        : defaults.gunzip
      if (!gunzip && (options.buffer || options.string || options.json))
        throw new Error('must gunzip if buffering the response')
      if (res.headers['content-encoding'] === 'gzip' && gunzip) {
        stream = res.pipe(zlib.createGunzip())
        stream.res = res
        // pass useful response stuff
        stream.statusCode = code
        stream.headers = res.headers
        // forward errors
        res.on('error', stream.emit.bind(stream, 'error'))
        // forward close
        // creates the following error:
        // Assertion failed: (!write_in_progress_ && "write in progress"), function Close, file ../src/node_zlib.cc, line 99.
        // make: *** [test] Abort trap: 6
        // res.on('close', stream.close.bind(stream))
        // forward destroy
        // note: if zlib adds a .destroy method, we have to change this
        stream.destroy = res.destroy.bind(res)
        res = stream
      } else {
        res.res = res
      }

      res.req = req
      res.urls = urls

      // save the file
      if (code === 200 && options.destination) {
        yield write(res, options.destination)
        res.destination = options.destination
        return res
      }

      // buffer the response
      if (options.buffer)
        res.buffer = yield rawBody(res)
      // buffer the response as a string or object
      if (options.string || options.json)
        res.text = res.buffer
          ? res.buffer.toString('utf8')
          : yield rawBody(res, { encoding: options.string || true })
      // buffer the response as JSON
      if (options.json) try {
        res.body = JSON.parse(res.text)
      } catch (err) {
        debug('"%s" is not valid JSON', uri)
      }

      return res
    }

    function request() {
      return new Promise(function (resolve, reject) {
        var called = false

        // timeout
        // note: timeout is only for the response,
        // not the entire request
        var id = setTimeout(function () {
          debug('timeout exceeded for %s %s', o.method, o.href)
          var err = new Error('timeout of ' + timeout + 'ms exceeded for "' + o.href + '"')
          err.url = o
          next(err)
        }, timeout)

        req = (securrrr ? https : http).request(o)
        if(paramsstr && paramsstr.length > 0)
          req.write(paramsstr)
        req.once('response', next)
        req.once('error', next)
        req.end()

        function next(err, res) {
          if (called) {
            // dump the stream in case there are any
            // to avoid any possible leaks
            if (res) res.resume()
            return
          }

          called = true
          clearTimeout(id)

          if (!(err instanceof Error)) {
            res = err
            err = null
          }

          // kill the request, specifically for timeouts
          // to do: tests for this #7
          if (err) req.abort()

          if (retries && (err
            || (res && status.retry[res.statusCode])
          )) {
            debug('retrying %s %s', o.method, o.href)
            retries--
            resolve(request())
          } else if (err) {
            debug('received error "%s" with "%s"', err.message, o.href)
            reject(err)
          } else {
            resolve(res)
          }
        }
      })
    }
  }
}
<|endoftext|>


<commit_before>import React from 'react'

export default class NullNotification extends React.Component {
  render() {
    return (

You had no notificatoins, yet.

    )
  }
}

NullNotification.propTypes = {}

NullNotification.defaultProps = {}
<commit_msg>Fix typo in NullNotification component<commit_after>import React from 'react'

export default class NullNotification extends React.Component {
  render() {
    return (

You had no notifications, yet.

    )
  }
}

NullNotification.propTypes = {}

NullNotification.defaultProps = {}
<|endoftext|>


<commit_before>import {asyncComponent} from 'vendors/AsyncComponent';

import AppContainer from 'examples/containers/AppContainer';
import AppRoot from 'examples/containers/AppRoot';

export default [{
    component: AppContainer,
    routes: [{
        path: '/',
        component: AppRoot,
        routes: [{
            path: '/landing',
            component: asyncComponent(() => {
                return import(
                    /* webpackChunkName: "Landing" */
                    'containers/landing/Landing'
                    );
            })
        }, {
            path: '/components',
            component: asyncComponent(() => {
                return import(
                    /* webpackChunkName: "App" */
                    'containers/app/App'
                    );
            }),
            routes: [

                /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- buttons -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
                {
                    path: '/components/RaisedButton',
                    component: asyncComponent(() => {
                        return import(
                            /* webpackChunkName: "RaisedButtonExamples" */
                            'modules/buttons/RaisedButtonExamples'
                            );
                    })
                }, {
                    path: '/components/FlatButton',
                    component: asyncComponent(() => {
                        return import(
                            /* webpackChunkName: "FlatButtonExamples" */
                            'modules/buttons/FlatButtonExamples'
                            );
                    })
                }, {
                    path: '/components/GhostButton',
                    component: asyncComponent(() => {
                        return import(
                            /* webpackChunkName: "GhostButtonExamples" */
                            'modules/buttons/GhostButtonExamples'
                            );
                    })
                }, {
                    path: '/components/IconButton',
                    component: asyncComponent(() => {
                        return import(
                            /* webpackChunkName: "IconButtonExamples" */
                            'modules/buttons/IconButtonExamples'
                            );
                    })
                }, {
                    path: '/components/IconAnchor',
                    component: asyncComponent(() => {
                        return import(
                            /* webpackChunkName: "IconAnchorExamples" */
                            'modules/buttons/IconAnchorExamples'
                            );
                    })
                }
            ]
        }]
    }]
}];<commit_msg>update<commit_after>import {asyncComponent} from 'vendors/AsyncComponent';

import AppContainer from 'examples/containers/AppContainer';
import AppRoot from 'examples/containers/AppRoot';

export default [{
    component: AppContainer,
    routes: [{
        path: '/',
        component: AppRoot,
        routes: [{
            path: '/landing',
            component: asyncComponent(() => {
                return import(
                    /* webpackChunkName: "Landing" */
                    'containers/landing/Landing'
                    );
            })
        }, {
            path: '/components',
            component: asyncComponent(() => {
                return import(
                    /* webpackChunkName: "App" */
                    'containers/app/App'
                    );
            }),
            routes: [

                /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- buttons -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
                {
                    path: '/components/RaisedButton',
                    component: asyncComponent(() => {
                        return import(
                            /* webpackChunkName: "RaisedButtonExamples" */
                            'modules/buttons/RaisedButtonExamples'
                            );
                    })
                }, {
                    path: '/components/FlatButton',
                    component: asyncComponent(() => {
                        return import(
                            /* webpackChunkName: "FlatButtonExamples" */
                            'modules/buttons/FlatButtonExamples'
                            );
                    })
                }, {
                    path: '/components/GhostButton',
                    component: asyncComponent(() => {
                        return import(
                            /* webpackChunkName: "GhostButtonExamples" */
                            'modules/buttons/GhostButtonExamples'
                            );
                    })
                }, {
                    path: '/components/IconButton',
                    component: asyncComponent(() => {
                        return import(
                            /* webpackChunkName: "IconButtonExamples" */
                            'modules/buttons/IconButtonExamples'
                            );
                    })
                }, {
                    path: '/components/IconAnchor',
                    component: asyncComponent(() => {
                        return import(
                            /* webpackChunkName: "IconAnchorExamples" */
                            'modules/buttons/IconAnchorExamples'
                            );
                    })
                },

                /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- fields -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
                {
                    path: '/components/CascaderField',
                    component: asyncComponent(() => {
                        return import(
                            /* webpackChunkName: "CascaderFieldExamples" */
                            'modules/fields/CascaderFieldExamples'
                            );
                    })
                }
            ]
        }]
    }]
}];<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * The easing functions come from the the jQuery UI project.
 * See http://api.jqueryui.com/easings/
 * Copyright jQuery Foundation and other contributors, https://jquery.org/
 * Copyright (c) 2008 George McGinley Smith
 * Copyright (c) 2001 Robert Penner
 *
 * @providesModule AnimationUtils
 * @flow
 */
'use strict';

type EasingFunction = (t: number) => number;

var defaults = {
  easeInQuad: function(t: number): number {
    return t * t;
  },
  easeOutQuad: function(t: number): number {
    return -t * (t - 2);
  },
  easeInOutQuad: function(t: number): number {
    t = t * 2;
    if (t < 1) {
      return 0.5 * t * t;
    }
    return -((t - 1) * (t - 3) - 1) / 2;
  },
  easeInCubic: function(t: number): number {
    return t * t * t;
  },
  easeOutCubic: function(t: number): number {
    t -= 1;
    return t * t * t + 1;
  },
  easeInOutCubic: function(t: number): number {
    t *= 2;
    if (t < 1) {
      return 0.5 * t * t * t;
    }
    t -= 2;
    return (t * t * t + 2) / 2;
  },
  easeInQuart: function(t: number): number {
    return t * t * t * t;
  },
  easeOutQuart: function(t: number): number {
    t -= 1;
    return -(t * t * t * t - 1);
  },
  easeInOutQuart: function(t: number): number {
    t *= 2;
    if (t < 1) {
      return 0.5 * t * t * t * t;
    }
    t -= 2;
    return -(t * t * t * t - 2) / 2;
  },
  easeInQuint: function(t: number): number {
    return t * t * t * t * t;
  },
  easeOutQuint: function(t: number): number {
    t -= 1;
    return t * t * t * t * t + 1;
  },
  easeInOutQuint: function(t: number): number {
    t *= 2;
    if (t < 1) {
      return (t * t * t * t * t) / 2;
    }
    t -= 2;
    return (t * t * t * t * t + 2) / 2;
  },
  easeInSine: function(t: number): number {
    return -Math.cos(t * (Math.PI / 2)) + 1;
  },
  easeOutSine: function(t: number): number {
    return Math.sin(t * (Math.PI / 2));
  },
  easeInOutSine: function(t: number): number {
    return -(Math.cos(Math.PI * t) - 1) / 2;
  },
  easeInExpo: function(t: number): number {
    return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1));
  },
  easeOutExpo: function(t: number): number {
    return (t === 1) ? 1 : (-Math.pow(2, -10 * t) + 1);
  },
  easeInOutExpo: function(t: number): number {
    if (t === 0) {
      return 0;
    }
    if (t === 1) {
      return 1;
    }
    t *= 2;
    if (t < 1) {
      return 0.5 * Math.pow(2, 10 * (t - 1));
    }
    return (-Math.pow(2, -10 * (t - 1)) + 2) / 2;
  },
  easeInCirc: function(t: number): number {
    return -(Math.sqrt(1 - t * t) - 1);
  },
  easeOutCirc: function(t: number): number {
    t -= 1;
    return Math.sqrt(1 - t * t);
  },
  easeInOutCirc: function(t: number): number {
    t *= 2;
    if (t < 1) {
      return -(Math.sqrt(1 - t * t) - 1) / 2;
    }
    t -= 2;
    return (Math.sqrt(1 - t * t) + 1) / 2;
  },
  easeInElastic: function(t: number): number {
    var s = 1.70158;
    var p = 0.3;
    if (t === 0) {
      return 0;
    }
    if (t === 1) {
      return 1;
    }
    var s = p / (2 * Math.PI) * Math.asin(1);
    t -= 1;
    return -(Math.pow(2, 10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p));
  },
  easeOutElastic: function(t: number): number {
    var s = 1.70158;
    var p = 0.3;
    if (t === 0) {
      return 0;
    }
    if (t === 1) {
      return 1;
    }
    var s = p / (2 * Math.PI) * Math.asin(1);
    return Math.pow(2, -10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) + 1;
  },
  easeInOutElastic: function(t: number): number {
    var s = 1.70158;
    var p = 0.3 * 1.5;
    if (t === 0) {
      return 0;
    }
    t *= 2;
    if (t === 2) {
      return 1;
    }
    var s = p / (2 * Math.PI) * Math.asin(1);
    if (t < 1) {
      t -= 1;
      return -(Math.pow(2, 10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p)) / 2;
    }
    t -= 1;
    return Math.pow(2, -10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) / 2 + 1;
  },
  easeInBack: function(t: number): number {
    var s = 1.70158;
    return t * t * ((s + 1) * t - s);
  },
  easeOutBack: function(t: number): number {
    var s = 1.70158;
    t -= 1;
    return (t * t * ((s + 1) * t + s) + 1);
  },
  easeInOutBack: function(t: number): number {
    var s = 1.70158 * 1.525;
    t *= 2;
    if (t < 1) {
      return (t * t * ((s + 1) * t - s)) / 2;
    }
    t -= 2;
    return (t * t * ((s + 1) * t + s) + 2) / 2;
  },
  easeInBounce: function(t: number): number {
    return 1 - this.easeOutBounce(1 - t);
  },
  easeOutBounce: function(t: number): number {
    if (t < (1 / 2.75)) {
      return 7.5625 * t * t;
    } else if (t < (2 / 2.75)) {
      t -= 1.5 / 2.75;
      return 7.5625 * t * t + 0.75;
    } else if (t < (2.5 / 2.75)) {
      t -= 2.25 / 2.75;
      return 7.5625 * t * t + 0.9375;
    } else {
      t -= 2.625 / 2.75;
      return 7.5625 * t * t + 0.984375;
    }
  },
  easeInOutBounce: function(t: number): number {
    if (t < 0.5) {
      return this.easeInBounce(t * 2) / 2;
    }
    return this.easeOutBounce(t * 2 - 1) / 2 + 0.5;
  },
};

var ticksPerSecond = 60;
var lastUsedTag = 0;

module.exports = {
  /**
   * Returns a new unique animation tag.
   */
  allocateTag: function(): number {
    return ++lastUsedTag;
  },

  /**
   * Returns the values of the easing function at discrete ticks (60 per second).
   */
  evaluateEasingFunction: function(duration: number, easing: string | EasingFunction): Array<number> {
    if (typeof easing === 'string') {
      easing = defaults[easing] || defaults.easeOutQuad;
    }

    var tickCount = Math.round(duration * ticksPerSecond / 1000);
    var samples = [];
    for (var i = 0; i <= tickCount; i++) {
      samples.push(easing.call(defaults, i / tickCount));
    }

    return samples;
  },

  Defaults: defaults,
};
<commit_msg>Add Linear easing to AnimationUtils<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * The easing functions come from the the jQuery UI project.
 * See http://api.jqueryui.com/easings/
 * Copyright jQuery Foundation and other contributors, https://jquery.org/
 * Copyright (c) 2008 George McGinley Smith
 * Copyright (c) 2001 Robert Penner
 *
 * @providesModule AnimationUtils
 * @flow
 */
'use strict';

type EasingFunction = (t: number) => number;

var defaults = {
  linear: function(t: number): number {
    return t;
  },
  easeInQuad: function(t: number): number {
    return t * t;
  },
  easeOutQuad: function(t: number): number {
    return -t * (t - 2);
  },
  easeInOutQuad: function(t: number): number {
    t = t * 2;
    if (t < 1) {
      return 0.5 * t * t;
    }
    return -((t - 1) * (t - 3) - 1) / 2;
  },
  easeInCubic: function(t: number): number {
    return t * t * t;
  },
  easeOutCubic: function(t: number): number {
    t -= 1;
    return t * t * t + 1;
  },
  easeInOutCubic: function(t: number): number {
    t *= 2;
    if (t < 1) {
      return 0.5 * t * t * t;
    }
    t -= 2;
    return (t * t * t + 2) / 2;
  },
  easeInQuart: function(t: number): number {
    return t * t * t * t;
  },
  easeOutQuart: function(t: number): number {
    t -= 1;
    return -(t * t * t * t - 1);
  },
  easeInOutQuart: function(t: number): number {
    t *= 2;
    if (t < 1) {
      return 0.5 * t * t * t * t;
    }
    t -= 2;
    return -(t * t * t * t - 2) / 2;
  },
  easeInQuint: function(t: number): number {
    return t * t * t * t * t;
  },
  easeOutQuint: function(t: number): number {
    t -= 1;
    return t * t * t * t * t + 1;
  },
  easeInOutQuint: function(t: number): number {
    t *= 2;
    if (t < 1) {
      return (t * t * t * t * t) / 2;
    }
    t -= 2;
    return (t * t * t * t * t + 2) / 2;
  },
  easeInSine: function(t: number): number {
    return -Math.cos(t * (Math.PI / 2)) + 1;
  },
  easeOutSine: function(t: number): number {
    return Math.sin(t * (Math.PI / 2));
  },
  easeInOutSine: function(t: number): number {
    return -(Math.cos(Math.PI * t) - 1) / 2;
  },
  easeInExpo: function(t: number): number {
    return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1));
  },
  easeOutExpo: function(t: number): number {
    return (t === 1) ? 1 : (-Math.pow(2, -10 * t) + 1);
  },
  easeInOutExpo: function(t: number): number {
    if (t === 0) {
      return 0;
    }
    if (t === 1) {
      return 1;
    }
    t *= 2;
    if (t < 1) {
      return 0.5 * Math.pow(2, 10 * (t - 1));
    }
    return (-Math.pow(2, -10 * (t - 1)) + 2) / 2;
  },
  easeInCirc: function(t: number): number {
    return -(Math.sqrt(1 - t * t) - 1);
  },
  easeOutCirc: function(t: number): number {
    t -= 1;
    return Math.sqrt(1 - t * t);
  },
  easeInOutCirc: function(t: number): number {
    t *= 2;
    if (t < 1) {
      return -(Math.sqrt(1 - t * t) - 1) / 2;
    }
    t -= 2;
    return (Math.sqrt(1 - t * t) + 1) / 2;
  },
  easeInElastic: function(t: number): number {
    var s = 1.70158;
    var p = 0.3;
    if (t === 0) {
      return 0;
    }
    if (t === 1) {
      return 1;
    }
    var s = p / (2 * Math.PI) * Math.asin(1);
    t -= 1;
    return -(Math.pow(2, 10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p));
  },
  easeOutElastic: function(t: number): number {
    var s = 1.70158;
    var p = 0.3;
    if (t === 0) {
      return 0;
    }
    if (t === 1) {
      return 1;
    }
    var s = p / (2 * Math.PI) * Math.asin(1);
    return Math.pow(2, -10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) + 1;
  },
  easeInOutElastic: function(t: number): number {
    var s = 1.70158;
    var p = 0.3 * 1.5;
    if (t === 0) {
      return 0;
    }
    t *= 2;
    if (t === 2) {
      return 1;
    }
    var s = p / (2 * Math.PI) * Math.asin(1);
    if (t < 1) {
      t -= 1;
      return -(Math.pow(2, 10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p)) / 2;
    }
    t -= 1;
    return Math.pow(2, -10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) / 2 + 1;
  },
  easeInBack: function(t: number): number {
    var s = 1.70158;
    return t * t * ((s + 1) * t - s);
  },
  easeOutBack: function(t: number): number {
    var s = 1.70158;
    t -= 1;
    return (t * t * ((s + 1) * t + s) + 1);
  },
  easeInOutBack: function(t: number): number {
    var s = 1.70158 * 1.525;
    t *= 2;
    if (t < 1) {
      return (t * t * ((s + 1) * t - s)) / 2;
    }
    t -= 2;
    return (t * t * ((s + 1) * t + s) + 2) / 2;
  },
  easeInBounce: function(t: number): number {
    return 1 - this.easeOutBounce(1 - t);
  },
  easeOutBounce: function(t: number): number {
    if (t < (1 / 2.75)) {
      return 7.5625 * t * t;
    } else if (t < (2 / 2.75)) {
      t -= 1.5 / 2.75;
      return 7.5625 * t * t + 0.75;
    } else if (t < (2.5 / 2.75)) {
      t -= 2.25 / 2.75;
      return 7.5625 * t * t + 0.9375;
    } else {
      t -= 2.625 / 2.75;
      return 7.5625 * t * t + 0.984375;
    }
  },
  easeInOutBounce: function(t: number): number {
    if (t < 0.5) {
      return this.easeInBounce(t * 2) / 2;
    }
    return this.easeOutBounce(t * 2 - 1) / 2 + 0.5;
  },
};

var ticksPerSecond = 60;
var lastUsedTag = 0;

module.exports = {
  /**
   * Returns a new unique animation tag.
   */
  allocateTag: function(): number {
    return ++lastUsedTag;
  },

  /**
   * Returns the values of the easing function at discrete ticks (60 per second).
   */
  evaluateEasingFunction: function(duration: number, easing: string | EasingFunction): Array<number> {
    if (typeof easing === 'string') {
      easing = defaults[easing] || defaults.easeOutQuad;
    }

    var tickCount = Math.round(duration * ticksPerSecond / 1000);
    var samples = [];
    for (var i = 0; i <= tickCount; i++) {
      samples.push(easing.call(defaults, i / tickCount));
    }

    return samples;
  },

  Defaults: defaults,
};
<|endoftext|>