<commit_before>'use strict';

const mlbRequest = require('./request');
const prune = require('../prune');

/**
 * Represents options given to MLB Request Builder.
 */
class SearchOptions {
    /**
     * Sets fallback values for options properties.
     *
     * @param {object} options
     */
    constructor(options) {
        this.query = options.query || null;
        this.active = (options.hasOwnProperty('active') && typeof (options.active === 'boolean')) ? options.active : true;
        this.prune = (options.hasOwnProperty('prune') && typeof (options.active === 'boolean')) ? options.prune : true;
    }
}
/**
 * Constructs and makes call to MLB for player search.
 *
 * @private
 * @param {Object|string} options - The options to make the request with.
 * @param {string} options.query - Search term to use.
 * @param {boolean} [options.active=true] - Active or historic player.
 * @param {boolean} [options.prune=true] - Whether the data retrieved should be pruned.
 * @return {Promise} - Promise to be fulfilled with search results object, or error.
 */
function playerSearch(options) {
    return new Promise((resolve, reject) => {
        const o = new SearchOptions(options);
        const url = mlbRequest.build('search_player_all', o);

        if (!url) {
            reject(new Error('Error building search_player_all request URL.'));
        }

        mlbRequest.make(url)
            .then((data) => {
                if (o.prune === true) {
                    data = prune(data);
                }
                resolve(data);
            })
            .catch((error) => {
                reject(error);
            });
    });
}

module.exports = playerSearch;
<commit_msg>use SearchDataTransformer<commit_after>'use strict';

const mlbRequest = require('./request');
const SearchDataTransformer = require('../transformers/SearchDataTransformer');

/**
 * Represents options given to MLB Request Builder.
 */
class SearchOptions {
    /**
     * Sets fallback values for options properties.
     *
     * @param {object} options
     */
    constructor(options) {
        this.query = options.query || null;
        this.active = (options.hasOwnProperty('active') && typeof (options.active === 'boolean')) ? options.active : true;
        this.prune = (options.hasOwnProperty('prune') && typeof (options.active === 'boolean')) ? options.prune : true;
    }
}
/**
 * Constructs and makes call to MLB for player search.
 *
 * @private
 * @param {Object|string} options - The options to make the request with.
 * @param {string} options.query - Search term to use.
 * @param {boolean} [options.active=true] - Active or historic player.
 * @param {boolean} [options.prune=true] - Whether the data retrieved should be pruned.
 * @return {Promise} - Promise to be fulfilled with search results object, or error.
 */
function playerSearch(options) {
    return new Promise((resolve, reject) => {
        const o = new SearchOptions(options);
        const url = mlbRequest.build('search_player_all', o);

        if (!url) {
            reject(new Error('Error building search_player_all request URL.'));
        }

        mlbRequest.make(url)
            .then((data) => {
                if (o.prune === true) {
                    const dataTransformer = new SearchDataTransformer(data);
                    dataTransformer.on('transform:success', (transformedData) => {
                        resolve(transformedData);
                    }).on('transform:nodata', (emptyData) => {
                        resolve(emptyData);
                    }).on('error', (err) => {
                        reject(err);
                    });
                    dataTransformer.transform();
                } else {
                    resolve(data);
                }
            })
            .catch((error) => {
                reject(error);
            });
    });
}

module.exports = playerSearch;
<|endoftext|>


<commit_before>/**
 * Encapsulates all the logic necessary for DOM Animations
 */

define(
  [
    'jquery',
    'underscore',
    'transit',
    'modernizr'
  ],
  function($, _, transit, modernizr) {
    'use strict';

    var FxManager = {

      /**
       * Applies a CSS3 animation to a DOM element
       * @param  {string} region    region to be animated
       * @param  {string} animation animation to apply
       *                  list of animations:
       *                  https://github.com/daneden/animate.css
       */
      animate : function(region, animation) {
        var anim = 'animated ' + animation;
        var time = 1000; //this value depends on the animation ...

        if (modernizr.csstransforms3d) {
          region.addClass('3d');
        }

        $(region).children().addClass(anim);
        setTimeout(function() {
          $(region).children().removeClass(anim);
        }, time);
      },

      animateEl : function(el, animation, cb, tm) {
        var anim = 'animated ' + animation;
        if (modernizr.csstransforms3d) {
          el.addClass('3d');
        }

        el.addClass(anim);

        if (!_.isFunction(cb)) {
          return;
        }

        setTimeout(function() {
          cb();
        }, tm ? tm : 300);
      },

      translate : function(config) {
        var el = config.el;
        var toggle = config.toggle;

        el.transition({
          x: toggle ? 0 : config.left + 'px',
          y: toggle ? 0 : config.top + 'px',
          duration: config.duration || 800,
          easing: config.easing || 'in',
          complete: config.complete
        });
      },

      slide : function(config) {
        var el = config.el;
        el.transition({
          width: config.toggle ? 0 : '100%',
          duration: config.duration || 800,
          easing: config.easing || 'ease',
          complete: config.complete
        });
      },

      fade : function(config) {
        var el = config.el;
        el.transition({
            opacity: +!config.toggle,
            duration: config.duration || 800,
            easing: config.easing || 'ease',
            complete: config.complete
          });
      },

      makeToggable : function(animation, config) {
        var that = this;

        return {

          show: true,

          toggle: function() {
            var self = this;

            config = config || {};

            config.toggle = this.show;

            config.complete = function() {
              self.show = !self.show;
            };

            that[animation](config);
          }
        };
      }

    };

    return FxManager;
  }
);
<commit_msg>fixed FxManager animate method<commit_after>/**
 * Encapsulates all the logic necessary for DOM Animations
 */

define(
  [
    'jquery',
    'underscore',
    'transit',
    'modernizr'
  ],
  function($, _, transit, modernizr) {
    'use strict';

    var FxManager = {

      /**
       * Applies a CSS3 animation to a DOM element
       * @param  {string} region    region to be animated
       * @param  {string} animation animation to apply
       *                  list of animations:
       *                  https://github.com/daneden/animate.css
       */
      animate : function(region, animation) {
        var anim = 'animated ' + animation;
        var time = 1000; //this value depends on the animation ...
        var $el = $(region);

        if (modernizr.csstransforms3d) {
          $el.addClass('3d');
        }

        $el.children().addClass(anim);
        setTimeout(function() {
          $el.children().removeClass(anim);
        }, time);
      },

      animateEl : function(el, animation, cb, tm) {
        var anim = 'animated ' + animation;
        if (modernizr.csstransforms3d) {
          el.addClass('3d');
        }

        el.addClass(anim);

        if (!_.isFunction(cb)) {
          return;
        }

        setTimeout(function() {
          cb();
        }, tm ? tm : 300);
      },

      translate : function(config) {
        var el = config.el;
        var toggle = config.toggle;

        el.transition({
          x: toggle ? 0 : config.left + 'px',
          y: toggle ? 0 : config.top + 'px',
          duration: config.duration || 800,
          easing: config.easing || 'in',
          complete: config.complete
        });
      },

      slide : function(config) {
        var el = config.el;
        el.transition({
          width: config.toggle ? 0 : '100%',
          duration: config.duration || 800,
          easing: config.easing || 'ease',
          complete: config.complete
        });
      },

      fade : function(config) {
        var el = config.el;
        el.transition({
            opacity: +!config.toggle,
            duration: config.duration || 800,
            easing: config.easing || 'ease',
            complete: config.complete
          });
      },

      makeToggable : function(animation, config) {
        var that = this;

        return {

          show: true,

          toggle: function() {
            var self = this;

            config = config || {};

            config.toggle = this.show;

            config.complete = function() {
              self.show = !self.show;
            };

            that[animation](config);
          }
        };
      }

    };

    return FxManager;
  }
);
<|endoftext|>


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

import objectValues from '../polyfills/objectValues';
import invariant from '../jsutils/invariant';
import keyMap from '../jsutils/keyMap';
import keyValMap from '../jsutils/keyValMap';
import type { ObjMap } from '../jsutils/ObjMap';
import { valueFromAST } from './valueFromAST';
import { assertValidSDL } from '../validation/validate';
import blockStringValue from '../language/blockStringValue';
import { TokenKind } from '../language/lexer';
import { parse } from '../language/parser';
import type { ParseOptions } from '../language/parser';
import type { Source } from '../language/source';
import { getDirectiveValues } from '../execution/values';
import { Kind } from '../language/kinds';

import type {
  DocumentNode,
  TypeNode,
  NamedTypeNode,
  SchemaDefinitionNode,
  TypeDefinitionNode,
  ScalarTypeDefinitionNode,
  ObjectTypeDefinitionNode,
  FieldDefinitionNode,
  InputValueDefinitionNode,
  InterfaceTypeDefinitionNode,
  UnionTypeDefinitionNode,
  EnumTypeDefinitionNode,
  EnumValueDefinitionNode,
  InputObjectTypeDefinitionNode,
  DirectiveDefinitionNode,
  StringValueNode,
  Location,
} from '../language/ast';
import { isTypeDefinitionNode } from '../language/predicates';

import type { DirectiveLocationEnum } from '../language/directiveLocation';

import type {
  GraphQLType,
  GraphQLNamedType,
  GraphQLFieldConfig,
  GraphQLEnumValueConfig,
  GraphQLInputField,
} from '../type/definition';

import {
  GraphQLScalarType,
  GraphQLObjectType,
  GraphQLInterfaceType,
  GraphQLUnionType,
  GraphQLEnumType,
  GraphQLInputObjectType,
  GraphQLList,
  GraphQLNonNull,
} from '../type/definition';

import {
  GraphQLDirective,
  GraphQLSkipDirective,
  GraphQLIncludeDirective,
  GraphQLDeprecatedDirective,
} from '../type/directives';

import { introspectionTypes } from '../type/introspection';

import { specifiedScalarTypes } from '../type/scalars';

import { GraphQLSchema } from '../type/schema';
import type { GraphQLSchemaValidationOptions } from '../type/schema';

export type BuildSchemaOptions = {
  ...GraphQLSchemaValidationOptions,

  /**
   * Descriptions are defined as preceding string literals, however an older
   * experimental version of the SDL supported preceding comments as
   * descriptions. Set to true to enable this deprecated behavior.
   * This option is provided to ease adoption and will be removed in v16.
   *
   * Default: false
   */
  commentDescriptions?: boolean,

  /**
   * Set to true to assume the SDL is valid.
   *
   * Default: false
   */
  assumeValidSDL?: boolean,
};

/**
 * This takes the ast of a schema document produced by the parse function in
 * src/language/parser.js.
 *
 * If no schema definition is provided, then it will look for types named Query
 * and Mutation.
 *
 * Given that AST it constructs a GraphQLSchema. The resulting schema
 * has no resolve methods, so execution will use default resolvers.
 *
 * Accepts options as a second argument:
 *
 *    - commentDescriptions:
 *        Provide true to use preceding comments as the description.
 *
 */
export function buildASTSchema(
  documentAST: DocumentNode,
  options?: BuildSchemaOptions,
): GraphQLSchema {
  invariant(
    documentAST && documentAST.kind === Kind.DOCUMENT,
    'Must provide valid Document AST',
  );

  if (!options || !(options.assumeValid || options.assumeValidSDL)) {
    assertValidSDL(documentAST);
  }

  let schemaDef: ?SchemaDefinitionNode;
  const nodeMap: ObjMap<TypeDefinitionNode> = Object.create(null);
  const directiveDefs: Array<DirectiveDefinitionNode> = [];

  for (const def of documentAST.definitions) {
    if (def.kind === Kind.SCHEMA_DEFINITION) {
      schemaDef = def;
    } else if (isTypeDefinitionNode(def)) {
      nodeMap[def.name.value] = def;
    } else if (def.kind === Kind.DIRECTIVE_DEFINITION) {
      directiveDefs.push(def);
    }
  }

  const operationTypes = schemaDef
    ? getOperationTypes(schemaDef)
    : {
        query: nodeMap.Query,
        mutation: nodeMap.Mutation,
        subscription: nodeMap.Subscription,
      };

  const definitionBuilder = new ASTDefinitionBuilder(
    nodeMap,
    options,
    typeName => {
      throw new Error(`Type "${typeName}" not found in document.`);
    },
  );

  const directives = directiveDefs.map(def =>
    definitionBuilder.buildDirective(def),
  );

  // If specified directives were not explicitly declared, add them.
  if (!directives.some(directive => directive.name === 'skip')) {
    directives.push(GraphQLSkipDirective);
  }

  if (!directives.some(directive => directive.name === 'include')) {
    directives.push(GraphQLIncludeDirective);
  }

  if (!directives.some(directive => directive.name === 'deprecated')) {
    directives.push(GraphQLDeprecatedDirective);
  }

  // Note: While this could make early assertions to get the correctly
  // typed values below, that would throw immediately while type system
  // validation with validateSchema() will produce more actionable results.
  return new GraphQLSchema({
    query: operationTypes.query
      ? (definitionBuilder.buildType(operationTypes.query): any)
      : null,
    mutation: operationTypes.mutation
      ? (definitionBuilder.buildType(operationTypes.mutation): any)
      : null,
    subscription: operationTypes.subscription
      ? (definitionBuilder.buildType(operationTypes.subscription): any)
      : null,
    types: objectValues(nodeMap).map(node => definitionBuilder.buildType(node)),
    directives,
    astNode: schemaDef,
    assumeValid: options && options.assumeValid,
    allowedLegacyNames: options && options.allowedLegacyNames,
  });

  function getOperationTypes(schema: SchemaDefinitionNode) {
    const opTypes = {};
    for (const operationType of schema.operationTypes) {
      opTypes[operationType.operation] = operationType.type;
    }
    return opTypes;
  }
}

type TypeDefinitionsMap = ObjMap<TypeDefinitionNode>;
type TypeResolver = (typeName: string) => GraphQLNamedType;

export class ASTDefinitionBuilder {
  _typeDefinitionsMap: TypeDefinitionsMap;
  _options: ?BuildSchemaOptions;
  _resolveType: TypeResolver;
  _cache: ObjMap<GraphQLNamedType>;

  constructor(
    typeDefinitionsMap: TypeDefinitionsMap,
    options: ?BuildSchemaOptions,
    resolveType: TypeResolver,
  ) {
    this._typeDefinitionsMap = typeDefinitionsMap;
    this._options = options;
    this._resolveType = resolveType;
    // Initialize to the GraphQL built in scalars and introspection types.
    this._cache = keyMap(
      specifiedScalarTypes.concat(introspectionTypes),
      type => type.name,
    );
  }

  buildType(node: NamedTypeNode | TypeDefinitionNode): GraphQLNamedType {
    const typeName = node.name.value;
    if (!this._cache[typeName]) {
      if (node.kind === Kind.NAMED_TYPE) {
        const defNode = this._typeDefinitionsMap[typeName];
        this._cache[typeName] = defNode
          ? this._makeSchemaDef(defNode)
          : this._resolveType(node.name.value);
      } else {
        this._cache[typeName] = this._makeSchemaDef(node);
      }
    }
    return this._cache[typeName];
  }

  _buildWrappedType(typeNode: TypeNode): GraphQLType {
    if (typeNode.kind === Kind.LIST_TYPE) {
      return GraphQLList(this._buildWrappedType(typeNode.type));
    }
    if (typeNode.kind === Kind.NON_NULL_TYPE) {
      return GraphQLNonNull(
        // Note: GraphQLNonNull constructor validates this type
        (this._buildWrappedType(typeNode.type): any),
      );
    }
    return this.buildType(typeNode);
  }

  buildDirective(directiveNode: DirectiveDefinitionNode): GraphQLDirective {
    return new GraphQLDirective({
      name: directiveNode.name.value,
      description: getDescription(directiveNode, this._options),
      locations: directiveNode.locations.map(
        node => ((node.value: any): DirectiveLocationEnum),
      ),
      args:
        directiveNode.arguments &&
        this._makeInputValues(directiveNode.arguments),
      astNode: directiveNode,
    });
  }

  buildField(field: FieldDefinitionNode): GraphQLFieldConfig<mixed, mixed> {
    return {
      // Note: While this could make assertions to get the correctly typed
      // value, that would throw immediately while type system validation
      // with validateSchema() will produce more actionable results.
      type: (this._buildWrappedType(field.type): any),
      description: getDescription(field, this._options),
      args: field.arguments && this._makeInputValues(field.arguments),
      deprecationReason: getDeprecationReason(field),
      astNode: field,
    };
  }

  buildInputField(value: InputValueDefinitionNode): GraphQLInputField {
    // Note: While this could make assertions to get the correctly typed
    // value, that would throw immediately while type system validation
    // with validateSchema() will produce more actionable results.
    const type: any = this._buildWrappedType(value.type);
    return {
      name: value.name.value,
      type,
      description: getDescription(value, this._options),
      defaultValue: valueFromAST(value.defaultValue, type),
      astNode: value,
    };
  }

  buildEnumValue(value: EnumValueDefinitionNode): GraphQLEnumValueConfig {
    return {
      description: getDescription(value, this._options),
      deprecationReason: getDeprecationReason(value),
      astNode: value,
    };
  }

  _makeSchemaDef(def: TypeDefinitionNode): GraphQLNamedType {
    switch (def.kind) {
      case Kind.OBJECT_TYPE_DEFINITION:
        return this._makeTypeDef(def);
      case Kind.INTERFACE_TYPE_DEFINITION:
        return this._makeInterfaceDef(def);
      case Kind.ENUM_TYPE_DEFINITION:
        return this._makeEnumDef(def);
      case Kind.UNION_TYPE_DEFINITION:
        return this._makeUnionDef(def);
      case Kind.SCALAR_TYPE_DEFINITION:
        return this._makeScalarDef(def);
      case Kind.INPUT_OBJECT_TYPE_DEFINITION:
        return this._makeInputObjectDef(def);
      default:
        throw new Error(`Type kind "${def.kind}" not supported.`);
    }
  }

  _makeTypeDef(def: ObjectTypeDefinitionNode) {
    const interfaces: ?$ReadOnlyArray<NamedTypeNode> = def.interfaces;
    return new GraphQLObjectType({
      name: def.name.value,
      description: getDescription(def, this._options),
      fields: () => this._makeFieldDefMap(def),
      // Note: While this could make early assertions to get the correctly
      // typed values, that would throw immediately while type system
      // validation with validateSchema() will produce more actionable results.
      interfaces: interfaces
        ? () => interfaces.map(ref => (this.buildType(ref): any))
        : [],
      astNode: def,
    });
  }

  _makeFieldDefMap(
    def: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode,
  ) {
    return def.fields
      ? keyValMap<_, GraphQLFieldConfig<mixed, mixed>>(
          def.fields,
          field => field.name.value,
          field => this.buildField(field),
        )
      : {};
  }

  _makeInputValues(values: $ReadOnlyArray<InputValueDefinitionNode>) {
    return keyValMap<_, GraphQLInputField>(
      values,
      value => value.name.value,
      value => this.buildInputField(value),
    );
  }

  _makeInterfaceDef(def: InterfaceTypeDefinitionNode) {
    return new GraphQLInterfaceType({
      name: def.name.value,
      description: getDescription(def, this._options),
      fields: () => this._makeFieldDefMap(def),
      astNode: def,
    });
  }

  _makeEnumDef(def: EnumTypeDefinitionNode) {
    return new GraphQLEnumType({
      name: def.name.value,
      description: getDescription(def, this._options),
      values: this._makeValueDefMap(def),
      astNode: def,
    });
  }

  _makeValueDefMap(def: EnumTypeDefinitionNode) {
    return def.values
      ? keyValMap<_, GraphQLEnumValueConfig>(
          def.values,
          enumValue => enumValue.name.value,
          enumValue => this.buildEnumValue(enumValue),
        )
      : {};
  }

  _makeUnionDef(def: UnionTypeDefinitionNode) {
    const types: ?$ReadOnlyArray<NamedTypeNode> = def.types;
    return new GraphQLUnionType({
      name: def.name.value,
      description: getDescription(def, this._options),
      // Note: While this could make assertions to get the correctly typed
      // values below, that would throw immediately while type system
      // validation with validateSchema() will produce more actionable results.
      types: types ? () => types.map(ref => (this.buildType(ref): any)) : [],
      astNode: def,
    });
  }

  _makeScalarDef(def: ScalarTypeDefinitionNode) {
    return new GraphQLScalarType({
      name: def.name.value,
      description: getDescription(def, this._options),
      astNode: def,
      serialize: value => value,
    });
  }

  _makeInputObjectDef(def: InputObjectTypeDefinitionNode) {
    return new GraphQLInputObjectType({
      name: def.name.value,
      description: getDescription(def, this._options),
      fields: () => (def.fields ? this._makeInputValues(def.fields) : {}),
      astNode: def,
    });
  }
}

/**
 * Given a field or enum value node, returns the string value for the
 * deprecation reason.
 */
function getDeprecationReason(
  node: EnumValueDefinitionNode | FieldDefinitionNode,
): ?string {
  const deprecated = getDirectiveValues(GraphQLDeprecatedDirective, node);
  return deprecated && (deprecated.reason: any);
}

/**
 * Given an ast node, returns its string description.
 * @deprecated: provided to ease adoption and will be removed in v16.
 *
 * Accepts options as a second argument:
 *
 *    - commentDescriptions:
 *        Provide true to use preceding comments as the description.
 *
 */
export function getDescription(
  node: { +description?: StringValueNode, +loc?: Location },
  options: ?BuildSchemaOptions,
): void | string {
  if (node.description) {
    return node.description.value;
  }
  if (options && options.commentDescriptions) {
    const rawValue = getLeadingCommentBlock(node);
    if (rawValue !== undefined) {
      return blockStringValue('\n' + rawValue);
    }
  }
}

function getLeadingCommentBlock(node): void | string {
  const loc = node.loc;
  if (!loc) {
    return;
  }
  const comments = [];
  let token = loc.startToken.prev;
  while (
    token &&
    token.kind === TokenKind.COMMENT &&
    token.next &&
    token.prev &&
    token.line + 1 === token.next.line &&
    token.line !== token.prev.line
  ) {
    const value = String(token.value);
    comments.push(value);
    token = token.prev;
  }
  return comments.reverse().join('\n');
}

/**
 * A helper function to build a GraphQLSchema directly from a source
 * document.
 */
export function buildSchema(
  source: string | Source,
  options?: BuildSchemaOptions & ParseOptions,
): GraphQLSchema {
  return buildASTSchema(parse(source, options), options);
}
<commit_msg>Remove usage of Flow placeholder argument + cleanup (#1669)<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict
 */

import objectValues from '../polyfills/objectValues';
import invariant from '../jsutils/invariant';
import keyMap from '../jsutils/keyMap';
import keyValMap from '../jsutils/keyValMap';
import type { ObjMap } from '../jsutils/ObjMap';
import { valueFromAST } from './valueFromAST';
import { assertValidSDL } from '../validation/validate';
import blockStringValue from '../language/blockStringValue';
import { TokenKind } from '../language/lexer';
import { parse } from '../language/parser';
import type { ParseOptions } from '../language/parser';
import type { Source } from '../language/source';
import { getDirectiveValues } from '../execution/values';
import { Kind } from '../language/kinds';

import type {
  DocumentNode,
  NameNode,
  TypeNode,
  NamedTypeNode,
  SchemaDefinitionNode,
  TypeDefinitionNode,
  ScalarTypeDefinitionNode,
  ObjectTypeDefinitionNode,
  FieldDefinitionNode,
  InputValueDefinitionNode,
  InterfaceTypeDefinitionNode,
  UnionTypeDefinitionNode,
  EnumTypeDefinitionNode,
  EnumValueDefinitionNode,
  InputObjectTypeDefinitionNode,
  DirectiveDefinitionNode,
  StringValueNode,
  Location,
} from '../language/ast';
import { isTypeDefinitionNode } from '../language/predicates';

import type { DirectiveLocationEnum } from '../language/directiveLocation';

import type {
  GraphQLType,
  GraphQLNamedType,
  GraphQLFieldConfig,
  GraphQLArgumentConfig,
  GraphQLEnumValueConfig,
  GraphQLInputFieldConfig,
} from '../type/definition';

import {
  GraphQLScalarType,
  GraphQLObjectType,
  GraphQLInterfaceType,
  GraphQLUnionType,
  GraphQLEnumType,
  GraphQLInputObjectType,
  GraphQLList,
  GraphQLNonNull,
} from '../type/definition';

import {
  GraphQLDirective,
  GraphQLSkipDirective,
  GraphQLIncludeDirective,
  GraphQLDeprecatedDirective,
} from '../type/directives';

import { introspectionTypes } from '../type/introspection';

import { specifiedScalarTypes } from '../type/scalars';

import { GraphQLSchema } from '../type/schema';
import type { GraphQLSchemaValidationOptions } from '../type/schema';

export type BuildSchemaOptions = {
  ...GraphQLSchemaValidationOptions,

  /**
   * Descriptions are defined as preceding string literals, however an older
   * experimental version of the SDL supported preceding comments as
   * descriptions. Set to true to enable this deprecated behavior.
   * This option is provided to ease adoption and will be removed in v16.
   *
   * Default: false
   */
  commentDescriptions?: boolean,

  /**
   * Set to true to assume the SDL is valid.
   *
   * Default: false
   */
  assumeValidSDL?: boolean,
};

/**
 * This takes the ast of a schema document produced by the parse function in
 * src/language/parser.js.
 *
 * If no schema definition is provided, then it will look for types named Query
 * and Mutation.
 *
 * Given that AST it constructs a GraphQLSchema. The resulting schema
 * has no resolve methods, so execution will use default resolvers.
 *
 * Accepts options as a second argument:
 *
 *    - commentDescriptions:
 *        Provide true to use preceding comments as the description.
 *
 */
export function buildASTSchema(
  documentAST: DocumentNode,
  options?: BuildSchemaOptions,
): GraphQLSchema {
  invariant(
    documentAST && documentAST.kind === Kind.DOCUMENT,
    'Must provide valid Document AST',
  );

  if (!options || !(options.assumeValid || options.assumeValidSDL)) {
    assertValidSDL(documentAST);
  }

  let schemaDef: ?SchemaDefinitionNode;
  const nodeMap: ObjMap<TypeDefinitionNode> = Object.create(null);
  const directiveDefs: Array<DirectiveDefinitionNode> = [];

  for (const def of documentAST.definitions) {
    if (def.kind === Kind.SCHEMA_DEFINITION) {
      schemaDef = def;
    } else if (isTypeDefinitionNode(def)) {
      nodeMap[def.name.value] = def;
    } else if (def.kind === Kind.DIRECTIVE_DEFINITION) {
      directiveDefs.push(def);
    }
  }

  const operationTypes = schemaDef
    ? getOperationTypes(schemaDef)
    : {
        query: nodeMap.Query,
        mutation: nodeMap.Mutation,
        subscription: nodeMap.Subscription,
      };

  const definitionBuilder = new ASTDefinitionBuilder(
    nodeMap,
    options,
    typeName => {
      throw new Error(`Type "${typeName}" not found in document.`);
    },
  );

  const directives = directiveDefs.map(def =>
    definitionBuilder.buildDirective(def),
  );

  // If specified directives were not explicitly declared, add them.
  if (!directives.some(directive => directive.name === 'skip')) {
    directives.push(GraphQLSkipDirective);
  }

  if (!directives.some(directive => directive.name === 'include')) {
    directives.push(GraphQLIncludeDirective);
  }

  if (!directives.some(directive => directive.name === 'deprecated')) {
    directives.push(GraphQLDeprecatedDirective);
  }

  // Note: While this could make early assertions to get the correctly
  // typed values below, that would throw immediately while type system
  // validation with validateSchema() will produce more actionable results.
  return new GraphQLSchema({
    query: operationTypes.query
      ? (definitionBuilder.buildType(operationTypes.query): any)
      : null,
    mutation: operationTypes.mutation
      ? (definitionBuilder.buildType(operationTypes.mutation): any)
      : null,
    subscription: operationTypes.subscription
      ? (definitionBuilder.buildType(operationTypes.subscription): any)
      : null,
    types: objectValues(nodeMap).map(node => definitionBuilder.buildType(node)),
    directives,
    astNode: schemaDef,
    assumeValid: options && options.assumeValid,
    allowedLegacyNames: options && options.allowedLegacyNames,
  });

  function getOperationTypes(schema: SchemaDefinitionNode) {
    const opTypes = {};
    for (const operationType of schema.operationTypes) {
      opTypes[operationType.operation] = operationType.type;
    }
    return opTypes;
  }
}

type TypeDefinitionsMap = ObjMap<TypeDefinitionNode>;
type TypeResolver = (typeName: string) => GraphQLNamedType;

export class ASTDefinitionBuilder {
  _typeDefinitionsMap: TypeDefinitionsMap;
  _options: ?BuildSchemaOptions;
  _resolveType: TypeResolver;
  _cache: ObjMap<GraphQLNamedType>;

  constructor(
    typeDefinitionsMap: TypeDefinitionsMap,
    options: ?BuildSchemaOptions,
    resolveType: TypeResolver,
  ) {
    this._typeDefinitionsMap = typeDefinitionsMap;
    this._options = options;
    this._resolveType = resolveType;
    // Initialize to the GraphQL built in scalars and introspection types.
    this._cache = keyMap(
      specifiedScalarTypes.concat(introspectionTypes),
      type => type.name,
    );
  }

  buildType(node: NamedTypeNode | TypeDefinitionNode): GraphQLNamedType {
    const typeName = node.name.value;
    if (!this._cache[typeName]) {
      if (node.kind === Kind.NAMED_TYPE) {
        const defNode = this._typeDefinitionsMap[typeName];
        this._cache[typeName] = defNode
          ? this._makeSchemaDef(defNode)
          : this._resolveType(node.name.value);
      } else {
        this._cache[typeName] = this._makeSchemaDef(node);
      }
    }
    return this._cache[typeName];
  }

  _buildWrappedType(typeNode: TypeNode): GraphQLType {
    if (typeNode.kind === Kind.LIST_TYPE) {
      return GraphQLList(this._buildWrappedType(typeNode.type));
    }
    if (typeNode.kind === Kind.NON_NULL_TYPE) {
      return GraphQLNonNull(
        // Note: GraphQLNonNull constructor validates this type
        (this._buildWrappedType(typeNode.type): any),
      );
    }
    return this.buildType(typeNode);
  }

  buildDirective(directive: DirectiveDefinitionNode): GraphQLDirective {
    const locations = directive.locations.map(
      ({ value }) => ((value: any): DirectiveLocationEnum),
    );

    return new GraphQLDirective({
      name: directive.name.value,
      description: getDescription(directive, this._options),
      locations,
      args: keyByNameNode(directive.arguments || [], arg => this.buildArg(arg)),
      astNode: directive,
    });
  }

  buildField(field: FieldDefinitionNode): GraphQLFieldConfig<mixed, mixed> {
    return {
      // Note: While this could make assertions to get the correctly typed
      // value, that would throw immediately while type system validation
      // with validateSchema() will produce more actionable results.
      type: (this._buildWrappedType(field.type): any),
      description: getDescription(field, this._options),
      args: keyByNameNode(field.arguments || [], arg => this.buildArg(arg)),
      deprecationReason: getDeprecationReason(field),
      astNode: field,
    };
  }

  buildArg(value: InputValueDefinitionNode): GraphQLArgumentConfig {
    // Note: While this could make assertions to get the correctly typed
    // value, that would throw immediately while type system validation
    // with validateSchema() will produce more actionable results.
    const type: any = this._buildWrappedType(value.type);
    return {
      type,
      description: getDescription(value, this._options),
      defaultValue: valueFromAST(value.defaultValue, type),
      astNode: value,
    };
  }

  buildInputField(value: InputValueDefinitionNode): GraphQLInputFieldConfig {
    // Note: While this could make assertions to get the correctly typed
    // value, that would throw immediately while type system validation
    // with validateSchema() will produce more actionable results.
    const type: any = this._buildWrappedType(value.type);
    return {
      type,
      description: getDescription(value, this._options),
      defaultValue: valueFromAST(value.defaultValue, type),
      astNode: value,
    };
  }

  buildEnumValue(value: EnumValueDefinitionNode): GraphQLEnumValueConfig {
    return {
      description: getDescription(value, this._options),
      deprecationReason: getDeprecationReason(value),
      astNode: value,
    };
  }

  _makeSchemaDef(astNode: TypeDefinitionNode): GraphQLNamedType {
    switch (astNode.kind) {
      case Kind.OBJECT_TYPE_DEFINITION:
        return this._makeTypeDef(astNode);
      case Kind.INTERFACE_TYPE_DEFINITION:
        return this._makeInterfaceDef(astNode);
      case Kind.ENUM_TYPE_DEFINITION:
        return this._makeEnumDef(astNode);
      case Kind.UNION_TYPE_DEFINITION:
        return this._makeUnionDef(astNode);
      case Kind.SCALAR_TYPE_DEFINITION:
        return this._makeScalarDef(astNode);
      case Kind.INPUT_OBJECT_TYPE_DEFINITION:
        return this._makeInputObjectDef(astNode);
      default:
        throw new Error(`Type kind "${astNode.kind}" not supported.`);
    }
  }

  _makeTypeDef(astNode: ObjectTypeDefinitionNode) {
    const interfaceNodes = astNode.interfaces;
    const fieldNodes = astNode.fields;

    // Note: While this could make assertions to get the correctly typed
    // values below, that would throw immediately while type system
    // validation with validateSchema() will produce more actionable results.
    const interfaces =
      interfaceNodes && interfaceNodes.length > 0
        ? () => interfaceNodes.map(ref => (this.buildType(ref): any))
        : [];

    const fields =
      fieldNodes && fieldNodes.length > 0
        ? () => keyByNameNode(fieldNodes, field => this.buildField(field))
        : Object.create(null);

    return new GraphQLObjectType({
      name: astNode.name.value,
      description: getDescription(astNode, this._options),
      interfaces,
      fields,
      astNode,
    });
  }

  _makeInterfaceDef(astNode: InterfaceTypeDefinitionNode) {
    const fieldNodes = astNode.fields;

    const fields =
      fieldNodes && fieldNodes.length > 0
        ? () => keyByNameNode(fieldNodes, field => this.buildField(field))
        : Object.create(null);

    return new GraphQLInterfaceType({
      name: astNode.name.value,
      description: getDescription(astNode, this._options),
      fields,
      astNode,
    });
  }

  _makeEnumDef(astNode: EnumTypeDefinitionNode) {
    const valueNodes = astNode.values || [];

    return new GraphQLEnumType({
      name: astNode.name.value,
      description: getDescription(astNode, this._options),
      values: keyByNameNode(valueNodes, value => this.buildEnumValue(value)),
      astNode,
    });
  }

  _makeUnionDef(astNode: UnionTypeDefinitionNode) {
    const typeNodes = astNode.types;

    // Note: While this could make assertions to get the correctly typed
    // values below, that would throw immediately while type system
    // validation with validateSchema() will produce more actionable results.
    const types =
      typeNodes && typeNodes.length > 0
        ? () => typeNodes.map(ref => (this.buildType(ref): any))
        : [];

    return new GraphQLUnionType({
      name: astNode.name.value,
      description: getDescription(astNode, this._options),
      types,
      astNode,
    });
  }

  _makeScalarDef(astNode: ScalarTypeDefinitionNode) {
    return new GraphQLScalarType({
      name: astNode.name.value,
      description: getDescription(astNode, this._options),
      astNode,
      serialize: value => value,
    });
  }

  _makeInputObjectDef(def: InputObjectTypeDefinitionNode) {
    const { fields } = def;

    return new GraphQLInputObjectType({
      name: def.name.value,
      description: getDescription(def, this._options),
      fields: fields
        ? () => keyByNameNode(fields, field => this.buildInputField(field))
        : Object.create(null),
      astNode: def,
    });
  }
}

function keyByNameNode<T: { +name: NameNode }, V>(
  list: $ReadOnlyArray<T>,
  valFn: (item: T) => V,
): ObjMap<V> {
  return keyValMap(list, ({ name }) => name.value, valFn);
}

/**
 * Given a field or enum value node, returns the string value for the
 * deprecation reason.
 */
function getDeprecationReason(
  node: EnumValueDefinitionNode | FieldDefinitionNode,
): ?string {
  const deprecated = getDirectiveValues(GraphQLDeprecatedDirective, node);
  return deprecated && (deprecated.reason: any);
}

/**
 * Given an ast node, returns its string description.
 * @deprecated: provided to ease adoption and will be removed in v16.
 *
 * Accepts options as a second argument:
 *
 *    - commentDescriptions:
 *        Provide true to use preceding comments as the description.
 *
 */
export function getDescription(
  node: { +description?: StringValueNode, +loc?: Location },
  options: ?BuildSchemaOptions,
): void | string {
  if (node.description) {
    return node.description.value;
  }
  if (options && options.commentDescriptions) {
    const rawValue = getLeadingCommentBlock(node);
    if (rawValue !== undefined) {
      return blockStringValue('\n' + rawValue);
    }
  }
}

function getLeadingCommentBlock(node): void | string {
  const loc = node.loc;
  if (!loc) {
    return;
  }
  const comments = [];
  let token = loc.startToken.prev;
  while (
    token &&
    token.kind === TokenKind.COMMENT &&
    token.next &&
    token.prev &&
    token.line + 1 === token.next.line &&
    token.line !== token.prev.line
  ) {
    const value = String(token.value);
    comments.push(value);
    token = token.prev;
  }
  return comments.reverse().join('\n');
}

/**
 * A helper function to build a GraphQLSchema directly from a source
 * document.
 */
export function buildSchema(
  source: string | Source,
  options?: BuildSchemaOptions & ParseOptions,
): GraphQLSchema {
  return buildASTSchema(parse(source, options), options);
}
<|endoftext|>


<commit_before>//META {"name": "BetterReplyer", "source": "https://github.com/Zerthox/BetterDiscord-Plugins/blob/master/v1/BetterReplyer.plugin.js"} *//

/**
 * @author Zerthox
 * @version 4.0.4
 * @return {class} BetterReplyer Plugin class
 */
const BetterReplyer = (() => {

	// Api constants
	const {React, ReactDOM} = BdApi;

	/** Module storage */
	const Module = {
		Constants: BdApi.findModuleByProps("Permissions"),
		Permissions: BdApi.findModuleByProps("getChannelPermissions"),
		Drafts: BdApi.findModuleByProps("getDraft"),
		DraftActions: BdApi.findModuleByProps("saveDraft"),
		Users: BdApi.findModuleByProps("getUser", "getCurrentUser")
	};

	/** Component storage */
	const Component = {
		Message: BdApi.findModuleByProps("Message", "MessageAvatar").Message,
		ChannelTextArea: BDV2.WebpackModules.findByDisplayName("ChannelTextArea")
	};

	/** Selector storage */
	const Selector = {
		Messages: BdApi.findModuleByProps("message", "container", "headerCozy"),
		TextArea: BdApi.findModuleByProps("channelTextArea")
	};

	/** Storage for Patches */
	const Patches = {};

	// return plugin class
	return class BetterReplyer {

		/**
		 * @return {string} Plugin name
		 */
		getName() {
			return "BetterReplyer";
		}

		/**
		 * @return {string} Plugin version
		 */
		getVersion() {
			return "4.0.4";
		}

		/**
		 * @return {ReactElement} Plugin author
		 */
		getAuthor() {
			return this.createAnchor({text: "Zerthox", url: "https://github.com/Zerthox"});
		}

		/**
		 * @return {ReactElement} Plugin description
		 */
		getDescription() {
			return React.createElement("span", {style: {"white-space": "pre-line"}},
				"Reply to people using their ID with a button.\n Inspired by ",
				this.createAnchor({text: "Replyer", url: "https://github.com/cosmicsalad/Discord-Themes-and-Plugins/blob/master/plugins/replyer.plugin.js"}),
				" by ",
				this.createAnchor({text: "@Hammmock#3110", url: "https://github.com/cosmicsalad"}),
				", ",
				this.createAnchor({text: "@Natsulus#0001", url: "https://github.com/Delivator"}),
				" & ",
				this.createAnchor({text: "@Zerebos#7790", url: "https://github.com/rauenzi"}),
				"."
			);
		}

		/**
		 * Log a message in Console
		 * @param {string} msg message
		 */
		log(msg) {
			console.log(`%c[${this.getName()}] %c(v${this.getVersion()})%c ${msg}`, "color: #3a71c1; font-weight: 700;", "color: #666; font-size: .8em;", "");
		}

		/**
		 * Create a new Anchor element based on Discord's Anchor Component
		 * @param {object} props Component props
		 * @param {string} props.text Anchor text
		 * @param {string} props.url Anchor url
		 * @return {ReactElement} New Anchor element
		 */
		createAnchor(props) {
			return React.createElement(BDV2.WebpackModules.findByDisplayName("Anchor"), {href: props.url, target: "_blank", title: props.url}, props.text);
		}

		/**
		 * Plugin constructor
		 */
		constructor() {
			this.focused = null;
			this.selection = [0, 0];
			this.mode = false;
		}

		/**
		 * Plugin start function
		 */
		start() {

			// inject styles
			BdApi.injectCSS(this.getName(),
				`/* BetterReplyer CSS */
				.replyer {
					position: relative;
					top: -1px;
					margin-left: 5px;
					padding: 3px 5px;
					background: rgba(0, 0, 0, 0.4);
					border-radius: 3px;
					color: #fff !important;
					font-size: 10px;
					text-transform: uppercase;
					cursor: pointer;
				}
				.${Selector.Messages.container.split(" ")[0]}:not(:hover) .replyer {
					visibility: hidden;
				}`
			);

			// patch message render function
			Patches.message = BdApi.monkeyPatch(Component.Message.prototype, "render", {silent: true, after: (d) => {

				// get this & old return value
				const t = d.thisObject,
					r = d.returnValue;

				// get message author id
				const id = t.props.message.author.id;

				// return unmodified if disabled, compact, no header or author is current user
				if (t.props.isDisabled || t.props.isCompact || !t.props.isHeader || id === Module.Users.getCurrentUser().id) {
					return r;
				}

				// get current channel permissions
				const p = Module.Permissions.getChannelPermissions(t.props.channel.id);

				// return unmodified if no permissions to send messages
				if (typeof p === "number" && !(p & Module.Constants.Permissions.SEND_MESSAGES)) {
					return r;
				}

				// find message header
				const h = r.props.children.find((e) => e.props && e.props.className === Selector.Messages.headerCozy);

				// find message header meta
				const m = h && h.props.children.find((e) => e.props && e.props.className === Selector.Messages.headerCozyMeta);

				// add reply button
				m && m.props.children.push(React.createElement("span", {
					className: "replyer",
					onClick: () => {

						// get saved text area
						const f = this.focused;

						// check if text area saved
						if (f) {

							// focus textarea
							f.focus();

							// check mode
							if (this.mode) {

								// select saved selection
								f.setSelectionRange(this.selection[0], this.selection[1]);

								// insert mention
								document.execCommand("insertText", false, `<@!${id}>`);

								// update saved text area
								setTimeout(() => {
									this.focused = f;
								}, 100);
							}
							else {

								// get mention
								const m = `<@!${id}> `;

								// go to start of textarea
								f.setSelectionRange(0, 0);

								// insert mention
								document.execCommand("insertText", false, m);

								// select saved selection
								f.setSelectionRange(this.selection[0] + m.length, this.selection[1] + m.length);
							}
						}
						else {

							// default to current channel
							Module.DraftActions.saveDraft(t.props.channel.id, `<@!${id}> ${Module.Drafts.getDraft(t.props.channel.id)}`);
						}
					}
				}, "Reply"));

				// return modified return value
				return r;
			}});
			this.log("Patched render of Message");

			// patch channel text area render function
			Patches.textarea = BdApi.monkeyPatch(Component.ChannelTextArea.prototype, "render", {silent: true, instead: (d) => {

				// get this
				const t = d.thisObject;

				// declare blur handler
				const f = () => {

					// get dom node
					const e = ReactDOM.findDOMNode(d.thisObject).querySelector("textarea");

					// save focused textarea
					this.focused = e;

					// save selection
					this.selection = [e.selectionStart, e.selectionEnd];

					// set mode
					this.mode = true;

					// reset mode after 100ms
					setTimeout(() => {
						if (this.focused === e) {
							this.mode = false;
						}
					}, 100);
				};

				// check if text area has a blur handler
				if (t.props.onBlur) {

					// patch blur handler
					BdApi.monkeyPatch(t.props, "onBlur", {silent: true, before: f});
				}
				else {

					// assign blur handler
					t.props.onBlur = f;
				}

				// return render with modified this
				return d.originalMethod.apply(t);
			}});
			this.log("Patched onBlur of ChannelTextArea");

			// force update
			this.forceUpdateAll();

			// console output
			this.log("Enabled");
		}

		/**
		 * Plugin stop function
		 */
		stop() {

			// reset saved text area, selection & mode
			this.focused = null;
			this.selection = [0, 0];
			this.mode = false;

			// clear styles
			BdApi.clearCSS(this.getName());

			// revert all patches
			for (const k in Patches) {
				Patches[k]();
				delete Patches[k];
			}
			this.log("Unpatched all");

			// force update
			this.forceUpdateAll();

			// console output
			this.log("Disabled");
		}

		/**
		 * Force update the "Message" & "ChannelTextArea" Component State Nodes
		 */
		forceUpdateAll() {

			// force update messages
			for (const e of document.getElementsByClassName(Selector.Messages.message)) {
				const i = BdApi.getInternalInstance(e);
				i && i.return.stateNode.forceUpdate && i.return.stateNode.forceUpdate();
			}

			// force update channel text areas
			for (const e of document.getElementsByClassName(Selector.TextArea.channelTextArea)) {
				const i = BdApi.getInternalInstance(e);
				i && i.return.stateNode.forceUpdate && i.return.stateNode.forceUpdate();
			}
		}

	}
})();<commit_msg>Fix error during reply button insertion<commit_after>//META {"name": "BetterReplyer", "source": "https://github.com/Zerthox/BetterDiscord-Plugins/blob/master/v1/BetterReplyer.plugin.js"} *//

/**
 * @author Zerthox
 * @version 4.0.5
 * @return {class} BetterReplyer Plugin class
 */
const BetterReplyer = (() => {

	// Api constants
	const {React, ReactDOM} = BdApi;

	/** Module storage */
	const Module = {
		Constants: BdApi.findModuleByProps("Permissions"),
		Permissions: BdApi.findModuleByProps("getChannelPermissions"),
		Drafts: BdApi.findModuleByProps("getDraft"),
		DraftActions: BdApi.findModuleByProps("saveDraft"),
		Users: BdApi.findModuleByProps("getUser", "getCurrentUser")
	};

	/** Component storage */
	const Component = {
		Message: BdApi.findModuleByProps("Message", "MessageAvatar").Message,
		ChannelTextArea: BDV2.WebpackModules.findByDisplayName("ChannelTextArea")
	};

	/** Selector storage */
	const Selector = {
		Messages: BdApi.findModuleByProps("message", "container", "headerCozy"),
		TextArea: BdApi.findModuleByProps("channelTextArea")
	};

	/** Storage for Patches */
	const Patches = {};

	// return plugin class
	return class BetterReplyer {

		/**
		 * @return {string} Plugin name
		 */
		getName() {
			return "BetterReplyer";
		}

		/**
		 * @return {string} Plugin version
		 */
		getVersion() {
			return "4.0.5";
		}

		/**
		 * @return {ReactElement} Plugin author
		 */
		getAuthor() {
			return this.createAnchor({text: "Zerthox", url: "https://github.com/Zerthox"});
		}

		/**
		 * @return {ReactElement} Plugin description
		 */
		getDescription() {
			return React.createElement("span", {style: {"white-space": "pre-line"}},
				"Reply to people using their ID with a button.\n Inspired by ",
				this.createAnchor({text: "Replyer", url: "https://github.com/cosmicsalad/Discord-Themes-and-Plugins/blob/master/plugins/replyer.plugin.js"}),
				" by ",
				this.createAnchor({text: "@Hammmock#3110", url: "https://github.com/cosmicsalad"}),
				", ",
				this.createAnchor({text: "@Natsulus#0001", url: "https://github.com/Delivator"}),
				" & ",
				this.createAnchor({text: "@Zerebos#7790", url: "https://github.com/rauenzi"}),
				"."
			);
		}

		/**
		 * Log a message in Console
		 * @param {string} msg message
		 */
		log(msg) {
			console.log(`%c[${this.getName()}] %c(v${this.getVersion()})%c ${msg}`, "color: #3a71c1; font-weight: 700;", "color: #666; font-size: .8em;", "");
		}

		/**
		 * Create a new Anchor element based on Discord's Anchor Component
		 * @param {object} props Component props
		 * @param {string} props.text Anchor text
		 * @param {string} props.url Anchor url
		 * @return {ReactElement} New Anchor element
		 */
		createAnchor(props) {
			return React.createElement(BDV2.WebpackModules.findByDisplayName("Anchor"), {href: props.url, target: "_blank", title: props.url}, props.text);
		}

		/**
		 * Plugin constructor
		 */
		constructor() {
			this.focused = null;
			this.selection = [0, 0];
			this.mode = false;
		}

		/**
		 * Plugin start function
		 */
		start() {

			// inject styles
			BdApi.injectCSS(this.getName(),
				`/* BetterReplyer CSS */
				.replyer {
					position: relative;
					top: -1px;
					margin-left: 5px;
					padding: 3px 5px;
					background: rgba(0, 0, 0, 0.4);
					border-radius: 3px;
					color: #fff !important;
					font-size: 10px;
					text-transform: uppercase;
					cursor: pointer;
				}
				.${Selector.Messages.container.split(" ")[0]}:not(:hover) .replyer {
					visibility: hidden;
				}`
			);

			// patch "Message" component render function
			Patches.message = BdApi.monkeyPatch(Component.Message.prototype, "render", {silent: true, after: (d) => {

				// get this & old return value
				const t = d.thisObject,
					r = d.returnValue;

				// get message author id
				const id = t.props.message.author.id;

				// return unmodified if disabled, compact, no header or author is current user
				if (t.props.isDisabled || t.props.isCompact || !t.props.isHeader || id === Module.Users.getCurrentUser().id) {
					return r;
				}

				// get current channel permissions
				const p = Module.Permissions.getChannelPermissions(t.props.channel.id);

				// return unmodified if no permissions to send messages
				if (typeof p === "number" && !(p & Module.Constants.Permissions.SEND_MESSAGES)) {
					return r;
				}

				// find message header
				const h = [r.props.children].flat().find((e) => e.props && e.props.className === Selector.Messages.headerCozy);

				// find message header meta
				const m = h && [h.props.children].flat().find((e) => e.props && e.props.className === Selector.Messages.headerCozyMeta);

				// check if message header meta found
				if (m) {

					// get children
					const c = [m.props.children].flat();

					// push reply button
					c.push(React.createElement("span", {
						className: "replyer",
						onClick: () => {

							// get saved text area
							const f = this.focused;

							// check if text area saved
							if (f) {

								// focus textarea
								f.focus();

								// check mode
								if (this.mode) {

									// select saved selection
									f.setSelectionRange(this.selection[0], this.selection[1]);

									// insert mention
									document.execCommand("insertText", false, `<@!${id}>`);

									// update saved text area
									setTimeout(() => {
										this.focused = f;
									}, 100);
								}
								else {

									// get mention
									const m = `<@!${id}> `;

									// go to start of textarea
									f.setSelectionRange(0, 0);

									// insert mention
									document.execCommand("insertText", false, m);

									// select saved selection
									f.setSelectionRange(this.selection[0] + m.length, this.selection[1] + m.length);
								}
							}
							else {

								// default to current channel
								Module.DraftActions.saveDraft(t.props.channel.id, `<@!${id}> ${Module.Drafts.getDraft(t.props.channel.id)}`);
							}
						}
					}, "Reply"));

					// override children
					m.props.children = c;
				}

				// return modified return value
				return r;
			}});
			this.log("Patched render of Message");

			// patch "ChannelTextArea" component render function
			Patches.textarea = BdApi.monkeyPatch(Component.ChannelTextArea.prototype, "render", {silent: true, instead: (d) => {

				// get this
				const t = d.thisObject;

				// declare blur handler
				const f = () => {

					// get dom node
					const e = ReactDOM.findDOMNode(d.thisObject).querySelector("textarea");

					// save focused textarea
					this.focused = e;

					// save selection
					this.selection = [e.selectionStart, e.selectionEnd];

					// set mode
					this.mode = true;

					// reset mode after 100ms
					setTimeout(() => {
						if (this.focused === e) {
							this.mode = false;
						}
					}, 100);
				};

				// check if text area has a blur handler
				if (t.props.onBlur) {

					// patch blur handler
					BdApi.monkeyPatch(t.props, "onBlur", {silent: true, before: f});
				}
				else {

					// assign blur handler
					t.props.onBlur = f;
				}

				// return render with modified this
				return d.originalMethod.apply(t);
			}});
			this.log("Patched onBlur of ChannelTextArea");

			// force update
			this.forceUpdateAll();

			// console output
			this.log("Enabled");
		}

		/**
		 * Plugin stop function
		 */
		stop() {

			// reset saved text area, selection & mode
			this.focused = null;
			this.selection = [0, 0];
			this.mode = false;

			// clear styles
			BdApi.clearCSS(this.getName());

			// revert all patches
			for (const k in Patches) {
				Patches[k]();
				delete Patches[k];
			}
			this.log("Unpatched all");

			// force update
			this.forceUpdateAll();

			// console output
			this.log("Disabled");
		}

		/**
		 * Force update the "Message" & "ChannelTextArea" component state nodes
		 */
		forceUpdateAll() {

			// force update messages
			for (const e of document.getElementsByClassName(Selector.Messages.message)) {
				const i = BdApi.getInternalInstance(e);
				i && i.return.stateNode.forceUpdate && i.return.stateNode.forceUpdate();
			}

			// force update channel text areas
			for (const e of document.getElementsByClassName(Selector.TextArea.channelTextArea)) {
				const i = BdApi.getInternalInstance(e);
				i && i.return.stateNode.forceUpdate && i.return.stateNode.forceUpdate();
			}
		}

	};
})();<|endoftext|>


<commit_before>import languagesUtil from './LanguagesUtil.js';
import LANGUAGE_COLORS from '../constants/LanguageColors.js';
import {expect} from 'chai';

describe('LanguagesUtil', function () {
  let repos = [
    { primaryLanguage: 'JS'},
    { primaryLanguage: 'JS'},
    { primaryLanguage: 'PHP'},
    { primaryLanguage: 'Java'},
    { primaryLanguage: 'Scala'}
  ];

  describe('#getLanguagesFromRepos method', function () {
    it('should return an arry of languages', function () {
      let languages = languagesUtil.getLanguagesFromRepos(repos);
      expect(languages.length).to.equal(4);
    });
  });

  describe('#guessLanguages method', function () {
    it('should return an array of languages, ordered and with extra metadata attached to each language', function () {
      let languages = languagesUtil.guessLanguages(repos);
      expect(languages.length).to.equal(4);
      expect(languages[0].name).to.equal('JS');
      expect(languages[0].color).to.not.be.undefined;
      expect(languages[0].percentage).to.not.be.undefined;
    });
  });

  describe('#getLanguageColor method', function () {
    it('should return an color for the language name or the default one', function () {
      let color = languagesUtil.getLanguageColor('JS');
      expect(color).not.to.be.undefined;
      expect(color).not.to.be.equal(LANGUAGE_COLORS.DEFAULT);

      let color2 = languagesUtil.getLanguageColor('FOOBARLANGUAGE');
      expect(color2).to.be.equal(LANGUAGE_COLORS.DEFAULT);
    });
  });

});
<commit_msg>fix tests<commit_after>import languagesUtil from './LanguagesUtil.js';
import LANGUAGE_COLORS from '../constants/LanguageColors.js';
import {expect} from 'chai';

describe('LanguagesUtil', function () {
  let repos = [
    { primaryLanguage: 'JS'},
    { primaryLanguage: 'JS'},
    { primaryLanguage: 'PHP'},
    { primaryLanguage: 'Java'},
    { primaryLanguage: 'Scala'}
  ];

  describe('#getLanguagesFromRepos method', function () {
    it('should return an arry of languages', function () {
      let languages = languagesUtil.getLanguagesFromRepos(repos);
      expect(languages.length).to.equal(4);
    });
  });

  describe('#guessLanguages method', function () {
    it('should return an array of languages, ordered and with extra metadata attached to each language', function () {
      let languages = languagesUtil.guessLanguages(repos);
      expect(languages.length).to.equal(4);
      expect(languages[0].name).to.equal('JS');
      expect(languages[0].color).to.not.be.undefined;
      expect(languages[0].percentage).to.not.be.undefined;
    });
  });

  describe('#getLanguageColor method', function () {
    it('should return an color for the language name or the default one', function () {
      let color = languagesUtil.getLanguageColor('JavaScript');
      expect(color).not.to.be.undefined;
      expect(color).not.to.be.equal(LANGUAGE_COLORS.DEFAULT);

      let color2 = languagesUtil.getLanguageColor('FOOBARLANGUAGE');
      expect(color2).to.be.equal(LANGUAGE_COLORS.DEFAULT);
    });
  });

});
<|endoftext|>


<commit_before>import uuid from 'uuid'
import { retrieve, insert, amend, partialAmend, search, deactivate, reactivate } from './assets.js'
import Asset from '../../assets/Asset/asset.js'
import * as api from '../../exports/api'

api.config({
  stage: 'staging',
  token: process.env.API_TOKEN
})

jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000

describe('utils/assets', () => {
  describe('retrieve', () => {
    test('with promise', callback => {
      let promise = retrieve({AMId: 1})
      expect(promise).toBeInstanceOf(Promise)
      promise.then(assets => {
        expect(Array.isArray(assets)).toBeTruthy()
        if (assets.length > 0) expect(assets[0]).toBeInstanceOf(Asset)
        callback()
      })
      .catch(err => console.error(err))
    })
  })

  describe('insert', () => {
    test('with promise', () => {
      let promise = insert({}).catch(error => {})
      expect(promise).toBeInstanceOf(Promise)
    })

    it.skip('should insert', done => {
      const asset = {
        description: 'testAsset',
        assetType: 'Equity',
        assetManagerId: 1,
        assetId: uuid().substring(0, 10)
      }
      insert({ AMId: 1, asset })
        .then(res => {
          expect(res).toEqual(expect.objectContaining(asset))
          done()
        })
        .catch(err => {
          console.error(err)
        })
    })
  })

  describe('amend', () => {
    test('with promise', () => {
      let promise = amend({}).catch(error => {})
      expect(promise).toBeInstanceOf(Promise)
    })
    it.only('amends', async done => {
      let f
      let res = await retrieve({ AMId: 1 })
      if (res.length === 0) {
        console.error('amend: Results is empty, force fail after timeout.')
        return
      }
      res = res[0]
      if (res.assetStatus === 'Inactive') {
        res = await reactivate({ AMId: res.assetManagerId, resourceId: res.assetId })
      }
      f = res.fungible
      res.fungible = !f
      res = await amend({ asset: res, AMId: res.assetManagerId, resourceId: res.assetId })
      expect(res.fungible).toEqual(!f)
      done()
    })
  })

  describe('partialAmend', () => {
    test('with promise', () => {
      let promise = partialAmend({}).catch(error => {})
      expect(promise).toBeInstanceOf(Promise)
    })
    test('partial amends', async done => {
      const desc = uuid().substring(0, 20)
      let res = await retrieve({ AMId: 1 })
      if (res.length === 0) {
        console.error('partialAmend: Results is empty, force fail after timeout.')
        return
      }
      res = res[0]
      res = await partialAmend({ changes: { description: desc }, AMId: res.assetManagerId, resourceId: res.assetId })
      expect(res.description).toEqual(desc)
      done()
    })
  })

  describe('search', () => {
    it('searches', async done => {
      const query = { assetClasses: ['Asset', 'ForeignExchange'] }
      let res = await search({ AMId: 1, query })
      if (Array.isArray(res) && res.length === 0) {
        console.warn('search: Results is empty, force fail after timeout.')
      } else if (Array.isArray(res) && res.length > 0) {
        res = res[0]
        expect(res.assetClass).toEqual(expect.stringMatching(/(Asset|ForeignExchange)/))
        done()
      } else {
        expect(res.assetClass).toEqual(expect.stringMatching(/(Asset|ForeignExchange)/))
        done()
      }
    })
  })

  describe('deactivate', () => {

    test('with promise', () => {
      let promise = deactivate({}).catch(error => {})
      expect(promise).toBeInstanceOf(Promise)
    })

    it('deactivates an active Asset', async done => {
      let res = await retrieve({ AMId: 1 })
      if (res.length === 0) {
        console.error('deactivate: Results is empty, force fail after timeout.')
        return
      }
      res = res[0]
      if (res.assetStatus === 'Inactive') {
        res = await reactivate({ AMId: res.assetManagerId, resourceId: res.assetId })
      }
      expect(res.assetStatus).toEqual('Active')
      res = await deactivate({ AMId: res.assetManagerId, resourceId: res.assetId })
      expect(res.assetStatus).toEqual('Inactive')
      await reactivate({ AMId: res.assetManagerId, resourceId: res.assetId })
      done()
    })
  })
})
<commit_msg>Remove the default timeout for now as it seems to work better with the default timeout. May need to revisit this when running all the tests.<commit_after>import uuid from 'uuid'
import { retrieve, insert, amend, partialAmend, search, deactivate, reactivate } from './assets.js'
import Asset from '../../assets/Asset/asset.js'
import * as api from '../../exports/api'

api.config({
  stage: 'staging',
  token: process.env.API_TOKEN
})

// jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000

describe('utils/assets', () => {
  describe('retrieve', () => {
    test('with promise', callback => {
      let promise = retrieve({AMId: 1})
      expect(promise).toBeInstanceOf(Promise)
      promise.then(assets => {
        expect(Array.isArray(assets)).toBeTruthy()
        if (assets.length > 0) expect(assets[0]).toBeInstanceOf(Asset)
        callback()
      })
      .catch(err => console.error(err))
    })
  })

  describe('insert', () => {
    test('with promise', () => {
      let promise = insert({}).catch(error => {})
      expect(promise).toBeInstanceOf(Promise)
    })

    it.skip('should insert', done => {
      const asset = {
        description: 'testAsset',
        assetType: 'Equity',
        assetManagerId: 1,
        assetId: uuid().substring(0, 10)
      }
      insert({ AMId: 1, asset })
        .then(res => {
          expect(res).toEqual(expect.objectContaining(asset))
          done()
        })
        .catch(err => {
          console.error(err)
        })
    })
  })

  describe('amend', () => {
    test('with promise', () => {
      let promise = amend({}).catch(error => {})
      expect(promise).toBeInstanceOf(Promise)
    })
    it('amends', async done => {
      let f
      let res = await retrieve({ AMId: 1 })
      if (res.length === 0) {
        console.error('amend: Results is empty, force fail after timeout.')
        return
      }
      res = res[0]
      if (res.assetStatus === 'Inactive') {
        res = await reactivate({ AMId: res.assetManagerId, resourceId: res.assetId })
      }
      f = res.fungible
      res.fungible = !f
      res = await amend({ asset: res, AMId: res.assetManagerId, resourceId: res.assetId })
      expect(res.fungible).toEqual(!f)
      done()
    })
  })

  describe('partialAmend', () => {
    test('with promise', () => {
      let promise = partialAmend({}).catch(error => {})
      expect(promise).toBeInstanceOf(Promise)
    })
    test('partial amends', async done => {
      const desc = uuid().substring(0, 20)
      let res = await retrieve({ AMId: 1 })
      if (res.length === 0) {
        console.error('partialAmend: Results is empty, force fail after timeout.')
        return
      }
      res = res[0]
      res = await partialAmend({ changes: { description: desc }, AMId: res.assetManagerId, resourceId: res.assetId })
      expect(res.description).toEqual(desc)
      done()
    })
  })

  describe('search', () => {
    it('searches', async done => {
      const query = { assetClasses: ['Asset', 'ForeignExchange'] }
      let res = await search({ AMId: 1, query })
      if (Array.isArray(res) && res.length === 0) {
        console.error('search: Results is empty, force fail after timeout.')
      } else if (Array.isArray(res) && res.length > 0) {
        res = res[0]
        expect(res.assetClass).toEqual(expect.stringMatching(/(Asset|ForeignExchange)/))
        done()
      } else {
        expect(res.assetClass).toEqual(expect.stringMatching(/(Asset|ForeignExchange)/))
        done()
      }
    })
  })

  describe('deactivate', () => {

    test('with promise', () => {
      let promise = deactivate({}).catch(error => {})
      expect(promise).toBeInstanceOf(Promise)
    })

    it('deactivates an active Asset', async done => {
      let res = await retrieve({ AMId: 1 })
      if (res.length === 0) {
        console.error('deactivate: Results is empty, force fail after timeout.')
        return
      }
      res = res[0]
      if (res.assetStatus === 'Inactive') {
        res = await reactivate({ AMId: res.assetManagerId, resourceId: res.assetId })
      }
      expect(res.assetStatus).toEqual('Active')
      res = await deactivate({ AMId: res.assetManagerId, resourceId: res.assetId })
      expect(res.assetStatus).toEqual('Inactive')
      await reactivate({ AMId: res.assetManagerId, resourceId: res.assetId })
      done()
    })
  })
})
<|endoftext|>


<commit_before>/* global angular, _, $, d3 */

angular.module('dci')
	.controller('sankey', function () {})
	.config(function ($stateProvider, $urlRouterProvider) {
			$stateProvider.state('dci.sankey', {
				url: '/sankey',
				template:'

',
				resolve: {
					pitypes:($http) => $http.get('../mitm_out/pi_by_host.json').then((x) => x.data),
					hosts: ($http) => $http.get('../mitm_out/host_by_app.json').then((x) => x.data),
					details: ($http) => $http.get('../mitm_out/company_details.json').then((x) => x.data),
					data: ($http) => $http.get('../mitm_out/data_all.json').then((x) => x.data)
				},
				controller:function($scope, pitypes, hosts, details, data, utils, $stateParams) {
					window._s = $scope;
					$scope.hosts = hosts;
					$scope.pitypes = pitypes;
					$scope.details = details;

					var ADD_APP_LEVEL = true, // add app level
						allData = data,
						margin = {top: 1, right: 1, bottom: 6, left: 1},
						width = 960 - margin.left - margin.right,
						height = 800 - margin.top - margin.bottom,
						app = $scope.app = $stateParams.app,
						app_id = utils.toAppId(app),
						appcompany = $scope.appcompany = data[0].company;

					data = data.filter((x) => x.app === $stateParams.app);

					var formatNumber = d3.format(",.0f"),
						format = function(d) { return formatNumber(d) + " TWh"; },
						color = d3.scale.category20();

					var svg = d3.select("#sankey-chart").append("svg")
					    .attr("width", width + margin.left + margin.right)
					    .attr("height", height + margin.top + margin.bottom)
					  .append("g")
					  	.attr("class","root")
					    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

					var sankey = d3.sankey()
					    .nodeWidth(15)
					    .nodePadding(10)
					    .size([width, height]),
					    path = sankey.link(),
					    link,
						dragmove = function(d) {
						    d3.select(this).attr("transform", "translate(" + d.x + "," + (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")");
						    sankey.relayout();
						    link.attr("d", path);
					    };

					if (!data.length) { $scope.error = 'no data for app ' + $stateParams.app; }
					var recompute = () => {

						var isPDCI = $scope.pdciApps && $scope.pdciApps.length || false,
							pdciApps = isPDCI ? $scope.pdciApps : [],
							apps = $scope.apps = (isPDCI ? _.union(pdciApps,[app]) : [app]),
							c2pi = $scope.c2pi = utils.makeCompany2pi(app, data, hosts, pitypes, 0),
							cat2c2pi = $scope.categories = utils.makeCategories(appcompany, details, c2pi),
							aTc = $scope.aTc = utils.makeApp2company(apps, data, c2pi, hosts, 0),
							app_ids = _.keys(aTc);

						console.info("isPDCI is ", isPDCI);

						// clear from last drawing
						$("#sankey-chart").find("svg g.root").children().remove(); // something like svg.remove(); would be more elegant

						if (isPDCI) {
							// redefine data - to include all pdci apps as well
							data = $scope.data = allData.filter((x) => x.app === app || $scope.pdciApps.indexOf(x.app) >= 0);
							c2pi = $scope.c2pi = utils.makePDCIc2pi(apps, data, hosts, pitypes, 0);
							cat2c2pi = $scope.categories = utils.makeCategories(appcompany, details, c2pi);
							aTc = $scope.aTc = utils.makeApp2company(apps, data, c2pi, hosts, 0);
							app_ids = _.keys(aTc);
						}

						// let's start making nodes
						// start with the pitypes
						var OTHERPITYPE = 'OTHER_PI',
							pitypes_set = _(pitypes).values().flatten().uniq().value(), // .concat([OTHERPITYPE]),
							nodemap = $scope.nodemap = {},
							nodes = $scope.nodes = [],
							links = $scope.links = [],
							pushNode = (id, label, isapp) => {
								console.log('pushing node ', id);
								var l = nodes.length;
								nodes.push({name:id, label:label, isapp:isapp});
								nodemap[id] = l;
								return l;
							},
							pushLink = (from, to, width, isApp) => {
								var l = links.length;
								links.push({source:from, target:to, value:width || 1, isapp:isApp});
								return l;
							},
							pilabels = utils.pilabels,
							a2pi = (aid) => _.flatten(aTc[aid].map((company) => c2pi[company])),
							a2cat = $scope.a2cat = (aid) => _.keys(cat2c2pi).filter((cat) => _.intersection(_.keys(cat2c2pi[cat] || {}), aTc[aid]).length > 0);

						////////////////////// nodes /////////////////////////
						// 1. register the apps as nodes
						if (ADD_APP_LEVEL) { apps.map((appname) => pushNode(utils.toAppId(appname),appname,appname===app)); }
						// pitypes
						pitypes_set.map((pitype) => pushNode(pitype, pilabels[pitype], a2pi(app_id).indexOf(pitype) >= 0));
						// 2. companies
						_.keys(c2pi).map((c) => pushNode(c, c, aTc[app_id].indexOf(c) >= 0));
						// 3. categories
						_.keys($scope.categories).map((cname) => pushNode(cname, cname, a2cat(app_id).indexOf(cname) >= 0));

						///////////////// app -> company links ////////////////////////////////
						if (ADD_APP_LEVEL) {
							// app -> pitype count
							app_ids.map((aid) => {
								// first compile { pitype -> count  } to determine thickness
								console.info('app adding app level ', aid, aTc[aid]);

								// apps out -> 1 -> company, company -> pi...
								//
								var pi2c = _.flatten(aTc[aid].map((c) => c2pi[c]))
									.reduce((picounts,pit) => {
										picounts[pit] = picounts[pit] && picounts[pit]+1 || 1;
										return picounts;
									}, {}),
									app_nid = nodemap[aid];

								_.map(pi2c, (count, pi_type) => {
									var pit_id = nodemap[pi_type];
									console.info('adding app link of ', aid, 'id: ', app_nid, ' → ', pi_type, ' id:', pit_id, ' ~ count: 	', count);
									pushLink(app_nid, pit_id, count, aid === app_id);
								});
							});
						}

						//////////////// pitype -> company links /////////////////
						_.toPairs($scope.c2pi).map((pair) => {
							var company = pair[0],
								pitypes = pair[1],
								company_nid = nodemap[company];

							// find the weight, find all apps that lead to this pi
							var n_apps = app_ids.filter((a)=> aTc[a].indexOf(company) >= 0).length;

							// add pitype -> company
							pitypes.map((pitype) => {
								var pitype_id = nodemap[pitype];
								console.info('adding pitype-company link ', pitype, pitype_id, '→', company, company_nid);
								pushLink(pitype_id, company_nid, n_apps, aTc[app_id].indexOf(company) >= 0);
							});
							// disable "other"
							// if ($scope.c2pi[company].length === 0) {
							// 	console.info('adding other_PI link ', nodemap[OTHERPITYPE], ' -> ', company, ' ', company_nid);
							// 	pushLink(nodemap[OTHERPITYPE], company_nid);
							// }
						});
						//////////////// company -> category links ///////////////
						var pic_weight = (company) => c2pi[company].length;
						_.map($scope.categories, (c2pi, category) => {
							var category_nid = nodemap[category];
							_.map(c2pi,(pitypes, company) => {
								var company_nid = nodemap[company],
									relates_to_app = aTc[app_id].indexOf(company) >= 0;
								if (pitypes.length > 0) {
									var pww = pic_weight(company);
									console.info("adding pitype link ", company, '→', category);
									pushLink(company_nid, category_nid, pww, relates_to_app);
								}
							});
						});

						console.log('old nodes ', nodes.length, JSON.stringify({nodes:nodes}));
						console.log('old links ', links.length, JSON.stringify({links:links}));

						// kill nodes that don't have any links
						var newnodes = _.filter(nodes, (n,i) => links.filter((l) => l.source === i || l.target === i).length > 0),
							newmap = $scope.newmap = newnodes.reduce((m, i) => {
								m[i.name] = newnodes.indexOf(i);
								return m;
							}, {}),
							newlinks = $scope.newlinks = links.map((oldlink) =>_.extend({}, oldlink, {
								source: newmap[nodes[oldlink.source].name],
								target: newmap[nodes[oldlink.target].name]
							}));

						console.log('new nodes ', newnodes.length, JSON.stringify({nodes:newnodes}));
						console.log('new links ', newlinks.length, JSON.stringify({links:newlinks}));
						console.log('do it one ');

						// do it
						sankey.nodes(newnodes)
						    .links(newlinks)
						    .layout(128);

						console.log('do it link ');

						link = svg.append("g").selectAll(".link")
						  .data(newlinks)
						  .enter().append("path")
						  .attr("class", (d) => "link " + (isPDCI ? "pdci " : " ") + (d.isapp ? "isapp " : " "))
						  .attr("d", path)
						  .style("stroke-width", (d) => Math.max(1, d.dy))
						  .sort((a, b) => b.dy - a.dy);

						console.log('do it app ');

						link.append("title")
					    	.text(function(d) { return d.source.name + " → " + d.target.name + " ("+d.value+")"; });

						console.log('do it node ');

						var node = svg.append("g").selectAll(".node")
							.data(newnodes)
							.enter().append("g")
								.attr("class", (d) => "node " + (isPDCI ? "pdci " : " ") + (d.isapp ? "isapp " : " "))
								.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
							.call(d3.behavior.drag()
						  		.origin(function(d) { return d; })
						  		.on("dragstart", function() { this.parentNode.appendChild(this); })
						  		.on("drag", dragmove));

						console.log('do it nodeapp ');

						node.append("rect")
						    .attr("height", function(d) { return d.dy; })
						    .attr("width", sankey.nodeWidth())
						    .style("fill", function(d) { return d.color = color(d.name.replace(/ .*/, "")); })
						    .style("stroke", function(d) { return d3.rgb(d.color).darker(2); })
						    .append("title")
						    .text(function(d) { return d.name + "\n" + format(d.value); });

						console.log('do it nodeapptext ');

						node.append("text")
						    .attr("x", -6)
						    .attr("y", function(d) { return d.dy / 2; })
						    .attr("dy", ".35em")
						    .attr("text-anchor", "end")
						    .attr("transform", null)
						    .text(function(d) { return d.label || d.name; })
						    .filter(function(d) { return d.x < width / 2; })
						    .attr("x", 6 + sankey.nodeWidth())
						    .attr("text-anchor", "start");

						console.log('do it done ');

						};

					if (!appcompany) { $scope.error = 'Captured data for ' + app + ' is in old data format without company field'; }
					if (!hosts[$scope.app]) { $scope.error = 'No hosts known for app'; }

					$scope.size = (l) => _.keys(l).length;
					// $scope.$watch('app', () => { if (app) { recompute(); } });
					recompute();
					$scope.$watch('pdciApps', recompute);
					console.info('sankey');
				}
		}); // controller
	});<commit_msg>now with better colouring pdci/dci<commit_after>/* global angular, _, $, d3 */

angular.module('dci')
	.controller('sankey', function () {})
	.config(function ($stateProvider, $urlRouterProvider) {
			$stateProvider.state('dci.sankey', {
				url: '/sankey',
				template:'

',
				resolve: {
					pitypes:($http) => $http.get('../mitm_out/pi_by_host.json').then((x) => x.data),
					hosts: ($http) => $http.get('../mitm_out/host_by_app.json').then((x) => x.data),
					details: ($http) => $http.get('../mitm_out/company_details.json').then((x) => x.data),
					data: ($http) => $http.get('../mitm_out/data_all.json').then((x) => x.data)
				},
				controller:function($scope, pitypes, hosts, details, data, utils, $stateParams) {
					window._s = $scope;
					$scope.hosts = hosts;
					$scope.pitypes = pitypes;
					$scope.details = details;

					var ADD_APP_LEVEL = true, // add app level
						allData = data,
						margin = {top: 1, right: 1, bottom: 6, left: 1},
						width = $('body').width() - 140, // 960 - margin.left - margin.right,
						height = $('body').height() - 140, // 800 - margin.top - margin.bottom,
						app = $scope.app = $stateParams.app,
						app_id = utils.toAppId(app),
						appcompany = $scope.appcompany = data[0].company;

					data = data.filter((x) => x.app === $stateParams.app);

					var formatNumber = d3.format(",.0f"),
						format = function(d) { return formatNumber(d) + " TWh"; },
						color = d3.scale.category20();

					var svg = d3.select("#sankey-chart").append("svg")
					    .attr("width", width + margin.left + margin.right)
					    .attr("height", height + margin.top + margin.bottom)
					  .append("g")
					  	.attr("class","root")
					    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

					var sankey = d3.sankey()
					    .nodeWidth(15)
					    .nodePadding(10)
					    .size([width, height]),
					    path = sankey.link(),
					    link,
						dragmove = function(d) {
						    d3.select(this).attr("transform", "translate(" + d.x + "," + (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")");
						    sankey.relayout();
						    link.attr("d", path);
					    };

					if (!data.length) { $scope.error = 'no data for app ' + $stateParams.app; }
					var recompute = () => {

						var isPDCI = $scope.pdciApps && $scope.pdciApps.length || false,
							pdciApps = isPDCI ? $scope.pdciApps : [],
							apps = $scope.apps = (isPDCI ? _.union(pdciApps,[app]) : [app]),
							c2pi = $scope.c2pi = utils.makeCompany2pi(app, data, hosts, pitypes, 0),
							cat2c2pi = $scope.categories = utils.makeCategories(appcompany, details, c2pi),
							aTc = $scope.aTc = utils.makeApp2company(apps, data, c2pi, hosts, 0),
							app_ids = _.keys(aTc);

						console.info("isPDCI is ", isPDCI);

						// clear from last drawing
						$("#sankey-chart").find("svg g.root").children().remove(); // something like svg.remove(); would be more elegant

						if (isPDCI) {
							// redefine data - to include all pdci apps as well
							data = $scope.data = allData.filter((x) => x.app === app || $scope.pdciApps.indexOf(x.app) >= 0);
							c2pi = $scope.c2pi = utils.makePDCIc2pi(apps, data, hosts, pitypes, 0);
							cat2c2pi = $scope.categories = utils.makeCategories(appcompany, details, c2pi);
							aTc = $scope.aTc = utils.makeApp2company(apps, data, c2pi, hosts, 0);
							app_ids = _.keys(aTc);
						}

						// let's start making nodes
						// start with the pitypes
						var OTHERPITYPE = 'OTHER_PI',
							pitypes_set = _(pitypes).values().flatten().uniq().value(), // .concat([OTHERPITYPE]),
							nodemap = $scope.nodemap = {},
							nodes = $scope.nodes = [],
							links = $scope.links = [],
							pushNode = (id, label, isapp) => {
								console.log('pushing node ', id);
								var l = nodes.length;
								nodes.push({name:id, label:label, isapp:isapp});
								nodemap[id] = l;
								return l;
							},
							pushLink = (from, to, width, isApp) => {
								var l = links.length;
								links.push({source:from, target:to, value:width || 1, isapp:isApp});
								return l;
							},
							pilabels = utils.pilabels,
							a2pi = (aid) => _.flatten(aTc[aid].map((company) => c2pi[company])),
							a2cat = $scope.a2cat = (aid) => _.keys(cat2c2pi).filter((cat) => _.intersection(_.keys(cat2c2pi[cat] || {}), aTc[aid]).length > 0);

						////////////////////// nodes /////////////////////////
						// 1. register the apps as nodes
						if (ADD_APP_LEVEL) { apps.map((appname) => pushNode(utils.toAppId(appname),appname,appname===app)); }
						// pitypes
						pitypes_set.map((pitype) => pushNode(pitype, pilabels[pitype], a2pi(app_id).indexOf(pitype) >= 0));
						// 2. companies
						_.keys(c2pi).map((c) => pushNode(c, c, aTc[app_id].indexOf(c) >= 0));
						// 3. categories
						_.keys($scope.categories).map((cname) => pushNode(cname, cname, a2cat(app_id).indexOf(cname) >= 0));

						///////////////// app -> company links ////////////////////////////////
						if (ADD_APP_LEVEL) {
							// app -> pitype count
							app_ids.map((aid) => {
								// first compile { pitype -> count  } to determine thickness
								console.info('app adding app level ', aid, aTc[aid]);

								// apps out -> 1 -> company, company -> pi...
								//
								var pi2c = _.flatten(aTc[aid].map((c) => c2pi[c]))
									.reduce((picounts,pit) => {
										picounts[pit] = picounts[pit] && picounts[pit]+1 || 1;
										return picounts;
									}, {}),
									app_nid = nodemap[aid];

								_.map(pi2c, (count, pi_type) => {
									var pit_id = nodemap[pi_type];
									console.info('adding app link of ', aid, 'id: ', app_nid, ' → ', pi_type, ' id:', pit_id, ' ~ count: 	', count);
									pushLink(app_nid, pit_id, count, aid === app_id);
								});
							});
						}

						//////////////// pitype -> company links /////////////////
						_.toPairs($scope.c2pi).map((pair) => {
							var company = pair[0],
								pitypes = pair[1],
								company_nid = nodemap[company];

							// find the weight, find all apps that lead to this pi
							var n_apps = app_ids.filter((a)=> aTc[a].indexOf(company) >= 0).length;

							// add pitype -> company
							pitypes.map((pitype) => {
								var pitype_id = nodemap[pitype];
								console.info('adding pitype-company link ', pitype, pitype_id, '→', company, company_nid);
								pushLink(pitype_id, company_nid, n_apps, aTc[app_id].indexOf(company) >= 0);
							});
							// disable "other"
							// if ($scope.c2pi[company].length === 0) {
							// 	console.info('adding other_PI link ', nodemap[OTHERPITYPE], ' -> ', company, ' ', company_nid);
							// 	pushLink(nodemap[OTHERPITYPE], company_nid);
							// }
						});
						//////////////// company -> category links ///////////////
						var pic_weight = (company) => c2pi[company].length;
						_.map($scope.categories, (c2pi, category) => {
							var category_nid = nodemap[category];
							_.map(c2pi,(pitypes, company) => {
								var company_nid = nodemap[company],
									relates_to_app = aTc[app_id].indexOf(company) >= 0;
								if (pitypes.length > 0) {
									var pww = pic_weight(company);
									console.info("adding pitype link ", company, '→', category);
									pushLink(company_nid, category_nid, pww, relates_to_app);
								}
							});
						});

						console.log('old nodes ', nodes.length, JSON.stringify({nodes:nodes}));
						console.log('old links ', links.length, JSON.stringify({links:links}));

						// kill nodes that don't have any links
						var newnodes = _.filter(nodes, (n,i) => links.filter((l) => l.source === i || l.target === i).length > 0),
							newmap = $scope.newmap = newnodes.reduce((m, i) => {
								m[i.name] = newnodes.indexOf(i);
								return m;
							}, {}),
							newlinks = $scope.newlinks = links.map((oldlink) =>_.extend({}, oldlink, {
								source: newmap[nodes[oldlink.source].name],
								target: newmap[nodes[oldlink.target].name]
							}));

						console.log('new nodes ', newnodes.length, JSON.stringify({nodes:newnodes}));
						console.log('new links ', newlinks.length, JSON.stringify({links:newlinks}));
						console.log('do it one ');

						// do it
						sankey.nodes(newnodes)
						    .links(newlinks)
						    .layout(128);

						console.log('do it link ');

						link = svg.append("g").selectAll(".link")
						  .data(newlinks)
						  .enter().append("path")
						  .attr("class", (d) => "link " + (isPDCI ? "pdci " : " ") + (d.isapp ? "isapp " : " "))
						  .attr("d", path)
						  .style("stroke-width", (d) => Math.max(1, d.dy))
						  .sort((a, b) => b.dy - a.dy);

						console.log('do it app ');

						link.append("title")
					    	.text(function(d) { return d.source.name + " → " + d.target.name + " ("+d.value+")"; });

						console.log('do it node ');

						var node = svg.append("g").selectAll(".node")
							.data(newnodes)
							.enter().append("g")
								.attr("class", (d) => "node " + (isPDCI ? "pdci " : " ") + (d.isapp ? "isapp " : " "))
								.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
							.call(d3.behavior.drag()
						  		.origin(function(d) { return d; })
						  		.on("dragstart", function() { this.parentNode.appendChild(this); })
						  		.on("drag", dragmove));

						console.log('do it nodeapp ');

						node.append("rect")
						    .attr("height", function(d) { return d.dy; })
						    .attr("width", sankey.nodeWidth())
						    .style("fill", function(d) { return d.color = color(d.name.replace(/ .*/, "")); })
						    .style("stroke", function(d) { return d3.rgb(d.color).darker(2); })
						    .append("title")
						    .text(function(d) { return d.name + "\n" + format(d.value); });

						console.log('do it nodeapptext ');

						node.append("text")
						    .attr("x", -6)
						    .attr("y", function(d) { return d.dy / 2; })
						    .attr("dy", ".35em")
						    .attr("text-anchor", "end")
						    .attr("transform", null)
						    .text(function(d) { return d.label || d.name; })
						    .filter(function(d) { return d.x < width / 2; })
						    .attr("x", 6 + sankey.nodeWidth())
						    .attr("text-anchor", "start");

						console.log('do it done ');

						};

					if (!appcompany) { $scope.error = 'Captured data for ' + app + ' is in old data format without company field'; }
					if (!hosts[$scope.app]) { $scope.error = 'No hosts known for app'; }

					$scope.size = (l) => _.keys(l).length;
					// $scope.$watch('app', () => { if (app) { recompute(); } });
					recompute();
					$scope.$watch('pdciApps', recompute);
					console.info('sankey');
				}
		}); // controller
	});<|endoftext|>


<commit_before>'use strict';
var $ = require('jquery');
var NodeGit = require('nodegit');
var Checkout = NodeGit.Checkout;
var Reset = NodeGit.Reset;

var AtomGitReplayView = function (serializedState) {
  this.element = document.createElement('div');
  this.element.classList.add('atom-git-replay');

  $(this.element).on('click', '.commit', function (e) {
    var el = $(e.target);

    var commitId = el.data('id');

    NodeGit.Repository.open(path.resolve(atom.project.getPaths()[0]))
      .then(function(repo) {
        Checkout
          .tree(repo, commitId, {
            checkoutStrategy: Checkout.STRATEGY.SAFE_CREATE
          })
          .then(function() {
            return repo.setHeadDetached(commitId, repo.defaultSignature, "Checkout: HEAD " + commitId);
          })
          .then(function (result) {
            if (result) {
              return Reset.reset(repo, commitId, Reset.TYPE.HARD)
            } else {
              throw new Error(result);
            }
          })
          .then(function (result) {
            console.log('reset: ', result ? 'successful' : 'failed');
          });
    });
  });
};

AtomGitReplayView.prototype.serialize = function() {
};

AtomGitReplayView.prototype.destroy = function() {
  return this.element.remove();
};

AtomGitReplayView.prototype.getElement = function() {
  return this.element;
};

AtomGitReplayView.prototype.updateElement = function(commits) {
  var _this = this;

  $(_this.getElement()).html('');

  commits.forEach(function (commit) {
    var commit = `
      <button
        class="commit btn btn-default"
        data-id="${commit.id()}"
      >
        ${commit.message()}
      </button>
    `;

    $(_this.getElement()).append(commit);
  });

  return this.element;
};

module.exports = AtomGitReplayView;
<commit_msg>point to HEAD's commit<commit_after>'use strict';
var $ = require('jquery');
var NodeGit = require('nodegit');
var Checkout = NodeGit.Checkout;
var Reset = NodeGit.Reset;

var AtomGitReplayView = function (serializedState) {
  this.element = document.createElement('div');
  this.element.classList.add('atom-git-replay');

  $(this.element).on('click', '.commit', function (e) {
    var el = $(e.target);

    var commitId = el.data('id');

    NodeGit.Repository.open(path.resolve(atom.project.getPaths()[0]))
      .then(function(repo) {
        Checkout
          .tree(repo, commitId, {
            checkoutStrategy: Checkout.STRATEGY.SAFE_CREATE
          })
          .then(function() {
            return repo.setHeadDetached(commitId, repo.defaultSignature, "Checkout: HEAD " + commitId);
          })
          .then(function (result) {
            if (result) {
              return Reset.reset(repo, repo.getHeadCommit(), Reset.TYPE.HARD)
            }
          })
          .then(function (result) {
            console.log('reset: ', result ? 'successful' : 'failed');
          });
    });
  });
};

AtomGitReplayView.prototype.serialize = function() {
};

AtomGitReplayView.prototype.destroy = function() {
  return this.element.remove();
};

AtomGitReplayView.prototype.getElement = function() {
  return this.element;
};

AtomGitReplayView.prototype.updateElement = function(commits) {
  var _this = this;

  $(_this.getElement()).html('');

  commits.forEach(function (commit) {
    var commit = `
      <button
        class="commit btn btn-default"
        data-id="${commit.id()}"
      >
        ${commit.message()}
      </button>
    `;

    $(_this.getElement()).append(commit);
  });

  return this.element;
};

module.exports = AtomGitReplayView;
<|endoftext|>