<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */

'use strict';

const RelayConcreteNode = require('./util/RelayConcreteNode');
const RelayConcreteVariables = require('./store/RelayConcreteVariables');
const RelayConnectionHandler = require('./handlers/connection/RelayConnectionHandler');
const RelayConnectionInterface = require('./handlers/connection/RelayConnectionInterface');
const RelayConnectionResolver = require('./store/RelayConnectionResolver');
const RelayDeclarativeMutationConfig = require('./mutations/RelayDeclarativeMutationConfig');
const RelayDefaultHandleKey = require('./util/RelayDefaultHandleKey');
const RelayDefaultHandlerProvider = require('./handlers/RelayDefaultHandlerProvider');
const RelayDefaultMissingFieldHandlers = require('./handlers/RelayDefaultMissingFieldHandlers');
const RelayError = require('./util/RelayError');
const RelayFeatureFlags = require('./util/RelayFeatureFlags');
const RelayModernEnvironment = require('./store/RelayModernEnvironment');
const RelayModernFragmentOwner = require('./store/RelayModernFragmentOwner');
const RelayModernGraphQLTag = require('./query/RelayModernGraphQLTag');
const RelayModernOperationDescriptor = require('./store/RelayModernOperationDescriptor');
const RelayModernRecord = require('./store/RelayModernRecord');
const RelayModernSelector = require('./store/RelayModernSelector');
const RelayModernStore = require('./store/RelayModernStore');
const RelayNetwork = require('./network/RelayNetwork');
const RelayNetworkLoggerTransaction = require('./network/RelayNetworkLoggerTransaction');
const RelayObservable = require('./network/RelayObservable');
const RelayOperationTracker = require('./store/RelayOperationTracker');
const RelayProfiler = require('./util/RelayProfiler');
const RelayQueryResponseCache = require('./network/RelayQueryResponseCache');
const RelayRecordSource = require('./store/RelayRecordSource');
const RelayStoreUtils = require('./store/RelayStoreUtils');
const ViewerPattern = require('./store/ViewerPattern');

const applyOptimisticMutation = require('./mutations/applyOptimisticMutation');
const commitLocalUpdate = require('./mutations/commitLocalUpdate');
const commitMutation = require('./mutations/commitMutation');
const createFragmentSpecResolver = require('./store/createFragmentSpecResolver');
const createRelayContext = require('./store/createRelayContext');
const createRelayNetworkLogger = require('./network/createRelayNetworkLogger');
const deepFreeze = require('./util/deepFreeze');
const fetchQuery = require('./query/fetchQuery');
const fetchQueryInternal = require('./query/fetchQueryInternal');
const getFragmentIdentifier = require('./util/getFragmentIdentifier');
const getFragmentSpecIdentifier = require('./util/getFragmentSpecIdentifier');
const getRelayHandleKey = require('./util/getRelayHandleKey');
const isPromise = require('./util/isPromise');
const isRelayModernEnvironment = require('./store/isRelayModernEnvironment');
const isScalarAndEqual = require('./util/isScalarAndEqual');
const readInlineData = require('./store/readInlineData');
const recycleNodesInto = require('./util/recycleNodesInto');
const requestSubscription = require('./subscription/requestSubscription');
const stableCopy = require('./util/stableCopy');

const {generateClientID} = require('./store/ClientID');

export type {
  ConnectionMetadata,
} from './handlers/connection/RelayConnectionHandler';
export type {
  EdgeRecord,
  PageInfo,
} from './handlers/connection/RelayConnectionInterface';
export type {
  DeclarativeMutationConfig,
  MutationType,
  RangeBehaviors,
  RangeOperation,
} from './mutations/RelayDeclarativeMutationConfig';
export type {
  OptimisticMutationConfig,
} from './mutations/applyOptimisticMutation';
export type {
  DEPRECATED_MutationConfig,
  MutationConfig,
  MutationParameters,
} from './mutations/commitMutation';
export type {
  RelayNetworkLog,
  LoggerTransactionConfig,
} from './network/RelayNetworkLoggerTransaction';
export type {
  ExecuteFunction,
  FetchFunction,
  GraphQLResponse,
  LogRequestInfoFunction,
  Network as INetwork,
  PayloadData,
  PayloadError,
  SubscribeFunction,
  Uploadable,
  UploadableMap,
} from './network/RelayNetworkTypes';
export type {
  ObservableFromValue,
  Observer,
  Subscribable,
  Subscription,
} from './network/RelayObservable';
export type {
  GraphiQLPrinter,
  NetworkLogger,
} from './network/createRelayNetworkLogger';
export type {GraphQLTaggedNode} from './query/RelayModernGraphQLTag';
export type {
  ConnectionEvent,
  ConnectionID,
  ConnectionReference,
  ConnectionReferenceObject,
  ConnectionResolver,
  ConnectionSnapshot,
} from './store/RelayConnection';
export type {ConnectionState} from './store/RelayConnectionResolver';
export type {TaskScheduler} from './store/RelayModernQueryExecutor';
export type {RecordState} from './store/RelayRecordState';
export type {
  Environment as IEnvironment,
  FragmentMap,
  FragmentPointer,
  FragmentReference,
  FragmentSpecResolver,
  HandleFieldPayload,
  LogEvent,
  LogFunction,
  Logger,
  LoggerProvider,
  MissingFieldHandler,
  ModuleImportPointer,
  NormalizationSelector,
  OperationDescriptor,
  OperationLoader,
  OperationTracker,
  OptimisticResponseConfig,
  OptimisticUpdate,
  OptimisticUpdateFunction,
  PluralReaderSelector,
  Props,
  PublishQueue,
  ReaderSelector,
  ReadOnlyRecordProxy,
  RecordProxy,
  RecordSourceProxy,
  RecordSourceSelectorProxy,
  RelayContext,
  RequestDescriptor,
  SelectorData,
  SelectorStoreUpdater,
  SingularReaderSelector,
  Snapshot,
  StoreUpdater,
} from './store/RelayStoreTypes';
export type {
  GraphQLSubscriptionConfig,
} from './subscription/requestSubscription';
export type {
  NormalizationArgument,
  NormalizationDefer,
  NormalizationConnection,
  NormalizationField,
  NormalizationLinkedField,
  NormalizationLinkedHandle,
  NormalizationLocalArgumentDefinition,
  NormalizationModuleImport,
  NormalizationScalarField,
  NormalizationSelection,
  NormalizationSplitOperation,
  NormalizationStream,
} from './util/NormalizationNode';
export type {NormalizationOperation} from './util/NormalizationNode';
export type {
  ReaderArgument,
  ReaderArgumentDefinition,
  ReaderConnection,
  ReaderField,
  ReaderFragment,
  ReaderInlineDataFragment,
  ReaderInlineDataFragmentSpread,
  ReaderLinkedField,
  ReaderModuleImport,
  ReaderPaginationMetadata,
  ReaderRefetchableFragment,
  ReaderRefetchMetadata,
  ReaderScalarField,
  ReaderSelection,
} from './util/ReaderNode';
export type {
  ConcreteRequest,
  GeneratedNode,
  RequestParameters,
} from './util/RelayConcreteNode';
export type {
  CacheConfig,
  DataID,
  Disposable,
  OperationType,
  Variables,
} from './util/RelayRuntimeTypes';

// As early as possible, check for the existence of the JavaScript globals which
// Relay Runtime relies upon, and produce a clear message if they do not exist.
if (__DEV__) {
  if (
    typeof Map !== 'function' ||
    typeof Set !== 'function' ||
    typeof Promise !== 'function' ||
    typeof Object.assign !== 'function'
  ) {
    throw new Error(
      'relay-runtime requires Map, Set, Promise, and Object.assign to exist. ' +
        'Use a polyfill to provide these for older browsers.',
    );
  }
}

/**
 * The public interface to Relay Runtime.
 */
module.exports = {
  // Core API
  Environment: RelayModernEnvironment,
  Network: RelayNetwork,
  Observable: RelayObservable,
  QueryResponseCache: RelayQueryResponseCache,
  RecordSource: RelayRecordSource,
  Record: RelayModernRecord,
  Store: RelayModernStore,

  areEqualSelectors: RelayModernSelector.areEqualSelectors,
  createFragmentSpecResolver: createFragmentSpecResolver,
  createNormalizationSelector: RelayModernSelector.createNormalizationSelector,
  createOperationDescriptor:
    RelayModernOperationDescriptor.createOperationDescriptor,
  createReaderSelector: RelayModernSelector.createReaderSelector,
  createRequestDescriptor:
    RelayModernOperationDescriptor.createRequestDescriptor,
  getDataIDsFromFragment: RelayModernSelector.getDataIDsFromFragment,
  getDataIDsFromObject: RelayModernSelector.getDataIDsFromObject,
  getFragment: RelayModernGraphQLTag.getFragment,
  getFragmentOwner: RelayModernFragmentOwner.getFragmentOwner,
  getFragmentOwners: RelayModernFragmentOwner.getFragmentOwners,
  getInlineDataFragment: RelayModernGraphQLTag.getInlineDataFragment,
  getModuleComponentKey: RelayStoreUtils.getModuleComponentKey,
  getModuleOperationKey: RelayStoreUtils.getModuleOperationKey,
  getPaginationFragment: RelayModernGraphQLTag.getPaginationFragment,
  getPluralSelector: RelayModernSelector.getPluralSelector,
  getRefetchableFragment: RelayModernGraphQLTag.getRefetchableFragment,
  getRequest: RelayModernGraphQLTag.getRequest,
  getSelector: RelayModernSelector.getSelector,
  getSelectorsFromObject: RelayModernSelector.getSelectorsFromObject,
  getSingularSelector: RelayModernSelector.getSingularSelector,
  getStorageKey: RelayStoreUtils.getStorageKey,
  getVariablesFromFragment: RelayModernSelector.getVariablesFromFragment,
  getVariablesFromObject: RelayModernSelector.getVariablesFromObject,
  getVariablesFromPluralFragment:
    RelayModernSelector.getVariablesFromPluralFragment,
  getVariablesFromSingularFragment:
    RelayModernSelector.getVariablesFromSingularFragment,
  graphql: RelayModernGraphQLTag.graphql,
  readInlineData,

  // Declarative mutation API
  MutationTypes: RelayDeclarativeMutationConfig.MutationTypes,
  RangeOperations: RelayDeclarativeMutationConfig.RangeOperations,

  // Extensions
  DefaultHandlerProvider: RelayDefaultHandlerProvider,
  DefaultMissingFieldHandlers: RelayDefaultMissingFieldHandlers,
  ConnectionHandler: RelayConnectionHandler,
  ConnectionResolver_UNSTABLE: RelayConnectionResolver,
  VIEWER_ID: ViewerPattern.VIEWER_ID,
  VIEWER_TYPE: ViewerPattern.VIEWER_TYPE,

  // Helpers (can be implemented via the above API)
  applyOptimisticMutation,
  commitLocalUpdate,
  commitMutation,
  fetchQuery,
  isRelayModernEnvironment,
  requestSubscription,

  // Configuration interface for legacy or special uses
  ConnectionInterface: RelayConnectionInterface,

  // Utilities
  RelayProfiler: RelayProfiler,

  // INTERNAL-ONLY: These exports might be removed at any point.
  RelayConcreteNode: RelayConcreteNode,
  RelayError: RelayError,
  RelayFeatureFlags: RelayFeatureFlags,
  RelayNetworkLoggerTransaction: RelayNetworkLoggerTransaction,
  DEFAULT_HANDLE_KEY: RelayDefaultHandleKey.DEFAULT_HANDLE_KEY,
  FRAGMENTS_KEY: RelayStoreUtils.FRAGMENTS_KEY,
  FRAGMENT_OWNER_KEY: RelayStoreUtils.FRAGMENT_OWNER_KEY,
  ID_KEY: RelayStoreUtils.ID_KEY,
  REF_KEY: RelayStoreUtils.REF_KEY,
  REFS_KEY: RelayStoreUtils.REFS_KEY,
  ROOT_ID: RelayStoreUtils.ROOT_ID,
  ROOT_TYPE: RelayStoreUtils.ROOT_TYPE,
  TYPENAME_KEY: RelayStoreUtils.TYPENAME_KEY,

  createRelayNetworkLogger: createRelayNetworkLogger,
  deepFreeze: deepFreeze,
  generateClientID: generateClientID,
  getRelayHandleKey: getRelayHandleKey,
  isPromise: isPromise,
  isScalarAndEqual: isScalarAndEqual,
  recycleNodesInto: recycleNodesInto,
  stableCopy: stableCopy,
  getFragmentIdentifier: getFragmentIdentifier,
  getFragmentSpecIdentifier: getFragmentSpecIdentifier,
  __internal: {
    OperationTracker: RelayOperationTracker,
    createRelayContext: createRelayContext,
    getModernOperationVariables: RelayConcreteVariables.getOperationVariables,
    fetchQuery: fetchQueryInternal.fetchQuery,
    fetchQueryDeduped: fetchQueryInternal.fetchQueryDeduped,
    getPromiseForRequestInFlight:
      fetchQueryInternal.getPromiseForRequestInFlight,
    getObservableForRequestInFlight:
      fetchQueryInternal.getObservableForRequestInFlight,
    hasRequestInFlight: fetchQueryInternal.hasRequestInFlight,
  },
};
<commit_msg>Improve debuggability<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */

'use strict';

const RelayConcreteNode = require('./util/RelayConcreteNode');
const RelayConcreteVariables = require('./store/RelayConcreteVariables');
const RelayConnectionHandler = require('./handlers/connection/RelayConnectionHandler');
const RelayConnectionInterface = require('./handlers/connection/RelayConnectionInterface');
const RelayConnectionResolver = require('./store/RelayConnectionResolver');
const RelayDeclarativeMutationConfig = require('./mutations/RelayDeclarativeMutationConfig');
const RelayDefaultHandleKey = require('./util/RelayDefaultHandleKey');
const RelayDefaultHandlerProvider = require('./handlers/RelayDefaultHandlerProvider');
const RelayDefaultMissingFieldHandlers = require('./handlers/RelayDefaultMissingFieldHandlers');
const RelayError = require('./util/RelayError');
const RelayFeatureFlags = require('./util/RelayFeatureFlags');
const RelayModernEnvironment = require('./store/RelayModernEnvironment');
const RelayModernFragmentOwner = require('./store/RelayModernFragmentOwner');
const RelayModernGraphQLTag = require('./query/RelayModernGraphQLTag');
const RelayModernOperationDescriptor = require('./store/RelayModernOperationDescriptor');
const RelayModernRecord = require('./store/RelayModernRecord');
const RelayModernSelector = require('./store/RelayModernSelector');
const RelayModernStore = require('./store/RelayModernStore');
const RelayNetwork = require('./network/RelayNetwork');
const RelayNetworkLoggerTransaction = require('./network/RelayNetworkLoggerTransaction');
const RelayObservable = require('./network/RelayObservable');
const RelayOperationTracker = require('./store/RelayOperationTracker');
const RelayProfiler = require('./util/RelayProfiler');
const RelayQueryResponseCache = require('./network/RelayQueryResponseCache');
const RelayRecordSource = require('./store/RelayRecordSource');
const RelayStoreUtils = require('./store/RelayStoreUtils');
const ViewerPattern = require('./store/ViewerPattern');

const applyOptimisticMutation = require('./mutations/applyOptimisticMutation');
const commitLocalUpdate = require('./mutations/commitLocalUpdate');
const commitMutation = require('./mutations/commitMutation');
const createFragmentSpecResolver = require('./store/createFragmentSpecResolver');
const createRelayContext = require('./store/createRelayContext');
const createRelayNetworkLogger = require('./network/createRelayNetworkLogger');
const deepFreeze = require('./util/deepFreeze');
const fetchQuery = require('./query/fetchQuery');
const fetchQueryInternal = require('./query/fetchQueryInternal');
const getFragmentIdentifier = require('./util/getFragmentIdentifier');
const getFragmentSpecIdentifier = require('./util/getFragmentSpecIdentifier');
const getRelayHandleKey = require('./util/getRelayHandleKey');
const isPromise = require('./util/isPromise');
const isRelayModernEnvironment = require('./store/isRelayModernEnvironment');
const isScalarAndEqual = require('./util/isScalarAndEqual');
const readInlineData = require('./store/readInlineData');
const recycleNodesInto = require('./util/recycleNodesInto');
const requestSubscription = require('./subscription/requestSubscription');
const stableCopy = require('./util/stableCopy');

const {generateClientID} = require('./store/ClientID');

export type {
  ConnectionMetadata,
} from './handlers/connection/RelayConnectionHandler';
export type {
  EdgeRecord,
  PageInfo,
} from './handlers/connection/RelayConnectionInterface';
export type {
  DeclarativeMutationConfig,
  MutationType,
  RangeBehaviors,
  RangeOperation,
} from './mutations/RelayDeclarativeMutationConfig';
export type {
  OptimisticMutationConfig,
} from './mutations/applyOptimisticMutation';
export type {
  DEPRECATED_MutationConfig,
  MutationConfig,
  MutationParameters,
} from './mutations/commitMutation';
export type {
  RelayNetworkLog,
  LoggerTransactionConfig,
} from './network/RelayNetworkLoggerTransaction';
export type {
  ExecuteFunction,
  FetchFunction,
  GraphQLResponse,
  LogRequestInfoFunction,
  Network as INetwork,
  PayloadData,
  PayloadError,
  SubscribeFunction,
  Uploadable,
  UploadableMap,
} from './network/RelayNetworkTypes';
export type {
  ObservableFromValue,
  Observer,
  Subscribable,
  Subscription,
} from './network/RelayObservable';
export type {
  GraphiQLPrinter,
  NetworkLogger,
} from './network/createRelayNetworkLogger';
export type {GraphQLTaggedNode} from './query/RelayModernGraphQLTag';
export type {
  ConnectionEvent,
  ConnectionID,
  ConnectionReference,
  ConnectionReferenceObject,
  ConnectionResolver,
  ConnectionSnapshot,
} from './store/RelayConnection';
export type {ConnectionState} from './store/RelayConnectionResolver';
export type {TaskScheduler} from './store/RelayModernQueryExecutor';
export type {RecordState} from './store/RelayRecordState';
export type {
  Environment as IEnvironment,
  FragmentMap,
  FragmentPointer,
  FragmentReference,
  FragmentSpecResolver,
  HandleFieldPayload,
  LogEvent,
  LogFunction,
  Logger,
  LoggerProvider,
  MissingFieldHandler,
  ModuleImportPointer,
  NormalizationSelector,
  OperationDescriptor,
  OperationLoader,
  OperationTracker,
  OptimisticResponseConfig,
  OptimisticUpdate,
  OptimisticUpdateFunction,
  PluralReaderSelector,
  Props,
  PublishQueue,
  ReaderSelector,
  ReadOnlyRecordProxy,
  RecordProxy,
  RecordSourceProxy,
  RecordSourceSelectorProxy,
  RelayContext,
  RequestDescriptor,
  SelectorData,
  SelectorStoreUpdater,
  SingularReaderSelector,
  Snapshot,
  StoreUpdater,
} from './store/RelayStoreTypes';
export type {
  GraphQLSubscriptionConfig,
} from './subscription/requestSubscription';
export type {
  NormalizationArgument,
  NormalizationDefer,
  NormalizationConnection,
  NormalizationField,
  NormalizationLinkedField,
  NormalizationLinkedHandle,
  NormalizationLocalArgumentDefinition,
  NormalizationModuleImport,
  NormalizationScalarField,
  NormalizationSelection,
  NormalizationSplitOperation,
  NormalizationStream,
} from './util/NormalizationNode';
export type {NormalizationOperation} from './util/NormalizationNode';
export type {
  ReaderArgument,
  ReaderArgumentDefinition,
  ReaderConnection,
  ReaderField,
  ReaderFragment,
  ReaderInlineDataFragment,
  ReaderInlineDataFragmentSpread,
  ReaderLinkedField,
  ReaderModuleImport,
  ReaderPaginationMetadata,
  ReaderRefetchableFragment,
  ReaderRefetchMetadata,
  ReaderScalarField,
  ReaderSelection,
} from './util/ReaderNode';
export type {
  ConcreteRequest,
  GeneratedNode,
  RequestParameters,
} from './util/RelayConcreteNode';
export type {
  CacheConfig,
  DataID,
  Disposable,
  OperationType,
  Variables,
} from './util/RelayRuntimeTypes';

// As early as possible, check for the existence of the JavaScript globals which
// Relay Runtime relies upon, and produce a clear message if they do not exist.
if (__DEV__) {
  const mapStr = typeof Map !== 'function' ? 'Map' : null;
  const setStr = typeof Set !== 'function' ? 'Set' : null;
  const promiseStr = typeof Promise !== 'function' ? 'Promise' : null;
  const objStr = typeof Object.assign !== 'function' ? 'Object.assign' : null;
  if (mapStr || setStr || promiseStr || objStr) {
    throw new Error(
      `relay-runtime requires ${[mapStr, setStr, promiseStr, objStr]
        .filter(Boolean)
        .join(', and ')} to exist. ` +
        'Use a polyfill to provide these for older browsers.',
    );
  }
}

/**
 * The public interface to Relay Runtime.
 */
module.exports = {
  // Core API
  Environment: RelayModernEnvironment,
  Network: RelayNetwork,
  Observable: RelayObservable,
  QueryResponseCache: RelayQueryResponseCache,
  RecordSource: RelayRecordSource,
  Record: RelayModernRecord,
  Store: RelayModernStore,

  areEqualSelectors: RelayModernSelector.areEqualSelectors,
  createFragmentSpecResolver: createFragmentSpecResolver,
  createNormalizationSelector: RelayModernSelector.createNormalizationSelector,
  createOperationDescriptor:
    RelayModernOperationDescriptor.createOperationDescriptor,
  createReaderSelector: RelayModernSelector.createReaderSelector,
  createRequestDescriptor:
    RelayModernOperationDescriptor.createRequestDescriptor,
  getDataIDsFromFragment: RelayModernSelector.getDataIDsFromFragment,
  getDataIDsFromObject: RelayModernSelector.getDataIDsFromObject,
  getFragment: RelayModernGraphQLTag.getFragment,
  getFragmentOwner: RelayModernFragmentOwner.getFragmentOwner,
  getFragmentOwners: RelayModernFragmentOwner.getFragmentOwners,
  getInlineDataFragment: RelayModernGraphQLTag.getInlineDataFragment,
  getModuleComponentKey: RelayStoreUtils.getModuleComponentKey,
  getModuleOperationKey: RelayStoreUtils.getModuleOperationKey,
  getPaginationFragment: RelayModernGraphQLTag.getPaginationFragment,
  getPluralSelector: RelayModernSelector.getPluralSelector,
  getRefetchableFragment: RelayModernGraphQLTag.getRefetchableFragment,
  getRequest: RelayModernGraphQLTag.getRequest,
  getSelector: RelayModernSelector.getSelector,
  getSelectorsFromObject: RelayModernSelector.getSelectorsFromObject,
  getSingularSelector: RelayModernSelector.getSingularSelector,
  getStorageKey: RelayStoreUtils.getStorageKey,
  getVariablesFromFragment: RelayModernSelector.getVariablesFromFragment,
  getVariablesFromObject: RelayModernSelector.getVariablesFromObject,
  getVariablesFromPluralFragment:
    RelayModernSelector.getVariablesFromPluralFragment,
  getVariablesFromSingularFragment:
    RelayModernSelector.getVariablesFromSingularFragment,
  graphql: RelayModernGraphQLTag.graphql,
  readInlineData,

  // Declarative mutation API
  MutationTypes: RelayDeclarativeMutationConfig.MutationTypes,
  RangeOperations: RelayDeclarativeMutationConfig.RangeOperations,

  // Extensions
  DefaultHandlerProvider: RelayDefaultHandlerProvider,
  DefaultMissingFieldHandlers: RelayDefaultMissingFieldHandlers,
  ConnectionHandler: RelayConnectionHandler,
  ConnectionResolver_UNSTABLE: RelayConnectionResolver,
  VIEWER_ID: ViewerPattern.VIEWER_ID,
  VIEWER_TYPE: ViewerPattern.VIEWER_TYPE,

  // Helpers (can be implemented via the above API)
  applyOptimisticMutation,
  commitLocalUpdate,
  commitMutation,
  fetchQuery,
  isRelayModernEnvironment,
  requestSubscription,

  // Configuration interface for legacy or special uses
  ConnectionInterface: RelayConnectionInterface,

  // Utilities
  RelayProfiler: RelayProfiler,

  // INTERNAL-ONLY: These exports might be removed at any point.
  RelayConcreteNode: RelayConcreteNode,
  RelayError: RelayError,
  RelayFeatureFlags: RelayFeatureFlags,
  RelayNetworkLoggerTransaction: RelayNetworkLoggerTransaction,
  DEFAULT_HANDLE_KEY: RelayDefaultHandleKey.DEFAULT_HANDLE_KEY,
  FRAGMENTS_KEY: RelayStoreUtils.FRAGMENTS_KEY,
  FRAGMENT_OWNER_KEY: RelayStoreUtils.FRAGMENT_OWNER_KEY,
  ID_KEY: RelayStoreUtils.ID_KEY,
  REF_KEY: RelayStoreUtils.REF_KEY,
  REFS_KEY: RelayStoreUtils.REFS_KEY,
  ROOT_ID: RelayStoreUtils.ROOT_ID,
  ROOT_TYPE: RelayStoreUtils.ROOT_TYPE,
  TYPENAME_KEY: RelayStoreUtils.TYPENAME_KEY,

  createRelayNetworkLogger: createRelayNetworkLogger,
  deepFreeze: deepFreeze,
  generateClientID: generateClientID,
  getRelayHandleKey: getRelayHandleKey,
  isPromise: isPromise,
  isScalarAndEqual: isScalarAndEqual,
  recycleNodesInto: recycleNodesInto,
  stableCopy: stableCopy,
  getFragmentIdentifier: getFragmentIdentifier,
  getFragmentSpecIdentifier: getFragmentSpecIdentifier,
  __internal: {
    OperationTracker: RelayOperationTracker,
    createRelayContext: createRelayContext,
    getModernOperationVariables: RelayConcreteVariables.getOperationVariables,
    fetchQuery: fetchQueryInternal.fetchQuery,
    fetchQueryDeduped: fetchQueryInternal.fetchQueryDeduped,
    getPromiseForRequestInFlight:
      fetchQueryInternal.getPromiseForRequestInFlight,
    getObservableForRequestInFlight:
      fetchQueryInternal.getObservableForRequestInFlight,
    hasRequestInFlight: fetchQueryInternal.hasRequestInFlight,
  },
};
<|endoftext|>


<commit_before>chrome.extension.onMessage.addListener(
    function(request, sender, sendResponse) {
      getOtherBookmarksChildren(function(other, otherID){
          if (other == null) {
              console.error("'Other Bookmarks' not found.");
              return;
          }
          var folders = retrieveFolders(other);
          var alreadyBookmarked = false;
          var bookmark = null;
          var bookmarkFolderID = null;
          chrome.bookmarks.search(sender.tab.url, function(results){
              results.forEach(function(currentBookmark){
                 if (currentBookmark.url == sender.tab.url){
                   alreadyBookmarked = true;
                   bookmarkFolderID = currentBookmark.parentId;
                   bookmark = currentBookmark;
                   return false;
                 }
              });
              if (alreadyBookmarked){
                     populateInterface(bookmarkFolderID, folders, bookmark);
                  return;
              }
              var folder = determineBestFolder(sender.tab, request, folders, function(folderName){
                  if (folderName == "Uncategorized"){
                      // Find the uncategorized folder and create bookmark there
                      getFolder(folderName, other, otherID, true, function(uncategorized){
                          chrome.bookmarks.create({'parentId': uncategorized.id,
                                'title': sender.tab.title || "No title",
                                'url': sender.tab.url}, function(bookmark) {
                             populateInterface(uncategorized.id, folders, bookmark);
                          });
                      });
                  }else{
                      getFolder(folderName, other, otherID, false, function(folder) {
                          chrome.bookmarks.create({'parentId': folder.id,
                             'title': sender.tab.title || "No title",
                             'url': sender.tab.url}, function(bookmark) {
                             populateInterface(folder.id, folders, bookmark);
                          });
                      });
                  }
              });
          });
     });
});

// Return everything in the "Other bookmarks" folder
function getOtherBookmarksChildren(callback) {
    chrome.bookmarks.getTree(function(results){
        var title = "Other Bookmarks";
        var topLevel = results[0].children;
        for (var nodeKey in topLevel){
           var node = topLevel[nodeKey];
           if (node.title == title)
              return callback(node.children, node.id);
        }
        return callback(null, null);
     });
}

// Given a list of bookmark nodes, return those that are folders (not actual bookmarks)
function retrieveFolders(folder) {
    var folders = [];
    for (var nodeKey in folder){
      var node = folder[nodeKey];
      if (!node.hasOwnProperty("url"))
          folders.push(node);
    }
    return folders;
}

function getFolder(name, folders, otherID, create, callback){
    for (var folderKey in folders){
        var folder = folders[folderKey];
        if (folder.title == name)
            return callback(folder);
    }
    if (create){
        // Create uncategorized folder
        chrome.bookmarks.create({'parentId': otherID, 'title': name},
            function(folder) {
                callback(folder);
            }
        );
    }else{
        callback(null);
    }
}

function populateInterface(folderID, otherFolders, bookmark){
    var views = chrome.extension.getViews({type:"popup"});
    var pop_doc = views[0].document;
    var title_input = pop_doc.getElementById("bookmark_title");
    var folder_input =  pop_doc.getElementById("bookmark_folders");
    title_input.value = bookmark.title;

    title_input.addEventListener("keyup", function(event) {
        chrome.bookmarks.update(bookmark.id, {title: title_input.value}, function(){});
    });

    chrome.bookmarks.getRecent(2, function(bookmarks){
        if (bookmarks.length > 0)
            if ((bookmarks[0].url === bookmark.url) && (bookmarks.length > 1))
                id = bookmarks[1].parentId
            else
                id = bookmarks[0].parentId
        else
            id = null
        var cache_option;
        otherFolders.forEach(function(currentFolder){
            var newOption = new Option(currentFolder.title, currentFolder.id);
            newOption.selected = (folderID == currentFolder.id);
            if (currentFolder.id == id) {
                newOption.className = "last";
                cache_option = newOption;
            }
            folder_input.add(newOption, null);
        });
        pop_doc.getElementById("remove").addEventListener("click", function(){
            chrome.bookmarks.remove(bookmark.id);
            window.close();
        }, false);
        // Setup move to last used folder option
        var last_folder = pop_doc.getElementById("last_folder");
        last_folder.addEventListener("click", function(){
            if (cache_option != null){
               chrome.bookmarks.move(bookmark.id, {parentId:id},function(){
                    cache_option.selected = true;
               });
            }else{
               //TODO notify user of error somehow
            }
        });
        // Setup change handler
        folder_input.addEventListener("change", function(event) {
           chrome.bookmarks.move(bookmark.id, {parentId: folder_input.selectedOptions[0].value}, function(){});
        });
    });

}

function determineBestFolder(page, meta, folders, callback){

    // First check to see if the title of the page contains
    // the name of the folder
    var folder = null;
    // Odd results if folder name is all spaces
    folders = folders.filter(function(folder){
        if (folder.title.trim().length) return true;
        return false;
    });

    folders.forEach(function(currentFolder){
        var regex = new RegExp("\\b"+currentFolder.title+"\\b","i");
        if (regex.test(page.title)){
           folder = currentFolder;
           return false;
        }
    });

    if (folder) {
        callback(folder.title);
        return;
    }

    // If first guess failed, try the bayes classifier
    chrome.storage.local.get({
        "feature_count":{},
        "klass_count":{}
    }, function(storage){
        var c = new NaiveBayesClassifier(storage);
        callback(c.classify(page.title));
    });
}

// Given a top level folder, return all descendant
// children that are not folders
function getAllPagesInFolder(folder){
    var pages = []
    for (var childIndex in folder.children){
        var child = folder.children[childIndex];
        if (child.hasOwnProperty("url"))
          pages.push(child);
        else
          pages.concat(getAllPagesInFolder(child));
    }
    return pages;
}

// Given a bookmark, navigate up the tree to find its highest
// parent folder immediately below "Other Bookmarks"
function findKlass(node, callback, descendant){
     if (!node.hasOwnProperty("parentId")){
           callback(false);
           return;
     }
     if (!node.hasOwnProperty("url") && node.parentId=="0" && node.title == "Other Bookmarks"){
          callback(node.title !== "Uncategorized", descendant);
          return;
     }
     chrome.bookmarks.get(node.parentId, function(results){
          findKlass(results[0], callback, node.title);
     });
};

// Events
//
// On install, scan all bookmarks and train the classifier
chrome.runtime.onInstalled.addListener(function(details) {
    if (details.reason == "install"){
        var c = new NaiveBayesClassifier();
        getOtherBookmarksChildren(function(nodes, otherID){
           var topLevelFolders = retrieveFolders(nodes);
           topLevelFolders = topLevelFolders.filter(function(bookmark){
               if (bookmark.title.trim().length) return true;
               return false;
           });
           for (var folderIndex in topLevelFolders){
               var klass = topLevelFolders[folderIndex].title;
               if (klass == "Uncategorized") continue;
               var pages = getAllPagesInFolder(topLevelFolders[folderIndex]);
               for (var pageIndex in pages){
                   c.train(pages[pageIndex].title, klass);
               }
           }
           chrome.storage.local.set(c.to_object(), function(){
           });
        });
    }
});

// On bookmark created, determine its root parent
// if it is "Other Bookmarks", train on the folder
chrome.bookmarks.onCreated.addListener(function(id, bookmark) {
    // determine if a bookmark was created or just a folder
    if (bookmark.hasOwnProperty("url")) {
          findKlass(bookmark, function(train, klass){
                 if (train && klass.trim().length()){
                       chrome.storage.local.get({
                           "feature_count":{},
                           "klass_count":{}
                       }, function(storage){
                          var c = new NaiveBayesClassifier(storage);
                          c.train(bookmark.title, klass);
                          chrome.storage.local.set(c.to_object(), function(){});
                       });
                 }
          });
    }
});

// Bookmarks are created and moved often, need to make it possible to
// untrain and train on the new folder
chrome.bookmarks.onMoved.addListener(function(id, moveInfo) {
    // Get name of old folder
    // If first guess failed, try the bayes classifier
    // TODO implement untrain in the classifier
    chrome.storage.local.get({
        "feature_count":{},
        "klass_count":{}
    }, function(storage){
        var c = new NaiveBayesClassifier(storage);
        chrome.bookmarks.get(id, function(bookmark) {
             // Is this a bookmark or a folder that was moved
             if bookmark.hasOwnProperty("url"){
                  // untrain
                  findKlass(moveInfo.oldParentId, function(train, oldKlass){
                         if (train){
                               // Don't do anything for empty folder names
                               if (!oldKlass.trim().length) return;
                               c.untrain(bookmark.title, klass);
                         };
                         // train, this has to come last so we only need to save once
                         findKlass(moveInfo.newParentId, function(train, newKlass){
                                if (train){
                                      // Don't do anything for empty folder names
                                      if (!newKlass.trim().length) return;
                                      c.train(bookmark.title, newKlass);
                                }
                                chrome.storage.local.set(c.to_object(), function(){});
                         });
                  });
             }else{
                 //TODO handle a whole folder that has been moved
             }
         });
    });
});

//TODO
//What about importing
<commit_msg>Commenting.<commit_after>chrome.extension.onMessage.addListener(
    function(request, sender, sendResponse) {
      getOtherBookmarksChildren(function(other, otherID){
          if (other == null) {
              console.error("'Other Bookmarks' not found.");
              return;
          }
          var folders = retrieveFolders(other);
          var alreadyBookmarked = false;
          var bookmark = null;
          var bookmarkFolderID = null;
          chrome.bookmarks.search(sender.tab.url, function(results){
              results.forEach(function(currentBookmark){
                 if (currentBookmark.url == sender.tab.url){
                   alreadyBookmarked = true;
                   bookmarkFolderID = currentBookmark.parentId;
                   bookmark = currentBookmark;
                   return false;
                 }
              });
              if (alreadyBookmarked){
                     populateInterface(bookmarkFolderID, folders, bookmark);
                  return;
              }
              var folder = determineBestFolder(sender.tab, request, folders, function(folderName){
                  if (folderName == "Uncategorized"){
                      // Find the uncategorized folder and create bookmark there
                      getFolder(folderName, other, otherID, true, function(uncategorized){
                          chrome.bookmarks.create({'parentId': uncategorized.id,
                                'title': sender.tab.title || "No title",
                                'url': sender.tab.url}, function(bookmark) {
                             populateInterface(uncategorized.id, folders, bookmark);
                          });
                      });
                  }else{
                      getFolder(folderName, other, otherID, false, function(folder) {
                          chrome.bookmarks.create({'parentId': folder.id,
                             'title': sender.tab.title || "No title",
                             'url': sender.tab.url}, function(bookmark) {
                             populateInterface(folder.id, folders, bookmark);
                          });
                      });
                  }
              });
          });
     });
});

// Return everything in the "Other bookmarks" folder
function getOtherBookmarksChildren(callback) {
    chrome.bookmarks.getTree(function(results){
        var title = "Other Bookmarks";
        var topLevel = results[0].children;
        for (var nodeKey in topLevel){
           var node = topLevel[nodeKey];
           if (node.title == title)
              return callback(node.children, node.id);
        }
        return callback(null, null);
     });
}

// Given a list of bookmark nodes, return those that are folders (not actual bookmarks)
function retrieveFolders(folder) {
    var folders = [];
    for (var nodeKey in folder){
      var node = folder[nodeKey];
      if (!node.hasOwnProperty("url"))
          folders.push(node);
    }
    return folders;
}

// Given a list of folder objects, returns one with a the given name
// If not found, and create is true, creates the folder under folder
// otherID
function getFolder(name, folders, otherID, create, callback){
    for (var folderKey in folders){
        var folder = folders[folderKey];
        if (folder.title == name)
            return callback(folder);
    }
    if (create){
        // Create uncategorized folder
        chrome.bookmarks.create({'parentId': otherID, 'title': name},
            function(folder) {
                callback(folder);
            }
        );
    }else{
        callback(null);
    }
}

function populateInterface(folderID, otherFolders, bookmark){
    var views = chrome.extension.getViews({type:"popup"});
    var pop_doc = views[0].document;
    var title_input = pop_doc.getElementById("bookmark_title");
    var folder_input =  pop_doc.getElementById("bookmark_folders");
    title_input.value = bookmark.title;

    title_input.addEventListener("keyup", function(event) {
        chrome.bookmarks.update(bookmark.id, {title: title_input.value}, function(){});
    });

    chrome.bookmarks.getRecent(2, function(bookmarks){
        if (bookmarks.length > 0)
            if ((bookmarks[0].url === bookmark.url) && (bookmarks.length > 1))
                id = bookmarks[1].parentId
            else
                id = bookmarks[0].parentId
        else
            id = null
        var cache_option;
        otherFolders.forEach(function(currentFolder){
            var newOption = new Option(currentFolder.title, currentFolder.id);
            newOption.selected = (folderID == currentFolder.id);
            if (currentFolder.id == id) {
                newOption.className = "last";
                cache_option = newOption;
            }
            folder_input.add(newOption, null);
        });
        pop_doc.getElementById("remove").addEventListener("click", function(){
            chrome.bookmarks.remove(bookmark.id);
            window.close();
        }, false);
        // Setup move to last used folder option
        var last_folder = pop_doc.getElementById("last_folder");
        last_folder.addEventListener("click", function(){
            if (cache_option != null){
               chrome.bookmarks.move(bookmark.id, {parentId:id},function(){
                    cache_option.selected = true;
               });
            }else{
               //TODO notify user of error somehow
            }
        });
        // Setup change handler
        folder_input.addEventListener("change", function(event) {
           chrome.bookmarks.move(bookmark.id, {parentId: folder_input.selectedOptions[0].value}, function(){});
        });
    });

}

function determineBestFolder(page, meta, folders, callback){

    // First check to see if the title of the page contains
    // the name of the folder
    var folder = null;
    // Odd results if folder name is all spaces
    folders = folders.filter(function(folder){
        if (folder.title.trim().length) return true;
        return false;
    });

    folders.forEach(function(currentFolder){
        var regex = new RegExp("\\b"+currentFolder.title+"\\b","i");
        if (regex.test(page.title)){
           folder = currentFolder;
           return false;
        }
    });

    if (folder) {
        callback(folder.title);
        return;
    }

    // If first guess failed, try the bayes classifier
    chrome.storage.local.get({
        "feature_count":{},
        "klass_count":{}
    }, function(storage){
        var c = new NaiveBayesClassifier(storage);
        callback(c.classify(page.title));
    });
}

// Given a top level folder, return all descendant
// children that are not folders
function getAllPagesInFolder(folder){
    var pages = []
    for (var childIndex in folder.children){
        var child = folder.children[childIndex];
        if (child.hasOwnProperty("url"))
          pages.push(child);
        else
          pages.concat(getAllPagesInFolder(child));
    }
    return pages;
}

// Given a bookmark, navigate up the tree to find its highest
// parent folder immediately below "Other Bookmarks"
function findKlass(node, callback, descendant){
     if (!node.hasOwnProperty("parentId")){
           callback(false);
           return;
     }
     if (!node.hasOwnProperty("url") && node.parentId=="0" && node.title == "Other Bookmarks"){
          callback(node.title !== "Uncategorized", descendant);
          return;
     }
     chrome.bookmarks.get(node.parentId, function(results){
          findKlass(results[0], callback, node.title);
     });
};

// Events
//
// On install, scan all bookmarks and train the classifier
chrome.runtime.onInstalled.addListener(function(details) {
    if (details.reason == "install"){
        var c = new NaiveBayesClassifier();
        getOtherBookmarksChildren(function(nodes, otherID){
           var topLevelFolders = retrieveFolders(nodes);
           topLevelFolders = topLevelFolders.filter(function(bookmark){
               if (bookmark.title.trim().length) return true;
               return false;
           });
           for (var folderIndex in topLevelFolders){
               var klass = topLevelFolders[folderIndex].title;
               if (klass == "Uncategorized") continue;
               var pages = getAllPagesInFolder(topLevelFolders[folderIndex]);
               for (var pageIndex in pages){
                   c.train(pages[pageIndex].title, klass);
               }
           }
           chrome.storage.local.set(c.to_object(), function(){
           });
        });
    }
});

// On bookmark created, determine its root parent
// if it is "Other Bookmarks", train on the folder
chrome.bookmarks.onCreated.addListener(function(id, bookmark) {
    // determine if a bookmark was created or just a folder
    if (bookmark.hasOwnProperty("url")) {
          findKlass(bookmark, function(train, klass){
                 if (train && klass.trim().length()){
                       chrome.storage.local.get({
                           "feature_count":{},
                           "klass_count":{}
                       }, function(storage){
                          var c = new NaiveBayesClassifier(storage);
                          c.train(bookmark.title, klass);
                          chrome.storage.local.set(c.to_object(), function(){});
                       });
                 }
          });
    }
});

// Bookmarks are created and moved often, need to make it possible to
// untrain and train on the new folder
chrome.bookmarks.onMoved.addListener(function(id, moveInfo) {
    // Get name of old folder
    // If first guess failed, try the bayes classifier
    // TODO implement untrain in the classifier
    chrome.storage.local.get({
        "feature_count":{},
        "klass_count":{}
    }, function(storage){
        var c = new NaiveBayesClassifier(storage);
        chrome.bookmarks.get(id, function(bookmark) {
             // Is this a bookmark or a folder that was moved
             if bookmark.hasOwnProperty("url"){
                  // untrain
                  findKlass(moveInfo.oldParentId, function(train, oldKlass){
                         if (train){
                               // Don't do anything for empty folder names
                               if (!oldKlass.trim().length) return;
                               c.untrain(bookmark.title, klass);
                         };
                         // train, this has to come last so we only need to save once
                         findKlass(moveInfo.newParentId, function(train, newKlass){
                                if (train){
                                      // Don't do anything for empty folder names
                                      if (!newKlass.trim().length) return;
                                      c.train(bookmark.title, newKlass);
                                }
                                chrome.storage.local.set(c.to_object(), function(){});
                         });
                  });
             }else{
                 //TODO handle a whole folder that has been moved
             }
         });
    });
});

//TODO
//What about importing

<|endoftext|>


<commit_before>// dlog.js 0.0.1
// https://github.com/ddo/dlog
// (c) 2014 Ddo <http://ddo.me>

(function(){function b(a){a=a?a:{};this.setName(a.name);this.setLevel(a.level);this.setSize(a.size)}this.dlog=b;b.prototype.setName=function(a){return this.name=a?a:"DLOG"};b.prototype.setLevel=function(a){this.level=a?this.level_map[a]?a:"info":"info";this.level_no=this.level_map[this.level];return this.level};b.prototype.setSize=function(a){return this.size=a?a:14};b.prototype.level_map={trace:1,debug:2,info:3,warn:4,error:5,silent:6};b.prototype.color_map={name:"cyan",trace:"black",debug:"green",
info:"blue",warn:"orange",error:"red"};b.prototype.getCSS=function(a){return a?"font-size: "+this.size+"px;color: "+this.color_map[a]:"font-size: "+this.size+"px"};b.prototype.log=function(a,b){"silent"!==a&&this.level_map[a]>=this.level_no&&this.show(a,b)};b.prototype.isAllObj=function(a){for(var b=0;b<a.length;b++)if("object"!==typeof a[b])return!1;return!0};b.prototype.show=function(a,b){console.log("%c [%s] %c %s %c %s:",this.getCSS(),(new Date).toJSON(),this.getCSS("name"),this.name,this.getCSS(a),
a.toUpperCase());Array.isArray(b[0])&&this.isAllObj(b[0])&&console.table(b[0]);console[a].apply(console,b)};b.prototype.trace=function(){this.log("trace",arguments)};b.prototype.debug=function(){this.log("debug",arguments)};b.prototype.info=function(){this.log("info",arguments)};b.prototype.warn=function(){this.log("warn",arguments)};b.prototype.error=function(){this.log("error",arguments)}})();<commit_msg>Change signature<commit_after>// dlog 0.0.1
// http://ddo.github.io/dlog
// (c) 2014 Ddo <http://ddo.me>

(function(){function b(a){a=a?a:{};this.setName(a.name);this.setLevel(a.level);this.setSize(a.size)}this.dlog=b;b.prototype.setName=function(a){return this.name=a?a:"DLOG"};b.prototype.setLevel=function(a){this.level=a?this.level_map[a]?a:"info":"info";this.level_no=this.level_map[this.level];return this.level};b.prototype.setSize=function(a){return this.size=a?a:14};b.prototype.level_map={trace:1,debug:2,info:3,warn:4,error:5,silent:6};b.prototype.color_map={name:"cyan",trace:"black",debug:"green",
info:"blue",warn:"orange",error:"red"};b.prototype.getCSS=function(a){return a?"font-size: "+this.size+"px;color: "+this.color_map[a]:"font-size: "+this.size+"px"};b.prototype.log=function(a,b){"silent"!==a&&this.level_map[a]>=this.level_no&&this.show(a,b)};b.prototype.isAllObj=function(a){for(var b=0;b<a.length;b++)if("object"!==typeof a[b])return!1;return!0};b.prototype.show=function(a,b){console.log("%c [%s] %c %s %c %s:",this.getCSS(),(new Date).toJSON(),this.getCSS("name"),this.name,this.getCSS(a),
a.toUpperCase());Array.isArray(b[0])&&this.isAllObj(b[0])&&console.table(b[0]);console[a].apply(console,b)};b.prototype.trace=function(){this.log("trace",arguments)};b.prototype.debug=function(){this.log("debug",arguments)};b.prototype.info=function(){this.log("info",arguments)};b.prototype.warn=function(){this.log("warn",arguments)};b.prototype.error=function(){this.log("error",arguments)}})();
<|endoftext|>


<commit_before>'use strict';

describe('Service: uint', function () {

  // load the service's module
  beforeEach(module('flowsimUiApp'));

  // instantiate service
  var UInt;
  beforeEach(inject(function (_UInt_) {
    UInt = _UInt_;
  }));

  it('UInt Import', function () {
    expect(!!UInt).toBe(true);
  });

  it('howMany_, maxFrom_', function () {
    var tmp;

    expect(UInt.howManyBits(0)).toBe(1);
    expect(UInt.howManyBits(0x0)).toBe(1);
    expect(UInt.howManyBytes(0)).toBe(1);
    expect(UInt.howManyBytes(0x0)).toBe(1);

    expect(UInt.howManyBits(0)).toBe(1);

    tmp = 1;
    _.each(_.range(31), function(i) {
      expect(UInt.howManyBits(tmp)).toBe(i+1);
      tmp <<= 1;
    });
    expect(UInt.howManyBytes(0)).toBe(1);

    tmp = 1;
    _.each(_.range(31), function(i) {
      expect(UInt.howManyBytes(tmp)).toBe(Math.ceil((i+1)/8));
      tmp <<= 1;
    });

    _.each(_.range(31), function(i) {
      expect(UInt.maxFromBits(i+1)).toBe(Math.pow(2, i+1)-1);
    });

    _.each(_.range(4), function(i) {
      expect(UInt.maxFromBytes(i+1)).toBe(Math.pow(2, (8*(i+1)))-1);
    });
  });

  it('UInt(null, 0x1ffff, 2) should fail', function() {
    expect(function() {
      new UInt.UInt(null, 0x1ffff, 2)
    }).toThrow();
  });

  it('UInt(null, "0x1ffff", 2) should fail', function() {
    expect(function() {
      new UInt.UInt(null, '0x1ffff', 2)
    }).toThrow();
  });

  it('UInt(null, 0x800, 2).toString()', function() {
    var v = new UInt.UInt(null, '0x800', 2);
    expect(v.toString(16)).toBe('0x0800');
  });

  it('UInt(null, "0xx0000", 2)', function() {
    expect(function() {
      new UInt.UInt(null, '0xx0000', 2);
    }).toThrow();
  });

  it('UInt Construction', function() {
    expect(function() {
      new UInt.UInt(null, 'q');
    }).toThrow();
    expect(function() {
      new UInt.UInt(null, '0xx00');
    }).toThrow();
    expect(function() {
      new UInt.UInt(null, 1.2);
    }).toThrow();
    expect(function() {
      new UInt.UInt(null, null, 0);
    }).toThrow();
  });

  it('UInt No-Throw Construction', function() {
    var type_ip  = new UInt.UInt(null, 0x0800, 2);
    var type_arp = new UInt.UInt(null, 0x0806, 2);
    var type     = new UInt.UInt(null, null, 2);

    var inval  = new UInt.UInt(null, 0x0a0101f0, 4);
    var outval = new UInt.UInt(null, 0x0b0101f0, 4);
  });

  it('UInt Match - Ethernet Type', function() {
    var type1 = new UInt.UInt(null, 0x0800, 2);
    var type2 = new UInt.UInt(null, 0x0806, 2);

    var exact1 = new UInt.Match(null,
        new UInt.UInt(null, 0x0800, 2),
        new UInt.UInt(null, 0xffff, 2));

    var exact2 = new UInt.Match.mkExact(type1);

    var wildcard1 = new UInt.Match(null,
        new UInt.UInt(null, 0x0000, 2),
        new UInt.UInt(null, 0x0000, 2));

    var wildcard2 = new UInt.Match.mkWildcard(type1);
    var wildcard3 = new UInt.Match.mkWildcard(2);

    expect(exact1.match(type1)).toBe(true);
    expect(exact2.match(type1)).toBe(true);
    expect(wildcard1.match(type1)).toBe(true);
    expect(wildcard2.match(type1)).toBe(true);
    expect(wildcard3.match(type1)).toBe(true);

    expect(exact1.match(type2)).toBe(false);
    expect(exact2.match(type2)).toBe(false);
    expect(wildcard1.match(type2)).toBe(true);
    expect(wildcard2.match(type2)).toBe(true);
    expect(wildcard3.match(type2)).toBe(true);

  });

  it('UInt Match - Ethernet MAC', function() {
    var empty     = new UInt.UInt(null, null, 6);
    var broadcast = (new UInt.UInt(null, null, 6)).neg();

    var mac1 = new UInt.UInt(null, [0, 1, 2, 3, 4, 5], 6);
    var mac2 = new UInt.UInt(null, [0, 1, 2, 3, 4, 6], 6);

    var exact1_mac1 = new UInt.Match(null,
        new UInt.UInt(null, [0, 1, 2, 3, 4, 5], 6),
        new UInt.UInt(null, [0xff, 0xff, 0xff, 0xff, 0xff, 0xff], 6));
    var exact2_mac1 = new UInt.Match.mkExact(mac1);

    var exact1_mac2 = new UInt.Match(null,
        new UInt.UInt(null, [0, 1, 2, 3, 4, 6], 6),
        new UInt.UInt(null, [0xff, 0xff, 0xff, 0xff, 0xff, 0xff], 6));
    var exact2_mac2 = new UInt.Match.mkExact(mac2);

    var wildcard1_mac1 = new UInt.Match(null,
        new UInt.UInt(null, null, 6),
        new UInt.UInt(null, null, 6));
    var wildcard2_mac1 = new UInt.Match.mkWildcard(mac1);
    var wildcard3_mac1 = new UInt.Match.mkWildcard(6);

    var wildcard1_mac2 = new UInt.Match(null,
        new UInt.UInt(null, null, 6),
        new UInt.UInt(null, null, 6));
    var wildcard2_mac2 = new UInt.Match.mkWildcard(mac2);
    var wildcard3_mac2 = new UInt.Match.mkWildcard(6);

    expect(exact1_mac1.match(mac1)).toBe(true);
    expect(exact2_mac1.match(mac1)).toBe(true);
    expect(wildcard1_mac1.match(mac1)).toBe(true);
    expect(wildcard2_mac1.match(mac1)).toBe(true);
    expect(wildcard3_mac1.match(mac1)).toBe(true);
    expect(exact1_mac1.match(mac2)).toBe(false);
    expect(exact2_mac1.match(mac2)).toBe(false);
    expect(wildcard1_mac1.match(mac2)).toBe(true);
    expect(wildcard2_mac1.match(mac2)).toBe(true);
    expect(wildcard3_mac1.match(mac2)).toBe(true);

    expect(exact1_mac2.match(mac1)).toBe(false);
    expect(exact2_mac2.match(mac1)).toBe(false);
    expect(wildcard1_mac2.match(mac1)).toBe(true);
    expect(wildcard2_mac2.match(mac1)).toBe(true);
    expect(wildcard3_mac2.match(mac1)).toBe(true);
    expect(exact1_mac2.match(mac2)).toBe(true);
    expect(exact2_mac2.match(mac2)).toBe(true);
    expect(wildcard1_mac2.match(mac2)).toBe(true);
    expect(wildcard2_mac2.match(mac2)).toBe(true);
    expect(wildcard3_mac2.match(mac2)).toBe(true);
  });

  it('UInt Match', function() {
    var left = new UInt.UInt(null, 0xffffffff);
    var mask = new UInt.UInt(null, 0x0000ff00);
    var right = new UInt.UInt(null, 0x11223344);

    var r = UInt.or(UInt.and(mask, right), UInt.and(UInt.neg(mask), left));
  });

});
<commit_msg>latest<commit_after>'use strict';

describe('Service: uint', function () {

  // load the service's module
  beforeEach(module('flowsimUiApp'));

  // instantiate service
  var UInt;
  beforeEach(inject(function (_UInt_) {
    UInt = _UInt_;
  }));

  it('UInt Import', function () {
    expect(!!UInt).toBe(true);
  });

  it('howMany_, maxFrom_', function () {
    var tmp;

    expect(UInt.howManyBits(0)).toBe(1);
    expect(UInt.howManyBits(0x0)).toBe(1);
    expect(UInt.howManyBytes(0)).toBe(1);
    expect(UInt.howManyBytes(0x0)).toBe(1);

    expect(UInt.howManyBits(0)).toBe(1);

    tmp = 1;
    _.each(_.range(31), function(i) {
      expect(UInt.howManyBits(tmp)).toBe(i+1);
      tmp <<= 1;
    });
    expect(UInt.howManyBytes(0)).toBe(1);

    tmp = 1;
    _.each(_.range(31), function(i) {
      expect(UInt.howManyBytes(tmp)).toBe(Math.ceil((i+1)/8));
      tmp <<= 1;
    });

    _.each(_.range(31), function(i) {
      expect(UInt.maxFromBits(i+1)).toBe(Math.pow(2, i+1)-1);
    });

    _.each(_.range(4), function(i) {
      expect(UInt.maxFromBytes(i+1)).toBe(Math.pow(2, (8*(i+1)))-1);
    });
  });

  it('UInt(null, 0x1ffff, 2) should fail', function() {
    expect(function() {
      new UInt.UInt(null, 0x1ffff, 2)
    }).toThrow();
  });

  it('UInt(null, "0x1ffff", 2) should fail', function() {
    expect(function() {
      new UInt.UInt(null, '0x1ffff', 2)
    }).toThrow();
  });

  it('UInt(null, 0x800, 2).toString()', function() {
    var v = new UInt.UInt(null, '0x800', 2);
    expect(v.toString(16)).toBe('0x0800');
  });

  it('UInt(null, "0xx0000", 2)', function() {
    expect(function() {
      new UInt.UInt(null, '0xx0000', 2);
    }).toThrow();
  });

  it('UInt Construction', function() {
    expect(function() {
      new UInt.UInt(null, 'q');
    }).toThrow();
    expect(function() {
      new UInt.UInt(null, '0xx00');
    }).toThrow();
    expect(function() {
      new UInt.UInt(null, 1.2);
    }).toThrow();
    expect(function() {
      new UInt.UInt(null, null, 0);
    }).toThrow();
  });

  it('UInt No-Throw Construction', function() {
    var type_ip  = new UInt.UInt(null, 0x0800, 2);
    var type_arp = new UInt.UInt(null, 0x0806, 2);
    var type     = new UInt.UInt(null, null, 2);

    var inval  = new UInt.UInt(null, 0x0a0101f0, 4);
    var outval = new UInt.UInt(null, 0x0b0101f0, 4);
  });

  it('UInt Match - Ethernet Type', function() {
    var type1 = new UInt.UInt(null, 0x0800, 2);
    var type2 = new UInt.UInt(null, 0x0806, 2);

    var exact1 = new UInt.Match(null,
        new UInt.UInt(null, 0x0800, 2),
        new UInt.UInt(null, 0xffff, 2));

    var exact2 = new UInt.Match.mkExact(type1);

    var wildcard1 = new UInt.Match(null,
        new UInt.UInt(null, 0x0000, 2),
        new UInt.UInt(null, 0x0000, 2));

    var wildcard2 = new UInt.Match.mkWildcard(type1);
    var wildcard3 = new UInt.Match.mkWildcard(2);

    expect(exact1.match(type1)).toBe(true);
    expect(exact2.match(type1)).toBe(true);
    expect(wildcard1.match(type1)).toBe(true);
    expect(wildcard2.match(type1)).toBe(true);
    expect(wildcard3.match(type1)).toBe(true);

    expect(exact1.match(type2)).toBe(false);
    expect(exact2.match(type2)).toBe(false);
    expect(wildcard1.match(type2)).toBe(true);
    expect(wildcard2.match(type2)).toBe(true);
    expect(wildcard3.match(type2)).toBe(true);

  });

  it('UInt Match - Ethernet MAC', function() {
    var empty     = new UInt.UInt(null, null, 6);
    var broadcast = (new UInt.UInt(null, null, 6)).neg();

    var mac1 = new UInt.UInt(null, [0, 1, 2, 3, 4, 5], 6);
    var mac2 = new UInt.UInt(null, [0, 1, 2, 3, 4, 6], 6);

    var exact1_mac1 = new UInt.Match(null,
        new UInt.UInt(null, [0, 1, 2, 3, 4, 5], 6),
        new UInt.UInt(null, [0xff, 0xff, 0xff, 0xff, 0xff, 0xff], 6));
    var exact2_mac1 = new UInt.Match.mkExact(mac1);

    var exact1_mac2 = new UInt.Match(null,
        new UInt.UInt(null, [0, 1, 2, 3, 4, 6], 6),
        new UInt.UInt(null, [0xff, 0xff, 0xff, 0xff, 0xff, 0xff], 6));
    var exact2_mac2 = new UInt.Match.mkExact(mac2);

    var wildcard1_mac1 = new UInt.Match(null,
        new UInt.UInt(null, null, 6),
        new UInt.UInt(null, null, 6));
    var wildcard2_mac1 = new UInt.Match.mkWildcard(mac1);
    var wildcard3_mac1 = new UInt.Match.mkWildcard(6);

    var wildcard1_mac2 = new UInt.Match(null,
        new UInt.UInt(null, null, 6),
        new UInt.UInt(null, null, 6));
    var wildcard2_mac2 = new UInt.Match.mkWildcard(mac2);
    var wildcard3_mac2 = new UInt.Match.mkWildcard(6);

    expect(exact1_mac1.match(mac1)).toBe(true);
    expect(exact2_mac1.match(mac1)).toBe(true);
    expect(wildcard1_mac1.match(mac1)).toBe(true);
    expect(wildcard2_mac1.match(mac1)).toBe(true);
    expect(wildcard3_mac1.match(mac1)).toBe(true);
    expect(exact1_mac1.match(mac2)).toBe(false);
    expect(exact2_mac1.match(mac2)).toBe(false);
    expect(wildcard1_mac1.match(mac2)).toBe(true);
    expect(wildcard2_mac1.match(mac2)).toBe(true);
    expect(wildcard3_mac1.match(mac2)).toBe(true);

    expect(exact1_mac2.match(mac1)).toBe(false);
    expect(exact2_mac2.match(mac1)).toBe(false);
    expect(wildcard1_mac2.match(mac1)).toBe(true);
    expect(wildcard2_mac2.match(mac1)).toBe(true);
    expect(wildcard3_mac2.match(mac1)).toBe(true);
    expect(exact1_mac2.match(mac2)).toBe(true);
    expect(exact2_mac2.match(mac2)).toBe(true);
    expect(wildcard1_mac2.match(mac2)).toBe(true);
    expect(wildcard2_mac2.match(mac2)).toBe(true);
    expect(wildcard3_mac2.match(mac2)).toBe(true);
  });

  it('UInt Prefix', function() {
    var route1 = new UInt.Match(null,
      new UInt.UInt(null, 0x0a000000, 4),
      new UInt.UInt(null, 0xff000000, 4));
    var route2 = new UInt.Match(null,
      new UInt.UInt(null, 0x0a0b0000, 4),
      new UInt.UInt(null, 0xffff0000, 4));
    var dst1 = new UInt.UInt(null, 0x0a0a0101, 4);
    var dst2 = new UInt.UInt(null, 0x0a0b0101, 4);
    var dst3 = new UInt.UInt(null, 0x0b0b0101, 4);

    expect(route1.match(dst1)).toBe(true);
    expect(route1.match(dst2)).toBe(true);
    expect(route1.match(dst3)).toBe(false);

    expect(route2.match(dst1)).toBe(false);
    expect(route2.match(dst2)).toBe(true);
    expect(route2.match(dst3)).toBe(false);
  });

  it('UInt Mask', function() {
    var left = new UInt.UInt(null, 0xffffffff);
    var mask = new UInt.UInt(null, 0x0000ff00);
    var right = new UInt.UInt(null, 0x11223344);

    var r = UInt.or(UInt.and(mask, right), UInt.and(UInt.neg(mask), left));
  });

});
<|endoftext|>


<commit_before>const apiRouter = require('express').Router();
const getMatches = require('../db/controllers/getMatchesGivenSelfAndOffset.js');
const addToRequests = require('../db/controllers/moveMatchIntoRequestsGivenSelfIdAndMatchId.js');
const addToRejects = require('../db/controllers/moveMatchIntoRejectsGivenSelfIdAndMatchId.js');
const changeToRejectFromConnection = require('../db/controllers/moveConnectionIntoRejectsGivenSelfIdAndConnectionId.js');
const changeToConnectionFromRequest = require('../db/controllers/moveRequestIntoConnectionsGivenSelfIdAndRequestId.js');
const changeToRejectFromRequest = require('../db/controllers/moveRequestIntoRejectsGivenSelfIdAndRequestId.js');

apiRouter.route('/matches')
  .get((req, res) => { // get matches
    getMatches(req.body.self, req.body.offset)
    .then(matches => {
      res.json(matches);
    });
  });

apiRouter.route('/relationships')
  .post((req, res) => { // post to rejects and requests
    if (req.body.newType === 'request') {
      return addToRequests(req.body.selfId, req.body.matchId)
        .then(() => {
          res.sendStatus(201);
        });
    }
    if (req.body.newType === 'reject') {
      return addToRejects(req.body.selfId, req.body.matchId)
        .then(() => {
          res.sendStatus(201);
        });
    }
    return res.sendStatus(404);
  })
  .put((req, res) => { // change relationship type
    if (req.body.oldType === 'connection') {
      return changeToRejectFromConnection(req.body.selfId, req.body.connectionId)
        .then(() => {
          res.sendStatus(200);
        });
    }
    if (req.body.oldType === 'request') {
      if (req.body.newType === 'connection') {
        return changeToConnectionFromRequest(req.body.selfId, req.body.requestId)
          .then(() => {
            res.sendStatus(200);
          });
      }
      if (req.body.newType === 'reject') {
        return changeToRejectFromRequest(req.body.selfId, req.body.requestId)
          .then(() => {
            res.sendStatus(200);
          });
      }
      return res.sendStatus(404);
    }
    return res.sendStatus(404);
  });

apiRouter.route('/profile/:id')
  .put((req, res) => { // update profile

  });

module.exports = apiRouter;
<commit_msg>Add controllers for /api/rooms and /api/messages<commit_after>const apiRouter = require('express').Router();

// controller for /matches
const getMatches = require('../db/controllers/getMatchesGivenSelfAndOffset.js');

// controllers for /relationships
const addToRequests = require('../db/controllers/moveMatchIntoRequestsGivenSelfIdAndMatchId.js');
const addToRejects = require('../db/controllers/moveMatchIntoRejectsGivenSelfIdAndMatchId.js');
const changeToRejectFromConnection = require('../db/controllers/moveConnectionIntoRejectsGivenSelfIdAndConnectionId.js');
const changeToConnectionFromRequest = require('../db/controllers/moveRequestIntoConnectionsGivenSelfIdAndRequestId.js');
const changeToRejectFromRequest = require('../db/controllers/moveRequestIntoRejectsGivenSelfIdAndRequestId.js');

// controllers for /profile/:id
const updateDescription = require('../db/controllers/updateDescriptionGivenBodyAndUserId.js');
const updateLanguages = require('../db/controllers/updateLanguagesGivenTypeAndUserId');

// controller for /rooms
const findRoom = require('../db/controllers/findOrCreateRoomGivenUserIds');

// controllers /messages
const getMessages = require('../db/controllers/getMessagesGivenRoomId');
const postMessage = require('../db/controllers/postMessageGivenUserIdAndRoomId');

apiRouter.route('/matches')
  .get((req, res) => { // get matches
    getMatches(req.body.self, req.body.offset)
    .then(matches => {
      res.json(matches);
    })
    .catch(() => {
      res.sendStatus(404);
    });
  });

apiRouter.route('/relationships')
  .post((req, res) => { // post to rejects and requests
    if (req.body.newType === 'request') {
      return addToRequests(req.body.selfId, req.body.matchId)
        .then(() => {
          res.sendStatus(201);
        });
    }
    if (req.body.newType === 'reject') {
      return addToRejects(req.body.selfId, req.body.matchId)
        .then(() => {
          res.sendStatus(201);
        });
    }
    return res.sendStatus(404);
  })
  .put((req, res) => { // change relationship type
    if (req.body.oldType === 'connection') {
      return changeToRejectFromConnection(req.body.selfId, req.body.connectionId)
        .then(() => {
          res.sendStatus(200);
        });
    }
    if (req.body.oldType === 'request') {
      if (req.body.newType === 'connection') {
        return changeToConnectionFromRequest(req.body.selfId, req.body.requestId)
          .then(() => {
            res.sendStatus(200);
          });
      }
      if (req.body.newType === 'reject') {
        return changeToRejectFromRequest(req.body.selfId, req.body.requestId)
          .then(() => {
            res.sendStatus(200);
          });
      }
      return res.sendStatus(404);
    }
    return res.sendStatus(404);
  });

apiRouter.route('/profile/:id')
  .put((req, res) => { // update profile

  });

apiRouter.route('/rooms')
  .get((req, res) => {

  });

apiRouter.route('/messages')
  .get((req, res) => {

  })
  .post((req, res) => {

  });

module.exports = apiRouter;
<|endoftext|>


<commit_before>import Ember from 'ember';

const { get, RSVP: { resolve } } = Ember;

import MegamorphicModel from './model';
import M3RecordArray from './record-array';

function stripSlash(str, stripLeading, stripTrailing) {
  let startSlash = stripLeading && str.charAt(0) === '/';
  let endSlash = stripTrailing && str.charAt(str.length - 1) === '/';
  return str.slice(startSlash ? 1 : 0, endSlash ? - 1 : str.length);
}

export default class QueryCache {
  constructor({ store }) {
    this._store = store;
    this._recordArrayManager = this._store.recordArrayManager;
    this._queryCache = new Object(null);
    this._reverseQueryCache = new Object(null);
    this.__adapter = null;
  }

  queryURL(url, { params=null, method='GET', cacheKey=null, reload=false, backgroundReload=false }={}, array) {
    let options = {};
    if (params) {
      options.data = params;
    }

    let cachedValue = cacheKey ? this._queryCache[cacheKey] : undefined;
    let adapterUrl = this._buildUrl(url);
    let loadPromise;

    if (backgroundReload || reload || cachedValue === undefined) {
      loadPromise = this._adapter.ajax(
        adapterUrl,
        method,
        options
      ).then(rawPayload => {
        let serializer = this._store.serializerFor('-ember-m3');
        let payload = serializer.normalizeResponse(this._store, MegamorphicModel, rawPayload, cacheKey, 'query-url');
        let result = this._createResult(payload, { url, params, method, cacheKey }, array);

        if (cacheKey) {
          this._addResultToCache(result, cacheKey);
        }
        return result;
      });
    }

    if (reload || cachedValue === undefined) {
      return loadPromise;
    } else {
      return resolve(cachedValue);
    }
  }

  unloadRecord(record) {
    let { id } = record;
    let matchingQueryCacheKeys = this._reverseQueryCache[id];
    if (!matchingQueryCacheKeys) { return; }

    for (let i=0; i<matchingQueryCacheKeys.length; ++i) {
      let invalidatedCacheKey = matchingQueryCacheKeys[i];
      delete this._queryCache[invalidatedCacheKey];
    }
    delete this._reverseQueryCache[id];
  }

  unloadURL(cacheKey) {
    if (this.contains(cacheKey)) {
      delete this._queryCache[cacheKey];
    }
  }

  contains(cacheKey) {
    return !!this._queryCache[cacheKey];
  }

  _buildUrl(url) {
    let parts = [];

    let needsHost = false;
    let needsNamespace = false;
    let host;
    let namespace;

    // add a hoost if we need to, ie if
    //  1. no host is present in url and
    //  2. a host is specified on the adapter
    if (/^\/\//.test(url) || /http(s)?:\/\//.test(url)) {
      needsHost = false;
      needsNamespace = false;
    } else {
      needsHost = true;
      needsNamespace = !(url.charAt(0) === '/');
    }

    if (needsHost) {
      host = stripSlash(get(this._adapter, 'host') || '', false, true);
      if (host.length > 0) {
        parts.push(host);
      }
    }

    if (needsNamespace) {
      // if we have a host we'll get '/' from joining, otherwise if we're
      // producing only a path respect whatever the namespace is configured as
      let stripLeadingSlash = parts.length > 0;
      namespace = stripSlash(get(this._adapter, 'namespace') || '', stripLeadingSlash, true);
      if (namespace.length > 0) {
        parts.push(namespace);
      }
    }

    if (parts.length > 0) {
      parts.push(stripSlash(url, true, true));
      url = parts.join('/');
    }

    if (needsHost && !host && url.charAt(0) !== '/') {
      if (needsNamespace && namespace) {
        // relative namespaces are implicitly converted to absolute, as with
        // ember data.
        //
        // namespace: 'library'
        // queryURL('books/1')
        // => '/library/books/1'
        url = `/${url}`;
      } else {
        // With no host, no namespace and a relative url we don't know what
        // request to make.  We could just make a relative request but then it
        // will resolved relative to either the base href (if a BASE tag is
        // present) or the current `location.pathname`
        throw new Error(`store.queryURL('${url}') is invalid.  Absolute paths are required.  Either add a 'host' or 'namespace' property to your -ember-m3 adapter or call 'queryURL' with an absolute path.`);
      }
    }
    return url;
  }

  _createResult(payload, query, array) {
    let internalModelOrModels = this._store._push(payload);

    if (array) {
      array._setInternalModels(internalModelOrModels);
      return array;
    } else if (Array.isArray(internalModelOrModels)) {
      return this._createRecordArray(internalModelOrModels, query);
    } else {
      return internalModelOrModels.getRecord();
    }
  }

  _addResultToCache(result, cacheKey) {
    this._queryCache[cacheKey] = result;

    if (result.constructor === M3RecordArray) {
      for (let i=0; i<result.content.length; ++i) {
        this._addRecordToReverseCache(result.content[i], cacheKey);
      }
    } else {
      this._addRecordToReverseCache(result, cacheKey);
    }
  }

  _addRecordToReverseCache({ id }, cacheKey) {
    let cacheKeys = this._reverseQueryCache[id] = this._reverseQueryCache[id] || [];
    // no need to check for presence as we're only here b/c of a cache miss
    cacheKeys.push(cacheKey);
  }

  _createRecordArray(internalModels, query) {
    let array = M3RecordArray.create({
      modelName: '-ember-m3',
      content: Ember.A(),
      store: this._store,
      manager: this._recordArrayManager,

      queryCache: this,
      query,
    });

    array._setInternalModels(internalModels);

    this._recordArrayManager._adapterPopulatedRecordArrays.push(array);

    return array;
  }

  get _adapter() {
    return this.__adapter || (this.__adapter = this._store.adapterFor('-ember-m3'));
  }

  toString() {
    return 'QueryCache';
  }
}
<commit_msg>Removing superfluous existence check for unloadURL<commit_after>import Ember from 'ember';

const { get, RSVP: { resolve } } = Ember;

import MegamorphicModel from './model';
import M3RecordArray from './record-array';

function stripSlash(str, stripLeading, stripTrailing) {
  let startSlash = stripLeading && str.charAt(0) === '/';
  let endSlash = stripTrailing && str.charAt(str.length - 1) === '/';
  return str.slice(startSlash ? 1 : 0, endSlash ? - 1 : str.length);
}

export default class QueryCache {
  constructor({ store }) {
    this._store = store;
    this._recordArrayManager = this._store.recordArrayManager;
    this._queryCache = new Object(null);
    this._reverseQueryCache = new Object(null);
    this.__adapter = null;
  }

  queryURL(url, { params=null, method='GET', cacheKey=null, reload=false, backgroundReload=false }={}, array) {
    let options = {};
    if (params) {
      options.data = params;
    }

    let cachedValue = cacheKey ? this._queryCache[cacheKey] : undefined;
    let adapterUrl = this._buildUrl(url);
    let loadPromise;

    if (backgroundReload || reload || cachedValue === undefined) {
      loadPromise = this._adapter.ajax(
        adapterUrl,
        method,
        options
      ).then(rawPayload => {
        let serializer = this._store.serializerFor('-ember-m3');
        let payload = serializer.normalizeResponse(this._store, MegamorphicModel, rawPayload, cacheKey, 'query-url');
        let result = this._createResult(payload, { url, params, method, cacheKey }, array);

        if (cacheKey) {
          this._addResultToCache(result, cacheKey);
        }
        return result;
      });
    }

    if (reload || cachedValue === undefined) {
      return loadPromise;
    } else {
      return resolve(cachedValue);
    }
  }

  unloadRecord(record) {
    let { id } = record;
    let matchingQueryCacheKeys = this._reverseQueryCache[id];
    if (!matchingQueryCacheKeys) { return; }

    for (let i=0; i<matchingQueryCacheKeys.length; ++i) {
      let invalidatedCacheKey = matchingQueryCacheKeys[i];
      delete this._queryCache[invalidatedCacheKey];
    }
    delete this._reverseQueryCache[id];
  }

  unloadURL(cacheKey) {
    delete this._queryCache[cacheKey];
  }

  contains(cacheKey) {
    return !!this._queryCache[cacheKey];
  }

  _buildUrl(url) {
    let parts = [];

    let needsHost = false;
    let needsNamespace = false;
    let host;
    let namespace;

    // add a hoost if we need to, ie if
    //  1. no host is present in url and
    //  2. a host is specified on the adapter
    if (/^\/\//.test(url) || /http(s)?:\/\//.test(url)) {
      needsHost = false;
      needsNamespace = false;
    } else {
      needsHost = true;
      needsNamespace = !(url.charAt(0) === '/');
    }

    if (needsHost) {
      host = stripSlash(get(this._adapter, 'host') || '', false, true);
      if (host.length > 0) {
        parts.push(host);
      }
    }

    if (needsNamespace) {
      // if we have a host we'll get '/' from joining, otherwise if we're
      // producing only a path respect whatever the namespace is configured as
      let stripLeadingSlash = parts.length > 0;
      namespace = stripSlash(get(this._adapter, 'namespace') || '', stripLeadingSlash, true);
      if (namespace.length > 0) {
        parts.push(namespace);
      }
    }

    if (parts.length > 0) {
      parts.push(stripSlash(url, true, true));
      url = parts.join('/');
    }

    if (needsHost && !host && url.charAt(0) !== '/') {
      if (needsNamespace && namespace) {
        // relative namespaces are implicitly converted to absolute, as with
        // ember data.
        //
        // namespace: 'library'
        // queryURL('books/1')
        // => '/library/books/1'
        url = `/${url}`;
      } else {
        // With no host, no namespace and a relative url we don't know what
        // request to make.  We could just make a relative request but then it
        // will resolved relative to either the base href (if a BASE tag is
        // present) or the current `location.pathname`
        throw new Error(`store.queryURL('${url}') is invalid.  Absolute paths are required.  Either add a 'host' or 'namespace' property to your -ember-m3 adapter or call 'queryURL' with an absolute path.`);
      }
    }
    return url;
  }

  _createResult(payload, query, array) {
    let internalModelOrModels = this._store._push(payload);

    if (array) {
      array._setInternalModels(internalModelOrModels);
      return array;
    } else if (Array.isArray(internalModelOrModels)) {
      return this._createRecordArray(internalModelOrModels, query);
    } else {
      return internalModelOrModels.getRecord();
    }
  }

  _addResultToCache(result, cacheKey) {
    this._queryCache[cacheKey] = result;

    if (result.constructor === M3RecordArray) {
      for (let i=0; i<result.content.length; ++i) {
        this._addRecordToReverseCache(result.content[i], cacheKey);
      }
    } else {
      this._addRecordToReverseCache(result, cacheKey);
    }
  }

  _addRecordToReverseCache({ id }, cacheKey) {
    let cacheKeys = this._reverseQueryCache[id] = this._reverseQueryCache[id] || [];
    // no need to check for presence as we're only here b/c of a cache miss
    cacheKeys.push(cacheKey);
  }

  _createRecordArray(internalModels, query) {
    let array = M3RecordArray.create({
      modelName: '-ember-m3',
      content: Ember.A(),
      store: this._store,
      manager: this._recordArrayManager,

      queryCache: this,
      query,
    });

    array._setInternalModels(internalModels);

    this._recordArrayManager._adapterPopulatedRecordArrays.push(array);

    return array;
  }

  get _adapter() {
    return this.__adapter || (this.__adapter = this._store.adapterFor('-ember-m3'));
  }

  toString() {
    return 'QueryCache';
  }
}
<|endoftext|>