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

'use strict';

const {getCppTypeForAnnotation, toSafeCppString} = require('./CppHelpers.js');

import type {PropTypeShape, SchemaType} from '../../CodegenSchema';

// File path -> contents
type FilesOutput = Map<string, string>;

const template = `
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */
#pragma once

::_IMPORTS_::

namespace facebook {
namespace react {

::_COMPONENT_CLASSES_::

} // namespace react
} // namespace facebook
`;

const classTemplate = `
::_ENUMS_::

class ::_CLASSNAME_:: final::_EXTEND_CLASSES_:: {
 public:
  ::_CLASSNAME_::() = default;
  ::_CLASSNAME_::(const ::_CLASSNAME_:: &sourceProps, const RawProps &rawProps);

#pragma mark - Props

  ::_PROPS_::
};
`.trim();

const enumTemplate = `
enum class ::_ENUM_NAME_:: { ::_VALUES_:: };

static inline void fromRawValue(const RawValue &value, ::_ENUM_NAME_:: &result) {
  auto string = (std::string)value;
  ::_FROM_CASES_::
  abort();
}

static inline std::string toString(const ::_ENUM_NAME_:: &value) {
  switch (value) {
    ::_TO_CASES_::
  }
}
`.trim();

const arrayEnumTemplate = `
using ::_ENUM_MASK_:: = uint32_t;

enum class ::_ENUM_NAME_::: ::_ENUM_MASK_:: {
  ::_VALUES_::
};

constexpr bool operator&(
  ::_ENUM_MASK_:: const lhs,
  enum ::_ENUM_NAME_:: const rhs) {
  return lhs & static_cast<::_ENUM_MASK_::>(rhs);
}

constexpr ::_ENUM_MASK_:: operator|(
  ::_ENUM_MASK_:: const lhs,
  enum ::_ENUM_NAME_:: const rhs) {
  return lhs | static_cast<::_ENUM_MASK_::>(rhs);
}

constexpr void operator|=(
  ::_ENUM_MASK_:: &lhs,
  enum ::_ENUM_NAME_:: const rhs) {
  lhs = lhs | static_cast<::_ENUM_MASK_::>(rhs);
}

static inline void fromRawValue(const RawValue &value, ::_ENUM_MASK_:: &result) {
  auto items = std::vector<std::string>{value};
  for (const auto &item : items) {
    ::_FROM_CASES_::
    abort();
  }
}

static inline std::string toString(const ::_ENUM_MASK_:: &value) {
    auto result = std::string{};
    auto separator = std::string{", "};

    ::_TO_CASES_::
    if (!result.empty()) {
      result.erase(result.length() - separator.length());
    }
    return result;
}
`.trim();

function getClassExtendString(component): string {
  const extendString =
    ' : ' +
    component.extendsProps
      .map(extendProps => {
        switch (extendProps.type) {
          case 'ReactNativeBuiltInType':
            switch (extendProps.knownTypeName) {
              case 'ReactNativeCoreViewProps':
                return 'public ViewProps';
              default:
                (extendProps.knownTypeName: empty);
                throw new Error('Invalid knownTypeName');
            }
          default:
            (extendProps.type: empty);
            throw new Error('Invalid extended type');
        }
      })
      .join(' ');

  return extendString;
}

function getNativeTypeFromAnnotation(componentName: string, prop): string {
  const typeAnnotation = prop.typeAnnotation;

  switch (typeAnnotation.type) {
    case 'BooleanTypeAnnotation':
    case 'StringTypeAnnotation':
    case 'Int32TypeAnnotation':
    case 'FloatTypeAnnotation':
      return getCppTypeForAnnotation(typeAnnotation.type);
    case 'NativePrimitiveTypeAnnotation':
      switch (typeAnnotation.name) {
        case 'ColorPrimitive':
          return 'SharedColor';
        case 'ImageSourcePrimitive':
          return 'ImageSource';
        case 'PointPrimitive':
          return 'Point';
        default:
          (typeAnnotation.name: empty);
          throw new Error('Received unknown NativePrimitiveTypeAnnotation');
      }
    case 'ArrayTypeAnnotation': {
      if (typeAnnotation.elementType.type === 'ArrayTypeAnnotation') {
        throw new Error(
          'ArrayTypeAnnotation of type ArrayTypeAnnotation not supported',
        );
      }
      if (typeAnnotation.elementType.type === 'StringEnumTypeAnnotation') {
        const enumName = getEnumName(componentName, prop.name);
        return getEnumMaskName(enumName);
      }
      const itemAnnotation = getNativeTypeFromAnnotation(componentName, {
        typeAnnotation: typeAnnotation.elementType,
        name: componentName,
      });
      return `std::vector<${itemAnnotation}>`;
    }
    case 'ObjectTypeAnnotation': {
      throw new Error('Object type is not implemented');
    }
    case 'StringEnumTypeAnnotation':
      return getEnumName(componentName, prop.name);
    default:
      (typeAnnotation: empty);
      throw new Error('Received invalid typeAnnotation');
  }
}

function convertDefaultTypeToString(componentName: string, prop): string {
  const typeAnnotation = prop.typeAnnotation;
  switch (typeAnnotation.type) {
    case 'BooleanTypeAnnotation':
      return String(typeAnnotation.default);
    case 'StringTypeAnnotation':
      if (typeAnnotation.default == null) {
        return '';
      }
      return `"${typeAnnotation.default}"`;
    case 'Int32TypeAnnotation':
      return String(typeAnnotation.default);
    case 'FloatTypeAnnotation':
      const defaultVal = typeAnnotation.default;
      return parseInt(defaultVal, 10) === defaultVal
        ? typeAnnotation.default.toFixed(1)
        : String(typeAnnotation.default);
    case 'NativePrimitiveTypeAnnotation':
      switch (typeAnnotation.name) {
        case 'ColorPrimitive':
          return '';
        case 'ImageSourcePrimitive':
          return '';
        case 'PointPrimitive':
          return '';
        default:
          (typeAnnotation.name: empty);
          throw new Error('Received unknown NativePrimitiveTypeAnnotation');
      }
    case 'ArrayTypeAnnotation': {
      switch (typeAnnotation.elementType.type) {
        case 'StringEnumTypeAnnotation':
          if (typeAnnotation.elementType.default == null) {
            throw new Error(
              'A default is required for array StringEnumTypeAnnotation',
            );
          }
          const enumName = getEnumName(componentName, prop.name);
          const enumMaskName = getEnumMaskName(enumName);
          const defaultValue = `${enumName}::${toSafeCppString(
            typeAnnotation.elementType.default || '',
          )}`;
          return `static_cast<${enumMaskName}>(${defaultValue})`;
        default:
          return '';
      }
    }
    case 'ObjectTypeAnnotation': {
      throw new Error('Object type is not implemented');
    }
    case 'StringEnumTypeAnnotation':
      return `${getEnumName(componentName, prop.name)}::${toSafeCppString(
        typeAnnotation.default,
      )}`;
    default:
      (typeAnnotation: empty);
      throw new Error('Received invalid typeAnnotation');
  }
}

function getEnumName(componentName, propName): string {
  const uppercasedPropName = toSafeCppString(propName);
  return `${componentName}${uppercasedPropName}`;
}

function getEnumMaskName(enumName: string): string {
  return `${enumName}Mask`;
}

function convertValueToEnumOption(value: string): string {
  return toSafeCppString(value);
}

function generateArrayEnumString(
  componentName: string,
  name: string,
  enumOptions,
): string {
  const options = enumOptions.map(option => option.name);
  const enumName = getEnumName(componentName, name);

  const values = options
    .map((option, index) => `${toSafeCppString(option)} = 1 << ${index}`)
    .join(',\n  ');

  const fromCases = options
    .map(
      option =>
        `if (item == "${option}") {
      result |= ${enumName}::${toSafeCppString(option)};
      continue;
    }`,
    )
    .join('\n    ');

  const toCases = options
    .map(
      option =>
        `if (value & ${enumName}::${toSafeCppString(option)}) {
      result += "${option}" + separator;
    }`,
    )
    .join('\n' + '    ');

  return arrayEnumTemplate
    .replace(/::_ENUM_NAME_::/g, enumName)
    .replace(/::_ENUM_MASK_::/g, getEnumMaskName(enumName))
    .replace('::_VALUES_::', values)
    .replace('::_FROM_CASES_::', fromCases)
    .replace('::_TO_CASES_::', toCases);
}

function generateEnumString(componentName: string, component): string {
  return component.props
    .map(prop => {
      if (
        prop.typeAnnotation.type === 'ArrayTypeAnnotation' &&
        prop.typeAnnotation.elementType.type === 'StringEnumTypeAnnotation'
      ) {
        return generateArrayEnumString(
          componentName,
          prop.name,
          prop.typeAnnotation.elementType.options,
        );
      }

      if (prop.typeAnnotation.type !== 'StringEnumTypeAnnotation') {
        return;
      }

      const values = prop.typeAnnotation.options.map(option => option.name);
      const enumName = getEnumName(componentName, prop.name);

      const fromCases = values
        .map(
          value =>
            `if (string == "${value}") { result = ${enumName}::${convertValueToEnumOption(
              value,
            )}; return; }`,
        )
        .join('\n' + '  ');

      const toCases = values
        .map(
          value =>
            `case ${enumName}::${convertValueToEnumOption(
              value,
            )}: return "${value}";`,
        )
        .join('\n' + '    ');

      return enumTemplate
        .replace(/::_ENUM_NAME_::/g, enumName)
        .replace('::_VALUES_::', values.map(toSafeCppString).join(', '))
        .replace('::_FROM_CASES_::', fromCases)
        .replace('::_TO_CASES_::', toCases);
    })
    .filter(Boolean)
    .join('\n');
}

function generatePropsString(
  componentName: string,
  props: $ReadOnlyArray<PropTypeShape>,
) {
  return props
    .map(prop => {
      const nativeType = getNativeTypeFromAnnotation(componentName, prop);
      const defaultValue = convertDefaultTypeToString(componentName, prop);

      return `const ${nativeType} ${prop.name}{${defaultValue}};`;
    })
    .join('\n' + '  ');
}

function getImports(component): Set<string> {
  const imports: Set<string> = new Set();

  component.extendsProps.forEach(extendProps => {
    switch (extendProps.type) {
      case 'ReactNativeBuiltInType':
        switch (extendProps.knownTypeName) {
          case 'ReactNativeCoreViewProps':
            imports.add('#include <react/components/view/ViewProps.h>');
            return;
          default:
            (extendProps.knownTypeName: empty);
            throw new Error('Invalid knownTypeName');
        }
      default:
        (extendProps.type: empty);
        throw new Error('Invalid extended type');
    }
  });

  function addImportsForNativeName(name) {
    switch (name) {
      case 'ColorPrimitive':
        imports.add('#include <react/graphics/Color.h>');
        return;
      case 'ImageSourcePrimitive':
        imports.add('#include <react/imagemanager/primitives.h>');
        return;
      case 'PointPrimitive':
        imports.add('#include <react/graphics/Geometry.h>');
        return;
      default:
        (name: empty);
        throw new Error(
          `Invalid NativePrimitiveTypeAnnotation name, got ${name}`,
        );
    }
  }

  component.props.forEach(prop => {
    const typeAnnotation = prop.typeAnnotation;

    if (typeAnnotation.type === 'NativePrimitiveTypeAnnotation') {
      addImportsForNativeName(typeAnnotation.name);
    }

    if (typeAnnotation.type === 'ArrayTypeAnnotation') {
      imports.add('#include <vector>');
      if (typeAnnotation.elementType.type === 'StringEnumTypeAnnotation') {
        imports.add('#include <cinttypes>');
      }
    }

    if (
      typeAnnotation.type === 'ArrayTypeAnnotation' &&
      typeAnnotation.elementType.type === 'NativePrimitiveTypeAnnotation'
    ) {
      addImportsForNativeName(typeAnnotation.elementType.name);
    }
  });

  return imports;
}

module.exports = {
  generate(
    libraryName: string,
    schema: SchemaType,
    moduleSpecName: string,
  ): FilesOutput {
    const fileName = 'Props.h';

    const allImports: Set<string> = new Set();

    const componentClasses = Object.keys(schema.modules)
      .map(moduleName => {
        const components = schema.modules[moduleName].components;
        // No components in this module
        if (components == null) {
          return null;
        }

        return Object.keys(components)
          .map(componentName => {
            const component = components[componentName];

            const newName = `${componentName}Props`;
            const enumString = generateEnumString(componentName, component);
            const propsString = generatePropsString(
              componentName,
              component.props,
            );
            const extendString = getClassExtendString(component);
            const imports = getImports(component);

            imports.forEach(allImports.add, allImports);

            const replacedTemplate = classTemplate
              .replace('::_ENUMS_::', enumString)
              .replace(/::_CLASSNAME_::/g, newName)
              .replace('::_EXTEND_CLASSES_::', extendString)
              .replace('::_PROPS_::', propsString)
              .trim();

            return replacedTemplate;
          })
          .join('\n\n');
      })
      .filter(Boolean)
      .join('\n\n');

    const replacedTemplate = template
      .replace(/::_COMPONENT_CLASSES_::/g, componentClasses)
      .replace(
        '::_IMPORTS_::',
        Array.from(allImports)
          .sort()
          .join('\n'),
      );

    return new Map([[fileName, replacedTemplate]]);
  },
};
<commit_msg>Better error message for invalid type annotation<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict
 * @format
 */

'use strict';

const {getCppTypeForAnnotation, toSafeCppString} = require('./CppHelpers.js');

import type {PropTypeShape, SchemaType} from '../../CodegenSchema';

// File path -> contents
type FilesOutput = Map<string, string>;

const template = `
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */
#pragma once

::_IMPORTS_::

namespace facebook {
namespace react {

::_COMPONENT_CLASSES_::

} // namespace react
} // namespace facebook
`;

const classTemplate = `
::_ENUMS_::

class ::_CLASSNAME_:: final::_EXTEND_CLASSES_:: {
 public:
  ::_CLASSNAME_::() = default;
  ::_CLASSNAME_::(const ::_CLASSNAME_:: &sourceProps, const RawProps &rawProps);

#pragma mark - Props

  ::_PROPS_::
};
`.trim();

const enumTemplate = `
enum class ::_ENUM_NAME_:: { ::_VALUES_:: };

static inline void fromRawValue(const RawValue &value, ::_ENUM_NAME_:: &result) {
  auto string = (std::string)value;
  ::_FROM_CASES_::
  abort();
}

static inline std::string toString(const ::_ENUM_NAME_:: &value) {
  switch (value) {
    ::_TO_CASES_::
  }
}
`.trim();

const arrayEnumTemplate = `
using ::_ENUM_MASK_:: = uint32_t;

enum class ::_ENUM_NAME_::: ::_ENUM_MASK_:: {
  ::_VALUES_::
};

constexpr bool operator&(
  ::_ENUM_MASK_:: const lhs,
  enum ::_ENUM_NAME_:: const rhs) {
  return lhs & static_cast<::_ENUM_MASK_::>(rhs);
}

constexpr ::_ENUM_MASK_:: operator|(
  ::_ENUM_MASK_:: const lhs,
  enum ::_ENUM_NAME_:: const rhs) {
  return lhs | static_cast<::_ENUM_MASK_::>(rhs);
}

constexpr void operator|=(
  ::_ENUM_MASK_:: &lhs,
  enum ::_ENUM_NAME_:: const rhs) {
  lhs = lhs | static_cast<::_ENUM_MASK_::>(rhs);
}

static inline void fromRawValue(const RawValue &value, ::_ENUM_MASK_:: &result) {
  auto items = std::vector<std::string>{value};
  for (const auto &item : items) {
    ::_FROM_CASES_::
    abort();
  }
}

static inline std::string toString(const ::_ENUM_MASK_:: &value) {
    auto result = std::string{};
    auto separator = std::string{", "};

    ::_TO_CASES_::
    if (!result.empty()) {
      result.erase(result.length() - separator.length());
    }
    return result;
}
`.trim();

function getClassExtendString(component): string {
  const extendString =
    ' : ' +
    component.extendsProps
      .map(extendProps => {
        switch (extendProps.type) {
          case 'ReactNativeBuiltInType':
            switch (extendProps.knownTypeName) {
              case 'ReactNativeCoreViewProps':
                return 'public ViewProps';
              default:
                (extendProps.knownTypeName: empty);
                throw new Error('Invalid knownTypeName');
            }
          default:
            (extendProps.type: empty);
            throw new Error('Invalid extended type');
        }
      })
      .join(' ');

  return extendString;
}

function getNativeTypeFromAnnotation(componentName: string, prop): string {
  const typeAnnotation = prop.typeAnnotation;

  switch (typeAnnotation.type) {
    case 'BooleanTypeAnnotation':
    case 'StringTypeAnnotation':
    case 'Int32TypeAnnotation':
    case 'FloatTypeAnnotation':
      return getCppTypeForAnnotation(typeAnnotation.type);
    case 'NativePrimitiveTypeAnnotation':
      switch (typeAnnotation.name) {
        case 'ColorPrimitive':
          return 'SharedColor';
        case 'ImageSourcePrimitive':
          return 'ImageSource';
        case 'PointPrimitive':
          return 'Point';
        default:
          (typeAnnotation.name: empty);
          throw new Error('Received unknown NativePrimitiveTypeAnnotation');
      }
    case 'ArrayTypeAnnotation': {
      if (typeAnnotation.elementType.type === 'ArrayTypeAnnotation') {
        throw new Error(
          'ArrayTypeAnnotation of type ArrayTypeAnnotation not supported',
        );
      }
      if (typeAnnotation.elementType.type === 'StringEnumTypeAnnotation') {
        const enumName = getEnumName(componentName, prop.name);
        return getEnumMaskName(enumName);
      }
      const itemAnnotation = getNativeTypeFromAnnotation(componentName, {
        typeAnnotation: typeAnnotation.elementType,
        name: componentName,
      });
      return `std::vector<${itemAnnotation}>`;
    }
    case 'ObjectTypeAnnotation': {
      throw new Error('Object type is not implemented');
    }
    case 'StringEnumTypeAnnotation':
      return getEnumName(componentName, prop.name);
    default:
      (typeAnnotation: empty);
      throw new Error(
        `Received invalid typeAnnotation for ${componentName} prop ${
          prop.name
        }, received ${typeAnnotation.type}`,
      );
  }
}

function convertDefaultTypeToString(componentName: string, prop): string {
  const typeAnnotation = prop.typeAnnotation;
  switch (typeAnnotation.type) {
    case 'BooleanTypeAnnotation':
      return String(typeAnnotation.default);
    case 'StringTypeAnnotation':
      if (typeAnnotation.default == null) {
        return '';
      }
      return `"${typeAnnotation.default}"`;
    case 'Int32TypeAnnotation':
      return String(typeAnnotation.default);
    case 'FloatTypeAnnotation':
      const defaultVal = typeAnnotation.default;
      return parseInt(defaultVal, 10) === defaultVal
        ? typeAnnotation.default.toFixed(1)
        : String(typeAnnotation.default);
    case 'NativePrimitiveTypeAnnotation':
      switch (typeAnnotation.name) {
        case 'ColorPrimitive':
          return '';
        case 'ImageSourcePrimitive':
          return '';
        case 'PointPrimitive':
          return '';
        default:
          (typeAnnotation.name: empty);
          throw new Error('Received unknown NativePrimitiveTypeAnnotation');
      }
    case 'ArrayTypeAnnotation': {
      switch (typeAnnotation.elementType.type) {
        case 'StringEnumTypeAnnotation':
          if (typeAnnotation.elementType.default == null) {
            throw new Error(
              'A default is required for array StringEnumTypeAnnotation',
            );
          }
          const enumName = getEnumName(componentName, prop.name);
          const enumMaskName = getEnumMaskName(enumName);
          const defaultValue = `${enumName}::${toSafeCppString(
            typeAnnotation.elementType.default || '',
          )}`;
          return `static_cast<${enumMaskName}>(${defaultValue})`;
        default:
          return '';
      }
    }
    case 'ObjectTypeAnnotation': {
      throw new Error('Object type is not implemented');
    }
    case 'StringEnumTypeAnnotation':
      return `${getEnumName(componentName, prop.name)}::${toSafeCppString(
        typeAnnotation.default,
      )}`;
    default:
      (typeAnnotation: empty);
      throw new Error('Received invalid typeAnnotation');
  }
}

function getEnumName(componentName, propName): string {
  const uppercasedPropName = toSafeCppString(propName);
  return `${componentName}${uppercasedPropName}`;
}

function getEnumMaskName(enumName: string): string {
  return `${enumName}Mask`;
}

function convertValueToEnumOption(value: string): string {
  return toSafeCppString(value);
}

function generateArrayEnumString(
  componentName: string,
  name: string,
  enumOptions,
): string {
  const options = enumOptions.map(option => option.name);
  const enumName = getEnumName(componentName, name);

  const values = options
    .map((option, index) => `${toSafeCppString(option)} = 1 << ${index}`)
    .join(',\n  ');

  const fromCases = options
    .map(
      option =>
        `if (item == "${option}") {
      result |= ${enumName}::${toSafeCppString(option)};
      continue;
    }`,
    )
    .join('\n    ');

  const toCases = options
    .map(
      option =>
        `if (value & ${enumName}::${toSafeCppString(option)}) {
      result += "${option}" + separator;
    }`,
    )
    .join('\n' + '    ');

  return arrayEnumTemplate
    .replace(/::_ENUM_NAME_::/g, enumName)
    .replace(/::_ENUM_MASK_::/g, getEnumMaskName(enumName))
    .replace('::_VALUES_::', values)
    .replace('::_FROM_CASES_::', fromCases)
    .replace('::_TO_CASES_::', toCases);
}

function generateEnumString(componentName: string, component): string {
  return component.props
    .map(prop => {
      if (
        prop.typeAnnotation.type === 'ArrayTypeAnnotation' &&
        prop.typeAnnotation.elementType.type === 'StringEnumTypeAnnotation'
      ) {
        return generateArrayEnumString(
          componentName,
          prop.name,
          prop.typeAnnotation.elementType.options,
        );
      }

      if (prop.typeAnnotation.type !== 'StringEnumTypeAnnotation') {
        return;
      }

      const values = prop.typeAnnotation.options.map(option => option.name);
      const enumName = getEnumName(componentName, prop.name);

      const fromCases = values
        .map(
          value =>
            `if (string == "${value}") { result = ${enumName}::${convertValueToEnumOption(
              value,
            )}; return; }`,
        )
        .join('\n' + '  ');

      const toCases = values
        .map(
          value =>
            `case ${enumName}::${convertValueToEnumOption(
              value,
            )}: return "${value}";`,
        )
        .join('\n' + '    ');

      return enumTemplate
        .replace(/::_ENUM_NAME_::/g, enumName)
        .replace('::_VALUES_::', values.map(toSafeCppString).join(', '))
        .replace('::_FROM_CASES_::', fromCases)
        .replace('::_TO_CASES_::', toCases);
    })
    .filter(Boolean)
    .join('\n');
}

function generatePropsString(
  componentName: string,
  props: $ReadOnlyArray<PropTypeShape>,
) {
  return props
    .map(prop => {
      const nativeType = getNativeTypeFromAnnotation(componentName, prop);
      const defaultValue = convertDefaultTypeToString(componentName, prop);

      return `const ${nativeType} ${prop.name}{${defaultValue}};`;
    })
    .join('\n' + '  ');
}

function getImports(component): Set<string> {
  const imports: Set<string> = new Set();

  component.extendsProps.forEach(extendProps => {
    switch (extendProps.type) {
      case 'ReactNativeBuiltInType':
        switch (extendProps.knownTypeName) {
          case 'ReactNativeCoreViewProps':
            imports.add('#include <react/components/view/ViewProps.h>');
            return;
          default:
            (extendProps.knownTypeName: empty);
            throw new Error('Invalid knownTypeName');
        }
      default:
        (extendProps.type: empty);
        throw new Error('Invalid extended type');
    }
  });

  function addImportsForNativeName(name) {
    switch (name) {
      case 'ColorPrimitive':
        imports.add('#include <react/graphics/Color.h>');
        return;
      case 'ImageSourcePrimitive':
        imports.add('#include <react/imagemanager/primitives.h>');
        return;
      case 'PointPrimitive':
        imports.add('#include <react/graphics/Geometry.h>');
        return;
      default:
        (name: empty);
        throw new Error(
          `Invalid NativePrimitiveTypeAnnotation name, got ${name}`,
        );
    }
  }

  component.props.forEach(prop => {
    const typeAnnotation = prop.typeAnnotation;

    if (typeAnnotation.type === 'NativePrimitiveTypeAnnotation') {
      addImportsForNativeName(typeAnnotation.name);
    }

    if (typeAnnotation.type === 'ArrayTypeAnnotation') {
      imports.add('#include <vector>');
      if (typeAnnotation.elementType.type === 'StringEnumTypeAnnotation') {
        imports.add('#include <cinttypes>');
      }
    }

    if (
      typeAnnotation.type === 'ArrayTypeAnnotation' &&
      typeAnnotation.elementType.type === 'NativePrimitiveTypeAnnotation'
    ) {
      addImportsForNativeName(typeAnnotation.elementType.name);
    }
  });

  return imports;
}

module.exports = {
  generate(
    libraryName: string,
    schema: SchemaType,
    moduleSpecName: string,
  ): FilesOutput {
    const fileName = 'Props.h';

    const allImports: Set<string> = new Set();

    const componentClasses = Object.keys(schema.modules)
      .map(moduleName => {
        const components = schema.modules[moduleName].components;
        // No components in this module
        if (components == null) {
          return null;
        }

        return Object.keys(components)
          .map(componentName => {
            const component = components[componentName];

            const newName = `${componentName}Props`;
            const enumString = generateEnumString(componentName, component);
            const propsString = generatePropsString(
              componentName,
              component.props,
            );
            const extendString = getClassExtendString(component);
            const imports = getImports(component);

            imports.forEach(allImports.add, allImports);

            const replacedTemplate = classTemplate
              .replace('::_ENUMS_::', enumString)
              .replace(/::_CLASSNAME_::/g, newName)
              .replace('::_EXTEND_CLASSES_::', extendString)
              .replace('::_PROPS_::', propsString)
              .trim();

            return replacedTemplate;
          })
          .join('\n\n');
      })
      .filter(Boolean)
      .join('\n\n');

    const replacedTemplate = template
      .replace(/::_COMPONENT_CLASSES_::/g, componentClasses)
      .replace(
        '::_IMPORTS_::',
        Array.from(allImports)
          .sort()
          .join('\n'),
      );

    return new Map([[fileName, replacedTemplate]]);
  },
};
<|endoftext|>


<commit_before>const TextLintTester = require("textlint-tester");
const tester = new TextLintTester();
// rule
const rule = require("../src/textlint-rule-google-tone");
// ruleName, rule, { valid, invalid }
const message = `using "please" in a set of instructions is overdoing the politeness.\n
        URL: https://developers.google.com/style/tone#politeness-and-use-of-please`;
tester.run("textlint-rule-google-tone", rule, {
    valid: ["To view the document, click View."],
    invalid: [
        {
            text: "To view the document, please click View.",
            output: "To view the document, click View.",
            errors: [
                {
                    message: message,
                    index: 0
                }
            ],
        },
        {
            text: "For more information, please see document.",
            output: "For more information, see document.",
            errors: [
                {
                    message: message,
                    index: 0
                }
            ],
        }

    ]
});
<commit_msg>test(tone): add test case<commit_after>const TextLintTester = require("textlint-tester");
const tester = new TextLintTester();
// rule
const rule = require("../src/textlint-rule-google-tone");
// ruleName, rule, { valid, invalid }
const message = `using "please" in a set of instructions is overdoing the politeness.\n
        URL: https://developers.google.com/style/tone#politeness-and-use-of-please`;
tester.run("textlint-rule-google-tone", rule, {
    valid: [
        "To view the document, click View.",
        "To get the user's phone number, call `user.phoneNumber.get()`.",
        "To clean up, call the `collectGarbage()` method.",
    ],
    invalid: [
        {
            text: "To view the document, please click View.",
            output: "To view the document, click View.",
            errors: [
                {
                    message: message,
                    index: 0
                }
            ],
        },
        {
            text: "For more information, please see document.",
            output: "For more information, see document.",
            errors: [
                {
                    message: message,
                    index: 0
                }
            ],
        }

    ]
});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import CommonQueries from './common/CommonGraphQLQueries';
import DataIndex from './common/DataIndex';
import Utilities from './common/Utilities';
import MultiSelectField from './MultiSelectField';
import Table from './Table';

const CURRENT_DATE = new Date();
CURRENT_DATE.setHours(0, 0, 0, 0);
const FINANCIAL_YEAR = getFinancialYear(CURRENT_DATE);
const APR_DATE = FINANCIAL_YEAR.start;
const MAR_DATE = FINANCIAL_YEAR.end;

function getFinancialYear(date) {
	if (!date || !(date instanceof Date)) {
		date = new Date();
		date.setHours(0, 0, 0, 0);
	}
	// get start point
	const startYear = date.getMonth() >= 3 ? date.getFullYear() : date.getFullYear() - 1;
	const startDate = new Date();
	startDate.setFullYear(startYear, 3, 1); // 1st apr
	startDate.setHours(0, 0, 0, 0);
	// get end point
	const endDate = new Date();
	endDate.setFullYear(startYear + 1, 2, 31); // 31th mar
	startDate.setHours(0, 0, 0, 0);
	return {
		start: startDate,
		end: endDate
	};
}

// timestamps
const CURRENT = CURRENT_DATE.getTime();
const APR = APR_DATE.getTime();
const MAR = MAR_DATE.getTime();

const PLAN = 'plan';
const PHASE_IN = 'phaseIn';
const ACTIVE = 'active';
const PHASE_OUT = 'phaseOut';
const END_OF_LIFE = 'endOfLife';

class Report extends Component {

	constructor(props) {
		super(props);
		this._initReport = this._initReport.bind(this);
		this._handleData = this._handleData.bind(this);
		this._addLifecyclePhaseEnd = this._addLifecyclePhaseEnd.bind(this);
		this._isTimestampInOnePhase = this._isTimestampInOnePhase.bind(this);
		this._onMultiSelectChange = this._onMultiSelectChange.bind(this);
		this.MARKET_OPTIONS = {};
		this.state = {
			setup: null,
			data: [],
			multiSelectValues: [
				'AL', 'CD', 'CZ', 'DE', 'EG', 'ES', 'GH', 'GR', 'HU', 'IE', 'IN',
				'IT', 'LS', 'MT', 'MZ', 'PT', 'RO', 'TR', 'TZ', 'UK', 'ZA'
			]
		};
	}

	componentDidMount() {
		lx.init().then(this._initReport);
	}

	_initReport(setup) {
		lx.ready(this._createConfig());
		lx.showSpinner('Loading data...');
		this.setState({
			setup: setup
		});
		// get all tags, then the data
		lx.executeGraphQL(CommonQueries.tagGroups).then((tagGroups) => {
			const index = new DataIndex();
			index.put(tagGroups);
			const applicationTagId = index.getFirstTagID('Application Type', 'Application');
			const itTagId = index.getFirstTagID('CostCentre', 'IT');
			lx.executeGraphQL(this._createQuery(applicationTagId, itTagId)).then((data) => {
				index.put(data);
				this._handleData(index, applicationTagId, itTagId);
			});
		});
	}

	_createConfig() {
		return {
			allowEditing: false
		};
	}

	_createQuery(applicationTagId, itTagId) {
		// initial assume tagGroup.name changed or the id couldn't be determined otherwise
		const idFilter = { application: '', it: '' };
		// initial assume to get it
		let tagNameDef = 'tags { name }';
		if (applicationTagId) {
			idFilter.application = `, {facetKey: "Application Type", keys: ["${applicationTagId}"]}`;
		}
		if (itTagId) {
			idFilter.it = `, {facetKey: "CostCentre", keys: ["${itTagId}"]}`;
		}
		if (applicationTagId && itTagId) {
			tagNameDef = '';
		}
		return `{applications: allFactSheets(
					sort: { mode: BY_FIELD, key: "displayName", order: asc },
					filter: {facetFilters: [
						{facetKey: "FactSheetTypes", keys: ["Application"]}
						${idFilter.application}
						${idFilter.it}
					]}
				) {
					edges { node {
						id name ${tagNameDef}
						... on Application {
							lifecycle { phases { phase startDate } }
						}
					}}
				}}`;
	}

	_handleData(index, applicationTagId, itTagId) {
		const tableData = [];
		// group applications by market
		const groupedByMarket = {};
		let marketCount = 0;
		index.applications.nodes.forEach((e) => {
			if (!applicationTagId && !index.includesTag(e, 'Application')) {
				return;
			}
			if (!itTagId && !index.includesTag(e, 'IT')) {
				return;
			}
			let market = Utilities.getMarket(e);
			if (!market) {
				return;
			}
			if (!groupedByMarket[market]) {
				groupedByMarket[market] = [];
				this.MARKET_OPTIONS[marketCount++] = market;
			}
			groupedByMarket[market].push(e);
		});
		if (groupedByMarket.CW) {
			// this is a hack for a requirement by v: CW apps should be considered belonging to UK
			const cwApplications = groupedByMarket.CW;
			if (!groupedByMarket.UK) {
				groupedByMarket.UK = cwApplications;
			} else {
				groupedByMarket.UK = cwApplications.concat(groupedByMarket.UK);
			}
			delete groupedByMarket.CW;
			delete this.MARKET_OPTIONS[Utilities.getKeyToValue(this.MARKET_OPTIONS, 'CW')];
		}
		for (let market in groupedByMarket) {
			const allApplications = groupedByMarket[market];
			let baselineApr = 0;
			let decommissionsPlanned = 0;
			let decommissionsActuals = 0;
			let commissionsPlanned = 0;
			let commissionsActuals = 0;
			let baselineMar = 0;
			let baselineToday = 0;
			allApplications.forEach((e) => {
				const lifecycles = Utilities.getLifecycles(e);
				if (lifecycles.length === 0) {
					return;
				}
				let activePhase = Utilities.getLifecyclePhase(lifecycles, ACTIVE);
				const phaseInPhase = Utilities.getLifecyclePhase(lifecycles, PHASE_IN);
				const phaseOutPhase = Utilities.getLifecyclePhase(lifecycles, PHASE_OUT);
				const endOfLifePhase = Utilities.getLifecyclePhase(lifecycles, END_OF_LIFE);
				// add impicit phase before 'endOfLife' if production phases are missing
				if (!activePhase && !phaseInPhase && !phaseOutPhase && endOfLifePhase) {
					activePhase = {
						phase: ACTIVE
					};
				}
				const productionPhases = [activePhase, phaseInPhase, phaseOutPhase];
				this._addLifecyclePhaseEnd(lifecycles, activePhase);
				this._addLifecyclePhaseEnd(lifecycles, phaseInPhase);
				this._addLifecyclePhaseEnd(lifecycles, phaseOutPhase);
				if (this._isTimestampInOnePhase(APR, productionPhases)) {
					// count if 1st apr <CURRENT_FYEAR> is a timepoint in the 'active', 'phaseIn' or 'phaseOut' lifecycle phase
					baselineApr++;
				} else if (endOfLifePhase && endOfLifePhase.startDate === APR) {
					// application is in time frame, but it's decommissioned on APR, still count to baseline
					baselineApr++;
				}
				if (this._isTimestampInOnePhase(CURRENT, productionPhases)) {
					// count if <CURRENT_DATE> is a timepoint in the 'active', 'phaseIn' or 'phaseOut' lifecycle phase
					baselineToday++;
				} else if (endOfLifePhase && endOfLifePhase.startDate === CURRENT) {
					// application is in time frame, but it's decommissioned on CURRENT, still count to baseline
					baselineToday++;
				}
				if (this._isTimestampInOnePhase(MAR, productionPhases)) {
					// count if 31th mar <CURRENT_FYEAR + 1> is a timepoint in the 'active', 'phaseIn' or 'phaseOut' lifecycle phase
					baselineMar++;
				} else if (endOfLifePhase && endOfLifePhase.startDate === MAR) {
					// application is in time frame, but it's decommissioned on MAR, still count to baseline
					// NOTE: this baseline is at the end, so end of life counts if it's equal to MAR
					baselineMar++;
				}
				// application decommissioning or decommissioned this FY?
				// 'endOfLife' phase start date must be between 1st apr <CURRENT_FYEAR> and 31th mar <CURRENT_FYEAR + 1> (both inclusive)
				if (this._isLifecyclePhaseStartDateIn(endOfLifePhase, APR, MAR, false, false)) {
					// planned (decommissioning) or actuals (decommissioned)?
					// NOTE: baseline CURRENT is at the beginning, so end of life counts to planned if it's equal to CURRENT
					if (endOfLifePhase.startDate >= CURRENT) {
						decommissionsPlanned++;
					} else {
						decommissionsActuals++;
					}
				}
				// application commissioning or commissioned this FY?
				// 'active' phase start date must be between 1st apr <CURRENT_FYEAR> and 31th mar <CURRENT_FYEAR + 1> (both inclusive)
				if (this._isLifecyclePhaseStartDateIn(activePhase, APR, MAR, false, false)) {
					// planned (commissioning) or actuals (commissioned)?
					// NOTE: baseline CURRENT is at the beginning, so production counts to actuals if it's equal to CURRENT
					if (activePhase.startDate > CURRENT) {
						commissionsPlanned++;
					} else {
						commissionsActuals++;
					}
				}
			});
			const marketEnum = this._getOptionKeyFromValue(this.MARKET_OPTIONS, market);
			tableData.push({
				id: market,
				market: marketEnum,
				baselineApr: baselineApr,
				decommissionsPlanned: decommissionsPlanned,
				decommissionsActuals: decommissionsActuals,
				commissionsPlanned: commissionsPlanned,
				commissionsActuals: commissionsActuals,
				baselineMar: baselineMar,
				baselineToday: baselineToday
			});
		}
		lx.hideSpinner();
		this.setState({
			data: tableData
		});
	}

	_addLifecyclePhaseEnd(lifecycles, phase) {
		if (!lifecycles || !phase || !phase.phase) {
			return;
		}
		let nextPhaseKey = this._getNextPhaseKey(phase.phase);
		let nextPhase = Utilities.getLifecyclePhase(lifecycles, nextPhaseKey);
		while (!nextPhase) {
			nextPhaseKey = this._getNextPhaseKey(nextPhaseKey);
			if (!nextPhaseKey) {
				break;
			}
			nextPhase = Utilities.getLifecyclePhase(lifecycles, nextPhaseKey);
		}
		if (nextPhase) {
			phase.endDate = nextPhase.startDate;
		}
	}

	_getNextPhaseKey(phase) {
		switch (phase) {
			case PLAN:
				return PHASE_IN;
			case PHASE_IN:
				return ACTIVE;
			case ACTIVE:
				return PHASE_OUT;
			case PHASE_OUT:
				return END_OF_LIFE;
			case END_OF_LIFE:
			default:
				return;
		}
	}

	_isTimestampInOnePhase(timestamp, phases) {
		if (timestamp === undefined || timestamp === null || !phases) {
			return false;
		}
		return phases.some((e) => {
			return this._isTimestampInPhase(e, timestamp);
		});
	}

	_isTimestampInPhase(phase, timestamp) {
		if (!phase || timestamp === undefined || timestamp === null) {
			return false;
		}
		const startDate = phase.startDate;
		const endDate = phase.endDate;
		if (startDate !== undefined && startDate !== null) {
			return (endDate !== undefined && endDate !== null)
				? (startDate <= timestamp && timestamp < endDate)
				: (startDate <= timestamp);
		} else if (endDate !== undefined && endDate !== null) {
			return timestamp < endDate;
		}
		return false;
	}

	_isLifecyclePhaseStartDateIn(lifecycle, from, to, fromExclusive, toExclusive) {
		return lifecycle
			&& (fromExclusive ? lifecycle.startDate > from : lifecycle.startDate >= from)
			&& (toExclusive ? lifecycle.startDate < to : lifecycle.startDate <= to);
	}

	_getOptionKeyFromValue(options, value) {
		if (!value) {
			return undefined;
		}
		const key = Utilities.getKeyToValue(options, value);
		return key !== undefined && key !== null ? parseInt(key, 10) : undefined;
	}

	_onMultiSelectChange(values) {
		this.setState({
			multiSelectValues: values
		});
	}

	render() {
		if (this.state.data.length === 0) {
			return (
Loading data...
);
		}
		let data = this.state.data;
		let marketOptions = Utilities.copyObject(this.MARKET_OPTIONS);
		if (this.state.multiSelectValues.length > 0) {
			// filter table data
			data = data.filter((e) => {
				return this.state.multiSelectValues.some((e2) => {
					const key = Utilities.getKeyToValue(this.MARKET_OPTIONS, e2);
					return key && e.market === parseInt(key);
				});
			});
			// filter market options for table only
			for (let key in this.MARKET_OPTIONS) {
				const value = this.MARKET_OPTIONS[key];
				if (!this.state.multiSelectValues.includes(value)) {
					delete marketOptions[key];
				}
			}
		}
		// add & compute the 'total' row
		const totalOptionKey = Object.keys(this.MARKET_OPTIONS).length + 1;
		marketOptions[totalOptionKey] = 'total';
		const total = {
			id: 'total',
			market: totalOptionKey,
			baselineApr: 0,
			decommissionsPlanned: 0,
			decommissionsActuals: 0,
			commissionsPlanned: 0,
			commissionsActuals: 0,
			baselineMar: 0,
			baselineToday: 0
		};
		data.forEach((e) => {
			total.baselineApr += e.baselineApr;
			total.decommissionsPlanned += e.decommissionsPlanned;
			total.decommissionsActuals += e.decommissionsActuals;
			total.commissionsPlanned += e.commissionsPlanned;
			total.commissionsActuals += e.commissionsActuals;
			total.baselineMar += e.baselineMar;
			total.baselineToday += e.baselineToday;
		});
		data.push(total);
		return (

				<MultiSelectField
					label='Markets to show'
					placeholder='Select a market'
					items={this.MARKET_OPTIONS}
					onChange={this._onMultiSelectChange}
					values={this.state.multiSelectValues} />

		);
	}
}

export default Report;
<commit_msg>DCA: bugfix<commit_after>import React, { Component } from 'react';
import CommonQueries from './common/CommonGraphQLQueries';
import DataIndex from './common/DataIndex';
import Utilities from './common/Utilities';
import MultiSelectField from './MultiSelectField';
import Table from './Table';

const CURRENT_DATE = new Date();
CURRENT_DATE.setHours(0, 0, 0, 0);
const FINANCIAL_YEAR = getFinancialYear(CURRENT_DATE);
const APR_DATE = FINANCIAL_YEAR.start;
const MAR_DATE = FINANCIAL_YEAR.end;

function getFinancialYear(date) {
	if (!date || !(date instanceof Date)) {
		date = new Date();
		date.setHours(0, 0, 0, 0);
	}
	// get start point
	const startYear = date.getMonth() >= 3 ? date.getFullYear() : date.getFullYear() - 1;
	const startDate = new Date();
	startDate.setFullYear(startYear, 3, 1); // 1st apr
	startDate.setHours(0, 0, 0, 0);
	// get end point
	const endDate = new Date();
	endDate.setFullYear(startYear + 1, 2, 31); // 31th mar
	startDate.setHours(0, 0, 0, 0);
	return {
		start: startDate,
		end: endDate
	};
}

// timestamps
const CURRENT = CURRENT_DATE.getTime();
const APR = APR_DATE.getTime();
const MAR = MAR_DATE.getTime();

const PLAN = 'plan';
const PHASE_IN = 'phaseIn';
const ACTIVE = 'active';
const PHASE_OUT = 'phaseOut';
const END_OF_LIFE = 'endOfLife';

class Report extends Component {

	constructor(props) {
		super(props);
		this._initReport = this._initReport.bind(this);
		this._handleData = this._handleData.bind(this);
		this._addLifecyclePhaseEnd = this._addLifecyclePhaseEnd.bind(this);
		this._isTimestampInOnePhase = this._isTimestampInOnePhase.bind(this);
		this._onMultiSelectChange = this._onMultiSelectChange.bind(this);
		this.MARKET_OPTIONS = {};
		this.state = {
			setup: null,
			data: [],
			multiSelectValues: [
				'AL', 'CD', 'CZ', 'DE', 'EG', 'ES', 'GH', 'GR', 'HU', 'IE', 'IN',
				'IT', 'LS', 'MT', 'MZ', 'PT', 'RO', 'TR', 'TZ', 'UK', 'ZA'
			]
		};
	}

	componentDidMount() {
		lx.init().then(this._initReport);
	}

	_initReport(setup) {
		lx.ready(this._createConfig());
		lx.showSpinner('Loading data...');
		this.setState({
			setup: setup
		});
		// get all tags, then the data
		lx.executeGraphQL(CommonQueries.tagGroups).then((tagGroups) => {
			const index = new DataIndex();
			index.put(tagGroups);
			const applicationTagId = index.getFirstTagID('Application Type', 'Application');
			const itTagId = index.getFirstTagID('CostCentre', 'IT');
			lx.executeGraphQL(this._createQuery(applicationTagId, itTagId)).then((data) => {
				index.put(data);
				this._handleData(index, applicationTagId, itTagId);
			});
		});
	}

	_createConfig() {
		return {
			allowEditing: false
		};
	}

	_createQuery(applicationTagId, itTagId) {
		// initial assume tagGroup.name changed or the id couldn't be determined otherwise
		const idFilter = { application: '', it: '' };
		// initial assume to get it
		let tagNameDef = 'tags { name }';
		if (applicationTagId) {
			idFilter.application = `, {facetKey: "Application Type", keys: ["${applicationTagId}"]}`;
		}
		if (itTagId) {
			idFilter.it = `, {facetKey: "CostCentre", keys: ["${itTagId}"]}`;
		}
		if (applicationTagId && itTagId) {
			tagNameDef = '';
		}
		return `{applications: allFactSheets(
					sort: { mode: BY_FIELD, key: "displayName", order: asc },
					filter: {facetFilters: [
						{facetKey: "FactSheetTypes", keys: ["Application"]}
						${idFilter.application}
						${idFilter.it}
					]}
				) {
					edges { node {
						id name ${tagNameDef}
						... on Application {
							lifecycle { phases { phase startDate } }
						}
					}}
				}}`;
	}

	_handleData(index, applicationTagId, itTagId) {
		const tableData = [];
		// group applications by market
		const groupedByMarket = {};
		let marketCount = 0;
		index.applications.nodes.forEach((e) => {
			if (!applicationTagId && !index.includesTag(e, 'Application')) {
				return;
			}
			if (!itTagId && !index.includesTag(e, 'IT')) {
				return;
			}
			let market = Utilities.getMarket(e);
			if (!market) {
				return;
			}
			if (!groupedByMarket[market]) {
				groupedByMarket[market] = [];
				this.MARKET_OPTIONS[marketCount++] = market;
			}
			groupedByMarket[market].push(e);
		});
		if (groupedByMarket.CW) {
			// this is a hack for a requirement by v: CW apps should be considered belonging to UK
			const cwApplications = groupedByMarket.CW;
			if (!groupedByMarket.UK) {
				groupedByMarket.UK = cwApplications;
			} else {
				groupedByMarket.UK = cwApplications.concat(groupedByMarket.UK);
			}
			delete groupedByMarket.CW;
			delete this.MARKET_OPTIONS[Utilities.getKeyToValue(this.MARKET_OPTIONS, 'CW')];
		}
		for (let market in groupedByMarket) {
			const allApplications = groupedByMarket[market];
			let baselineApr = 0;
			let decommissionsPlanned = 0;
			let decommissionsActuals = 0;
			let commissionsPlanned = 0;
			let commissionsActuals = 0;
			let baselineMar = 0;
			let baselineToday = 0;
			allApplications.forEach((e) => {
				const lifecycles = Utilities.getLifecycles(e);
				if (lifecycles.length === 0) {
					return;
				}
				let activePhase = Utilities.getLifecyclePhase(lifecycles, ACTIVE);
				const phaseInPhase = Utilities.getLifecyclePhase(lifecycles, PHASE_IN);
				const phaseOutPhase = Utilities.getLifecyclePhase(lifecycles, PHASE_OUT);
				const endOfLifePhase = Utilities.getLifecyclePhase(lifecycles, END_OF_LIFE);
				// add impicit phase before 'endOfLife' if production phases are missing
				if (!activePhase && !phaseInPhase && !phaseOutPhase && endOfLifePhase) {
					activePhase = {
						phase: ACTIVE
					};
				}
				const productionPhases = [activePhase, phaseInPhase, phaseOutPhase];
				this._addLifecyclePhaseEnd(lifecycles, activePhase);
				this._addLifecyclePhaseEnd(lifecycles, phaseInPhase);
				this._addLifecyclePhaseEnd(lifecycles, phaseOutPhase);
				if (this._isTimestampInOnePhase(APR, productionPhases)) {
					// count if 1st apr <CURRENT_FYEAR> is a timepoint in the 'active', 'phaseIn' or 'phaseOut' lifecycle phase
					baselineApr++;
				} else if (endOfLifePhase && endOfLifePhase.startDate === APR) {
					// application is in time frame, but it's decommissioned on APR, still count to baseline
					baselineApr++;
				}
				if (this._isTimestampInOnePhase(CURRENT, productionPhases)) {
					// count if <CURRENT_DATE> is a timepoint in the 'active', 'phaseIn' or 'phaseOut' lifecycle phase
					baselineToday++;
				} else if (endOfLifePhase && endOfLifePhase.startDate === CURRENT) {
					// application is in time frame, but it's decommissioned on CURRENT, still count to baseline
					baselineToday++;
				}
				if (this._isTimestampInOnePhase(MAR, productionPhases)) {
					// count if 31th mar <CURRENT_FYEAR + 1> is a timepoint in the 'active', 'phaseIn' or 'phaseOut' lifecycle phase
					baselineMar++;
				}
				// application decommissioning or decommissioned this FY?
				// 'endOfLife' phase start date must be between 1st apr <CURRENT_FYEAR> and 31th mar <CURRENT_FYEAR + 1> (both inclusive)
				if (this._isLifecyclePhaseStartDateIn(endOfLifePhase, APR, MAR, false, false)) {
					// planned (decommissioning) or actuals (decommissioned)?
					// NOTE: baseline CURRENT is at the beginning, so end of life counts to planned if it's equal to CURRENT
					if (endOfLifePhase.startDate >= CURRENT) {
						decommissionsPlanned++;
					} else {
						decommissionsActuals++;
					}
				}
				// application commissioning or commissioned this FY?
				// 'active' phase start date must be between 1st apr <CURRENT_FYEAR> and 31th mar <CURRENT_FYEAR + 1> (both inclusive)
				if (this._isLifecyclePhaseStartDateIn(activePhase, APR, MAR, false, false)) {
					// planned (commissioning) or actuals (commissioned)?
					// NOTE: baseline CURRENT is at the beginning, so production counts to actuals if it's equal to CURRENT
					if (activePhase.startDate > CURRENT) {
						commissionsPlanned++;
					} else {
						commissionsActuals++;
					}
				}
			});
			const marketEnum = this._getOptionKeyFromValue(this.MARKET_OPTIONS, market);
			tableData.push({
				id: market,
				market: marketEnum,
				baselineApr: baselineApr,
				decommissionsPlanned: decommissionsPlanned,
				decommissionsActuals: decommissionsActuals,
				commissionsPlanned: commissionsPlanned,
				commissionsActuals: commissionsActuals,
				baselineMar: baselineMar,
				baselineToday: baselineToday
			});
		}
		lx.hideSpinner();
		this.setState({
			data: tableData
		});
	}

	_addLifecyclePhaseEnd(lifecycles, phase) {
		if (!lifecycles || !phase || !phase.phase) {
			return;
		}
		let nextPhaseKey = this._getNextPhaseKey(phase.phase);
		let nextPhase = Utilities.getLifecyclePhase(lifecycles, nextPhaseKey);
		while (!nextPhase) {
			nextPhaseKey = this._getNextPhaseKey(nextPhaseKey);
			if (!nextPhaseKey) {
				break;
			}
			nextPhase = Utilities.getLifecyclePhase(lifecycles, nextPhaseKey);
		}
		if (nextPhase) {
			phase.endDate = nextPhase.startDate;
		}
	}

	_getNextPhaseKey(phase) {
		switch (phase) {
			case PLAN:
				return PHASE_IN;
			case PHASE_IN:
				return ACTIVE;
			case ACTIVE:
				return PHASE_OUT;
			case PHASE_OUT:
				return END_OF_LIFE;
			case END_OF_LIFE:
			default:
				return;
		}
	}

	_isTimestampInOnePhase(timestamp, phases) {
		if (timestamp === undefined || timestamp === null || !phases) {
			return false;
		}
		return phases.some((e) => {
			return this._isTimestampInPhase(e, timestamp);
		});
	}

	_isTimestampInPhase(phase, timestamp) {
		if (!phase || timestamp === undefined || timestamp === null) {
			return false;
		}
		const startDate = phase.startDate;
		const endDate = phase.endDate;
		if (startDate !== undefined && startDate !== null) {
			return (endDate !== undefined && endDate !== null)
				? (startDate <= timestamp && timestamp < endDate)
				: (startDate <= timestamp);
		} else if (endDate !== undefined && endDate !== null) {
			return timestamp < endDate;
		}
		return false;
	}

	_isLifecyclePhaseStartDateIn(lifecycle, from, to, fromExclusive, toExclusive) {
		return lifecycle
			&& (fromExclusive ? lifecycle.startDate > from : lifecycle.startDate >= from)
			&& (toExclusive ? lifecycle.startDate < to : lifecycle.startDate <= to);
	}

	_getOptionKeyFromValue(options, value) {
		if (!value) {
			return undefined;
		}
		const key = Utilities.getKeyToValue(options, value);
		return key !== undefined && key !== null ? parseInt(key, 10) : undefined;
	}

	_onMultiSelectChange(values) {
		this.setState({
			multiSelectValues: values
		});
	}

	render() {
		if (this.state.data.length === 0) {
			return (
Loading data...
);
		}
		let data = this.state.data;
		let marketOptions = Utilities.copyObject(this.MARKET_OPTIONS);
		if (this.state.multiSelectValues.length > 0) {
			// filter table data
			data = data.filter((e) => {
				return this.state.multiSelectValues.some((e2) => {
					const key = Utilities.getKeyToValue(this.MARKET_OPTIONS, e2);
					return key && e.market === parseInt(key);
				});
			});
			// filter market options for table only
			for (let key in this.MARKET_OPTIONS) {
				const value = this.MARKET_OPTIONS[key];
				if (!this.state.multiSelectValues.includes(value)) {
					delete marketOptions[key];
				}
			}
		}
		// add & compute the 'total' row
		const totalOptionKey = Object.keys(this.MARKET_OPTIONS).length + 1;
		marketOptions[totalOptionKey] = 'total';
		const total = {
			id: 'total',
			market: totalOptionKey,
			baselineApr: 0,
			decommissionsPlanned: 0,
			decommissionsActuals: 0,
			commissionsPlanned: 0,
			commissionsActuals: 0,
			baselineMar: 0,
			baselineToday: 0
		};
		data.forEach((e) => {
			total.baselineApr += e.baselineApr;
			total.decommissionsPlanned += e.decommissionsPlanned;
			total.decommissionsActuals += e.decommissionsActuals;
			total.commissionsPlanned += e.commissionsPlanned;
			total.commissionsActuals += e.commissionsActuals;
			total.baselineMar += e.baselineMar;
			total.baselineToday += e.baselineToday;
		});
		data.push(total);
		return (

				<MultiSelectField
					label='Markets to show'
					placeholder='Select a market'
					items={this.MARKET_OPTIONS}
					onChange={this._onMultiSelectChange}
					values={this.state.multiSelectValues} />

		);
	}
}

export default Report;
<|endoftext|>


<commit_before>var price;
var quanlity;
var total;

price = 5;
quanlity = 14;
total = price * quanlity;

//document.write("Total is" + total);
var totalPriceEle= document.getElementById("totalPrice");
totalPriceEle.textContent = "$"+ total;
<commit_msg>no message<commit_after>var price =[10,5,1];
var products = ["Stamford T-Shirt", "Stamford Notebook", "Stamford Wristband"];
var total = 0;

//calculate the total price below
var productList= document.getElementById("productList");
productList.innerHTML += "
" +products[0] +": $" + price[0] +"
"
productList.innerHTML += "
" +products[0] +": $" + price[0] +"
"
productList.innerHTML += "
" +products[0] +": $" + price[0] +"
"

//Display purchase product to the screen
total = price[0];

//document.write("Total is" + total);
var totalPriceEle= document.getElementById("totalPrice");
totalPriceEle.textContent = "$"+ total;
<|endoftext|>


<commit_before>var price =[10,5,1];
var products = ["Stamford T-Shirt", "Stamford Notebook", "Stamford Wristband"];
var total = 0;

//calculate the total price below
var productList= document.getElementById("productList");
productList.innerHTML += "
" +products[0] +": $" + price[0] +"
"
productList.innerHTML += "
" +products[0] +": $" + price[0] +"
"
productList.innerHTML += "
" +products[0] +": $" + price[0] +"
"

//Display purchase product to the screen
total = price[0];

//document.write("Total is" + total);
var totalPriceEle= document.getElementById("totalPrice");
totalPriceEle.textContent = "$"+ total;
<commit_msg>no message<commit_after>var price =[10,5,1];
var products = ["Stamford T-Shirt", "Stamford Notebook", "Stamford Wristband"];
var total = 0;

//calculate the total price below
var productList= document.getElementById("productList");
productList.innerHTML += "
" +products[0] +": $" + price[0] +"
"

//Display purchase product to the screen
total = price[0];

//document.write("Total is" + total);
var totalPriceEle= document.getElementById("totalPrice");
totalPriceEle.textContent = "$"+ total;
<|endoftext|>


<commit_before>// used in profile banner
Handlebars.registerHelper("formatPhoneNumber", function(str) {
    if (str.length == 10) {
        return str.replace(/(\d{3})(\d{3})(\d{4})/, '$1-$2-$3');
    }
    return str
});

// used on Library card
Handlebars.registerHelper("toFromNowDate", function(str) {
    return moment(new Date(str)).fromNow();
});

// used on Grade, Library card
Handlebars.registerHelper("toFriendlyDate", function(str) {
    return moment(new Date(str)).format("ddd, MMM D");
});

Handlebars.registerHelper("toUrlSafe", function(str) {
    return str.replace(/ /g, "%20");
});

Handlebars.registerHelper("toLowerCase", function(str) {
    if (str) {
        return str.toLowerCase();
    }
    return str;
});

// convert term string from "2013,summer,a-term" to "summer a-term"
Handlebars.registerHelper("termNoYear", function(term) {
    value = term.split(",");
    str = value[1];
    if (value[2]) {
        str += " " + value[2];
    }
    return str;
});

Handlebars.registerHelper("capitalizeString", function(str) {
    return capitalizeString(str);
});

// convert term string from "2013,summer,a-term" to "Summer 2013 A-Term"
Handlebars.registerHelper("titleFormatTerm", function(term) {
    value = term.split(",");
    str = capitalizeString(value[1]) + " " + value[0];
    if (value[2]) {
        str += " " + capitalizeString(value[2]);
    }
    return str;
});

// Google maps gets very confused by some characters in map urls
Handlebars.registerHelper("encodeForMaps", function(str) {
    str = str.replace(/ \(/g, " - ");
    str = str.replace(/[\)&]/g, "");
    str = encodeURIComponent(str);
    return str;
});

//probably extraneous
Handlebars.registerHelper("formatTime", function(time) {
    formatted = time.toString().split(":");
    formatted[0] = parseInt(formatted[0], 10);
    if (formatted[0] > 12) {
        formatted[0] -= 12;
    }
    return formatted.join(":");
});

//converts 24 hour time to 12 hour
Handlebars.registerHelper("formatTimeAMPM", function(time) {
    formatted = time.toString().split(":");
    formatted[0] = parseInt(formatted[0], 10);
    if (formatted[0] < 12) {
        formatted[1] += "AM";
    }
    else {
        formatted[1] += "PM";
    }

    if (formatted[0] > 12) {
        formatted[0] = formatted[0] - 12;
    }
    return formatted.join(":");
});

// converts date string into 12 hour display - no am/pm
Handlebars.registerHelper("formatDateAsTime", function(date_str) {
    var date = date_from_string(date_str);
    var hours = date.getHours();
    var minutes = date.getMinutes();
    if (minutes < 10) {
        minutes = "0"+minutes;
    }

    if (hours > 12) {
        hours = hours - 12;
    }
    return hours + ":" + minutes;
});

// converts date string into 12 hour am/pm display
Handlebars.registerHelper("formatDateAsTimeAMPM", function(date_str) {
    var date = date_from_string(date_str);
    var hours = date.getHours();
    var minutes = date.getMinutes();
    var am_pm;
    if (hours < 12) {
        am_pm = "AM";
    }
    else {
        am_pm = "PM";
    }

    if (minutes < 10) {
        minutes = "0"+minutes;
    }
    if (hours > 12) {
        hours = hours - 12;
    }
    return hours + ":" + minutes + am_pm;
});

// converts date string into a day display
Handlebars.registerHelper("formatDateAsDate", function(date_str) {
    var date = date_from_string(date_str);
    var day_of_week = date.getDay();
    var month_num = date.getMonth();
    var day_of_month = date.getDate();

    var day_names = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
    var month_names = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

    return new Handlebars.SafeString(day_names[day_of_week] + ", " + month_names[month_num] + " " + day_of_month);
});

// converts date string into the label for the final exams schedule
Handlebars.registerHelper("formatDateAsFinalsDay", function(date_str, days_back) {
    var date = date_from_string(date_str);
    date.setDate(date.getDate() - days_back);
    var day_of_week = date.getDay();
    var month_num = date.getMonth();
    var day_of_month = date.getDate();

    var month_names = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

    return month_names[month_num] + " " + day_of_month;
});

Handlebars.registerHelper("ucfirst", function(str) {
    return str.replace(/^([a-z])/, function(match) {
        return match.toUpperCase();
    });
});

Handlebars.registerHelper("formatPrice", function(price) {
    formatted = price.toString().split(".");
    if (formatted[1] && formatted[1].length == 1) {
        formatted[1] += "0";
    }
    if (!formatted[1] || formatted[1].length == 0) {
        formatted[1] = "00";
    }
    return formatted.join(".");
});

Handlebars.registerHelper('equal', function(value1, value2, options) {
    if (arguments.length < 3)
        throw new Error("Handlebars Helper equal needs 2 parameters");
    if(value1 != value2) {
        return options.inverse(this);
    }
    else {
        return options.fn(this);
    }
});

Handlebars.registerHelper("eachWithIndex", function(array, fn) {
    var buffer = "";
    for (var i = 0, j = array.length; i < j; i++) {
        var item = array[i];
        item.index = i;
        buffer += fn.fn(item);
    }
    return buffer;
});

Handlebars.registerHelper('format_schedule_hour', function(hour, position) {
    if (parseInt(hour, 10) === 12) {
        VisualSchedule.shown_am_marker = true;
        return hour + "p";
    }
    else if (hour > 12) {
        var shown_hour = hour - 12;
        if (position === 0) {
            return shown_hour + "p";
        }
        return shown_hour;
    }
    else if (hour < 12) {
        if (position === 0) {
            return hour + "a";
        }
    }
    return hour;
});

Handlebars.registerHelper('time_percentage', function(time, start, end) {
    return VisualSchedule.get_scaled_percentage(time, start, end);
});

Handlebars.registerHelper('time_percentage_height', function(start, end, min, max) {
    var top = VisualSchedule.get_scaled_percentage(start, min, max);
    var bottom = VisualSchedule.get_scaled_percentage(end, min, max);

    return bottom-top;
});

Handlebars.registerHelper('show_days_meetings', function(list, start_time, end_time) {
    if (!VisualSchedule.day_template) {
        var day_source = $("#visual_schedule_day").html();
        var _day_template = Handlebars.compile(day_source);

        VisualSchedule.day_template = _day_template;
    }

    return new Handlebars.SafeString(VisualSchedule.day_template({ meetings: list, start_time: start_time, end_time: end_time }));
});

Handlebars.registerHelper('show_days_finals', function(list, start_time, end_time, term) {
    if (!VisualSchedule.day_template) {
        var day_source = $("#finals_schedule_day").html();
        var _day_template = Handlebars.compile(day_source);

        VisualSchedule.day_template = _day_template;
    }

    return new Handlebars.SafeString(VisualSchedule.day_template({ meetings: list, start_time: start_time, end_time: end_time, term: term }));
});

Handlebars.registerHelper('show_card_days_meetings', function(list, start_time, end_time) {
    if (!VisualScheduleCard.day_template) {
        var day_source = $("#visual_schedule_card_day").html();
        var _day_template = Handlebars.compile(day_source);

        VisualScheduleCard.day_template = _day_template;
    }

    return new Handlebars.SafeString(VisualScheduleCard.day_template({ meetings: list, start_time: start_time, end_time: end_time }));
});

Handlebars.registerHelper('show_final_card_day', function(list, start_time, end_time, term) {
    if (!FinalExamCard.day_template) {
        var day_source = $("#final_exam_schedule_card_day").html();
        var _day_template = Handlebars.compile(day_source);

        FinalExamCard.day_template = _day_template;
    }

    return new Handlebars.SafeString(FinalExamCard.day_template({ meetings: list, start_time: start_time, end_time: end_time, term: term }));
});

Handlebars.registerHelper('pluralize', function(number, single, plural) {
    if (number === 1) {
        return single;
    }
    return plural;
});

Handlebars.registerHelper('pluralize_by_size', function(list, single, plural) {
    if (list.length === 1) {
        return single;
    }
    return plural;
});

Handlebars.registerHelper('greater_than', function(value1, value2, options) {
    if (arguments.length < 3)
        throw new Error("Handlebars Helper greater_than needs 2 parameters");
    if(value1 > value2) {
        return options.inverse(this);
    }
    else {
        return options.fn(this);
    }
});
<commit_msg>Fixes MUWM-2289<commit_after>// used in profile banner
Handlebars.registerHelper("formatPhoneNumber", function(str) {
    if (str.length == 10) {
        return str.replace(/(\d{3})(\d{3})(\d{4})/, '$1-$2-$3');
    }
    return str
});

(function() {

    function parse_date(str) {
        // MUWM-2289.  Our dates come in looking like:
        // 2014-11-26 23:59:59
        // sometimes.  Rather than hunt all of those down, we can just convert
        // that to ISO-8601
        // If that's still invalid - write more code.
        var d = new Date(str);
        if (isNaN(d.getYear())) {
            d = new Date(str.replace(" ", "T"));
        }
        return d;
    }

    // used on Library card
    Handlebars.registerHelper("toFromNowDate", function(str) {
        return moment(parse_date(str)).fromNow();
    });

    // used on Grade, Library card
    Handlebars.registerHelper("toFriendlyDate", function(str) {
        return moment(parse_date(str)).format("ddd, MMM D");
    });

})();

Handlebars.registerHelper("toUrlSafe", function(str) {
    return str.replace(/ /g, "%20");
});

Handlebars.registerHelper("toLowerCase", function(str) {
    if (str) {
        return str.toLowerCase();
    }
    return str;
});

// convert term string from "2013,summer,a-term" to "summer a-term"
Handlebars.registerHelper("termNoYear", function(term) {
    value = term.split(",");
    str = value[1];
    if (value[2]) {
        str += " " + value[2];
    }
    return str;
});

Handlebars.registerHelper("capitalizeString", function(str) {
    return capitalizeString(str);
});

// convert term string from "2013,summer,a-term" to "Summer 2013 A-Term"
Handlebars.registerHelper("titleFormatTerm", function(term) {
    value = term.split(",");
    str = capitalizeString(value[1]) + " " + value[0];
    if (value[2]) {
        str += " " + capitalizeString(value[2]);
    }
    return str;
});

// Google maps gets very confused by some characters in map urls
Handlebars.registerHelper("encodeForMaps", function(str) {
    str = str.replace(/ \(/g, " - ");
    str = str.replace(/[\)&]/g, "");
    str = encodeURIComponent(str);
    return str;
});

//probably extraneous
Handlebars.registerHelper("formatTime", function(time) {
    formatted = time.toString().split(":");
    formatted[0] = parseInt(formatted[0], 10);
    if (formatted[0] > 12) {
        formatted[0] -= 12;
    }
    return formatted.join(":");
});

//converts 24 hour time to 12 hour
Handlebars.registerHelper("formatTimeAMPM", function(time) {
    formatted = time.toString().split(":");
    formatted[0] = parseInt(formatted[0], 10);
    if (formatted[0] < 12) {
        formatted[1] += "AM";
    }
    else {
        formatted[1] += "PM";
    }

    if (formatted[0] > 12) {
        formatted[0] = formatted[0] - 12;
    }
    return formatted.join(":");
});

// converts date string into 12 hour display - no am/pm
Handlebars.registerHelper("formatDateAsTime", function(date_str) {
    var date = date_from_string(date_str);
    var hours = date.getHours();
    var minutes = date.getMinutes();
    if (minutes < 10) {
        minutes = "0"+minutes;
    }

    if (hours > 12) {
        hours = hours - 12;
    }
    return hours + ":" + minutes;
});

// converts date string into 12 hour am/pm display
Handlebars.registerHelper("formatDateAsTimeAMPM", function(date_str) {
    var date = date_from_string(date_str);
    var hours = date.getHours();
    var minutes = date.getMinutes();
    var am_pm;
    if (hours < 12) {
        am_pm = "AM";
    }
    else {
        am_pm = "PM";
    }

    if (minutes < 10) {
        minutes = "0"+minutes;
    }
    if (hours > 12) {
        hours = hours - 12;
    }
    return hours + ":" + minutes + am_pm;
});

// converts date string into a day display
Handlebars.registerHelper("formatDateAsDate", function(date_str) {
    var date = date_from_string(date_str);
    var day_of_week = date.getDay();
    var month_num = date.getMonth();
    var day_of_month = date.getDate();

    var day_names = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
    var month_names = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

    return new Handlebars.SafeString(day_names[day_of_week] + ", " + month_names[month_num] + " " + day_of_month);
});

// converts date string into the label for the final exams schedule
Handlebars.registerHelper("formatDateAsFinalsDay", function(date_str, days_back) {
    var date = date_from_string(date_str);
    date.setDate(date.getDate() - days_back);
    var day_of_week = date.getDay();
    var month_num = date.getMonth();
    var day_of_month = date.getDate();

    var month_names = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

    return month_names[month_num] + " " + day_of_month;
});

Handlebars.registerHelper("ucfirst", function(str) {
    return str.replace(/^([a-z])/, function(match) {
        return match.toUpperCase();
    });
});

Handlebars.registerHelper("formatPrice", function(price) {
    formatted = price.toString().split(".");
    if (formatted[1] && formatted[1].length == 1) {
        formatted[1] += "0";
    }
    if (!formatted[1] || formatted[1].length == 0) {
        formatted[1] = "00";
    }
    return formatted.join(".");
});

Handlebars.registerHelper('equal', function(value1, value2, options) {
    if (arguments.length < 3)
        throw new Error("Handlebars Helper equal needs 2 parameters");
    if(value1 != value2) {
        return options.inverse(this);
    }
    else {
        return options.fn(this);
    }
});

Handlebars.registerHelper("eachWithIndex", function(array, fn) {
    var buffer = "";
    for (var i = 0, j = array.length; i < j; i++) {
        var item = array[i];
        item.index = i;
        buffer += fn.fn(item);
    }
    return buffer;
});

Handlebars.registerHelper('format_schedule_hour', function(hour, position) {
    if (parseInt(hour, 10) === 12) {
        VisualSchedule.shown_am_marker = true;
        return hour + "p";
    }
    else if (hour > 12) {
        var shown_hour = hour - 12;
        if (position === 0) {
            return shown_hour + "p";
        }
        return shown_hour;
    }
    else if (hour < 12) {
        if (position === 0) {
            return hour + "a";
        }
    }
    return hour;
});

Handlebars.registerHelper('time_percentage', function(time, start, end) {
    return VisualSchedule.get_scaled_percentage(time, start, end);
});

Handlebars.registerHelper('time_percentage_height', function(start, end, min, max) {
    var top = VisualSchedule.get_scaled_percentage(start, min, max);
    var bottom = VisualSchedule.get_scaled_percentage(end, min, max);

    return bottom-top;
});

Handlebars.registerHelper('show_days_meetings', function(list, start_time, end_time) {
    if (!VisualSchedule.day_template) {
        var day_source = $("#visual_schedule_day").html();
        var _day_template = Handlebars.compile(day_source);

        VisualSchedule.day_template = _day_template;
    }

    return new Handlebars.SafeString(VisualSchedule.day_template({ meetings: list, start_time: start_time, end_time: end_time }));
});

Handlebars.registerHelper('show_days_finals', function(list, start_time, end_time, term) {
    if (!VisualSchedule.day_template) {
        var day_source = $("#finals_schedule_day").html();
        var _day_template = Handlebars.compile(day_source);

        VisualSchedule.day_template = _day_template;
    }

    return new Handlebars.SafeString(VisualSchedule.day_template({ meetings: list, start_time: start_time, end_time: end_time, term: term }));
});

Handlebars.registerHelper('show_card_days_meetings', function(list, start_time, end_time) {
    if (!VisualScheduleCard.day_template) {
        var day_source = $("#visual_schedule_card_day").html();
        var _day_template = Handlebars.compile(day_source);

        VisualScheduleCard.day_template = _day_template;
    }

    return new Handlebars.SafeString(VisualScheduleCard.day_template({ meetings: list, start_time: start_time, end_time: end_time }));
});

Handlebars.registerHelper('show_final_card_day', function(list, start_time, end_time, term) {
    if (!FinalExamCard.day_template) {
        var day_source = $("#final_exam_schedule_card_day").html();
        var _day_template = Handlebars.compile(day_source);

        FinalExamCard.day_template = _day_template;
    }

    return new Handlebars.SafeString(FinalExamCard.day_template({ meetings: list, start_time: start_time, end_time: end_time, term: term }));
});

Handlebars.registerHelper('pluralize', function(number, single, plural) {
    if (number === 1) {
        return single;
    }
    return plural;
});

Handlebars.registerHelper('pluralize_by_size', function(list, single, plural) {
    if (list.length === 1) {
        return single;
    }
    return plural;
});

Handlebars.registerHelper('greater_than', function(value1, value2, options) {
    if (arguments.length < 3)
        throw new Error("Handlebars Helper greater_than needs 2 parameters");
    if(value1 > value2) {
        return options.inverse(this);
    }
    else {
        return options.fn(this);
    }
});
<|endoftext|>


<commit_before>var log = console.log.bind(console);
var version = "0.0.5";
var cacheName = "moviediary";
var cache = cacheName + "-" + version;
var filesToCache = [
    '/',
    'css/custom/loader.min.css',
    'css/font-awesome/css/font-awesome.min.css',
    'css/font-awesome/fonts/fontawesome-webfont.woff2?v=4.7.0',
    'css/custom/materialize.min.css',
    'css/fonts/roboto/Roboto-Regular.woff2',
    'css/fonts/roboto/Roboto-Medium.woff2',
    'css/fonts/roboto/Roboto-Light.woff2',
    'css/custom/base.css',
    'js/custom/loader.js',
    'css/custom/page-center.css',
    'css/clockpicker.css',
    'img/eng.svg',
    'img/est.svg',
    'img/ger.svg',
    'img/nanPosterBig.jpg',
    'img/nanPosterSmall.jpg',
    'js/custom/clockpicker.js',
    'js/custom/materialize.min.js',
    'js/custom/vertx-eventbus.js',
    'js/pages/history.js',
    'js/pages/home.js',
    'js/pages/login.js',
    'js/pages/movies.js',
    'js/pages/stats.js',
    'js/pages/user.js',
    'js/pages/wishlist.js',
    'js/chart.min.js',
    'js/jquery.min.js',
    'js/jquery-matchHeight.min.js',
    'js/sockjs.min.js'
];

self.addEventListener('install', function (event) {
    log('[ServiceWorker] Installing...');
    event.waitUntil(caches.open(cache).then(function (cache) {
        log('[ServiceWorker] Caching files');
        return cache.addAll(filesToCache);
    }));
});

self.addEventListener('fetch', function () {
    event.respondWith(caches.match(event.request).then(function (response) {
        if (response) {
            log("Fulfilling " + event.request.url + " from cache.");
            return response;
        }
        log(event.request.url + " not found in cache fetching from network.");
        var fetchRequest = event.request.clone();
        return fetch(fetchRequest).then(function (response) {
            if (!response || response.status !== 200 || response.type !== 'basic') {
                return response;
            }
            var responseToCache = response.clone();
            caches.open(cacheName).then(function (cache) {
                cache.put(event.request, responseToCache);
            });
            return response;
        });
    }));
});

self.addEventListener('activate', function (event) {
    log('[ServiceWorker] Activate');
    event.waitUntil(caches.keys().then(function (keyList) {
        return Promise.all(keyList.map(function (key) {
            if (key !== cacheName) {
                log('[ServiceWorker] Removing old cache ', key);
                return caches.delete(key);
            }
        }));
    }).then(function () {
        self.clients.claim();
    }));
});<commit_msg>service worker static files list update<commit_after>var log = console.log.bind(console);
var version = "0.0.6";
var cacheName = "moviediary";
var cache = cacheName + "-" + version;
var filesToCache = [
    '/',
    'css/custom/base.css',
    'css/custom/loader.min.css',
    'css/custom/page-center.css',
    'css/clockpicker.css',
    'img/eng.svg',
    'img/est.svg',
    'img/nanPosterBig.jpg',
    'img/nanPosterSmall.jpg',
    'js/custom/loader.js',
    'js/custom/clockpicker.js',
    'js/custom/vertx-eventbus.js',
    'js/pages/apiUtils.js',
    'js/pages/discover.js',
    'js/pages/history.js',
    'js/pages/home.js',
    'js/pages/lists.js',
    'js/pages/login.js',
    'js/pages/movies.js',
    'js/pages/series.js',
    'js/pages/stats.js'
];

self.addEventListener('install', function (event) {
    log('[ServiceWorker] Installing...');
    event.waitUntil(caches.open(cache).then(function (cache) {
        log('[ServiceWorker] Caching files');
        return cache.addAll(filesToCache);
    }));
});

self.addEventListener('fetch', function () {
    event.respondWith(caches.match(event.request).then(function (response) {
        if (response) {
            log("Fulfilling " + event.request.url + " from cache.");
            return response;
        }
        log(event.request.url + " not found in cache fetching from network.");
        var fetchRequest = event.request.clone();
        return fetch(fetchRequest).then(function (response) {
            if (!response || response.status !== 200 || response.type !== 'basic') {
                return response;
            }
            var responseToCache = response.clone();
            caches.open(cacheName).then(function (cache) {
                cache.put(event.request, responseToCache);
            });
            return response;
        });
    }));
});

self.addEventListener('activate', function (event) {
    log('[ServiceWorker] Activate');
    event.waitUntil(caches.keys().then(function (keyList) {
        return Promise.all(keyList.map(function (key) {
            if (key !== cacheName) {
                log('[ServiceWorker] Removing old cache ', key);
                return caches.delete(key);
            }
        }));
    }).then(function () {
        self.clients.claim();
    }));
});<|endoftext|>


<commit_before>/* eslint eqeqeq: 0 */

const VALID_CALLEES = ["String", "Number", "Math"];
const INVALID_METHODS = ["random"];

/**
 * Walk the input `node` and statically evaluate if it's truthy.
 *
 * Returning `true` when we're sure that the expression will evaluate to a
 * truthy value, `false` if we're sure that it will evaluate to a falsy
 * value and `undefined` if we aren't sure. Because of this please do not
 * rely on coercion when using this method and check with === if it's false.
 *
 * For example do:
 *
 *   if (t.evaluateTruthy(node) === false) falsyLogic();
 *
 * **AND NOT**
 *
 *   if (!t.evaluateTruthy(node)) falsyLogic();
 *
 */

export function evaluateTruthy(): boolean {
  var res = this.evaluate();
  if (res.confident) return !!res.value;
}

/**
 * Walk the input `node` and statically evaluate it.
 *
 * Returns an object in the form `{ confident, value }`. `confident` indicates
 * whether or not we had to drop out of evaluating the expression because of
 * hitting an unknown node that we couldn't confidently find the value of.
 *
 * Example:
 *
 *   t.evaluate(parse("5 + 5")) // { confident: true, value: 10 }
 *   t.evaluate(parse("!true")) // { confident: true, value: false }
 *   t.evaluate(parse("foo + foo")) // { confident: false, value: undefined }
 *
 */

export function evaluate(): { confident: boolean; value: any } {
  var confident = true;

  var value = evaluate(this);
  if (!confident) value = undefined;
  return {
    confident: confident,
    value:     value
  };

  function evaluate(path) {
    if (!confident) return;

    var node = path.node;

    if (path.isSequenceExpression()) {
      var exprs = path.get("expressions");
      return evaluate(exprs[exprs.length - 1]);
    }

    if (path.isLiteral()) {
      if (node.regex) {
        // we have a regex and we can't represent it natively
      } else {
        return node.value;
      }
    }

    if (path.isConditionalExpression()) {
      if (evaluate(path.get("test"))) {
        return evaluate(path.get("consequent"));
      } else {
        return evaluate(path.get("alternate"));
      }
    }

    if (path.isTypeCastExpression()) {
      return evaluate(path.get("expression"));
    }

    if (path.isIdentifier() && !path.scope.hasBinding(node.name, true)) {
      if (node.name === "undefined") {
        return undefined;
      } else if (node.name === "Infinity") {
        return Infinity;
      } else if (node.name === "NaN") {
        return NaN;
      }
    }

    // "foo".length
    if (path.isMemberExpression() && !path.parentPath.isCallExpression({ callee: node })) {
      let property = path.get("property");
      let object = path.get("object");

      if (object.isLiteral() && property.isIdentifier()) {
        let value = object.node.value;
        let type = typeof value;
        if (type === "number" || type === "string") {
          return value[property.node.name];
        }
      }
    }

    if (path.isReferencedIdentifier()) {
      var binding = path.scope.getBinding(node.name);
      if (binding && binding.hasValue) {
        return binding.value;
      } else {
        var resolved = path.resolve();
        if (resolved === path) {
          return confident = false;
        } else {
          return evaluate(resolved);
        }
      }
    }

    if (path.isUnaryExpression({ prefix: true })) {
      var arg = evaluate(path.get("argument"));
      switch (node.operator) {
        case "void": return undefined;
        case "!": return !arg;
        case "+": return +arg;
        case "-": return -arg;
        case "~": return ~arg;
      }
    }

    if (path.isArrayExpression() || path.isObjectExpression()) {
      // we could evaluate these but it's probably impractical and not very useful
    }

    if (path.isLogicalExpression()) {
      let left = evaluate(path.get("left"));
      let right = evaluate(path.get("right"));

      switch (node.operator) {
        case "||": return left || right;
        case "&&": return left && right;
      }
    }

    if (path.isBinaryExpression()) {
      let left = evaluate(path.get("left"));
      let right = evaluate(path.get("right"));

      switch (node.operator) {
        case "-": return left - right;
        case "+": return left + right;
        case "/": return left / right;
        case "*": return left * right;
        case "%": return left % right;
        case "**": return left ** right;
        case "<": return left < right;
        case ">": return left > right;
        case "<=": return left <= right;
        case ">=": return left >= right;
        case "==": return left == right;
        case "!=": return left != right;
        case "===": return left === right;
        case "!==": return left !== right;
      }
    }

    if (path.isCallExpression()) {
      var callee = path.get("callee");
      var context;
      var func;

      // Number(1);
      if (callee.isIdentifier() && !path.scope.getBinding(callee.node.name, true) && VALID_CALLEES.indexOf(callee.node.name) >= 0) {
        func = global[node.callee.name];
      }

      if (callee.isMemberExpression()) {
        let object = callee.get("object");
        var property = callee.get("property");

        // Math.min(1, 2)
        if (object.isIdentifier() && property.isIdentifier() && VALID_CALLEES.indexOf(object.node.name) >= 0 && INVALID_METHODS.indexOf(property.node.name) < 0) {
          context = global[object.node.name];
          func = context[property.node.name];
        }

        // "abc".charCodeAt(4)
        if (object.isLiteral() && property.isIdentifier()) {
          let type = typeof object.node.value;
          if (type === "string" || type === "number") {
            context = object.node.value;
            func = context[property.node.name];
          }
        }
      }

      if (func) {
        var args = path.get("arguments").map(evaluate);
        if (!confident) return;

        return func.apply(context, args);
      }
    }

    confident = false;
  }
}
<commit_msg>add support for evaluating template literals<commit_after>/* eslint eqeqeq: 0 */

const VALID_CALLEES = ["String", "Number", "Math"];
const INVALID_METHODS = ["random"];

/**
 * Walk the input `node` and statically evaluate if it's truthy.
 *
 * Returning `true` when we're sure that the expression will evaluate to a
 * truthy value, `false` if we're sure that it will evaluate to a falsy
 * value and `undefined` if we aren't sure. Because of this please do not
 * rely on coercion when using this method and check with === if it's false.
 *
 * For example do:
 *
 *   if (t.evaluateTruthy(node) === false) falsyLogic();
 *
 * **AND NOT**
 *
 *   if (!t.evaluateTruthy(node)) falsyLogic();
 *
 */

export function evaluateTruthy(): boolean {
  var res = this.evaluate();
  if (res.confident) return !!res.value;
}

/**
 * Walk the input `node` and statically evaluate it.
 *
 * Returns an object in the form `{ confident, value }`. `confident` indicates
 * whether or not we had to drop out of evaluating the expression because of
 * hitting an unknown node that we couldn't confidently find the value of.
 *
 * Example:
 *
 *   t.evaluate(parse("5 + 5")) // { confident: true, value: 10 }
 *   t.evaluate(parse("!true")) // { confident: true, value: false }
 *   t.evaluate(parse("foo + foo")) // { confident: false, value: undefined }
 *
 */

export function evaluate(): { confident: boolean; value: any } {
  var confident = true;

  var value = evaluate(this);
  if (!confident) value = undefined;
  return {
    confident: confident,
    value:     value
  };

  function evaluate(path) {
    if (!confident) return;

    var node = path.node;

    if (path.isSequenceExpression()) {
      var exprs = path.get("expressions");
      return evaluate(exprs[exprs.length - 1]);
    }

    if (path.isLiteral()) {
      if (node.regex) {
        // we have a regex and we can't represent it natively
      } else {
        return node.value;
      }
    }

    if (path.isTemplateLiteral()) {
      var str = "";

      var i = 0;
      var exprs = path.get("expressions");

      for (let elem of (node.quasis: Array)) {
        // not confident, evaluated an expression we don't like
        if (!confident) break;

        // add on cooked element
        str += elem.value.cooked;

        // add on interpolated expression if it's present
        var expr = exprs[i++];
        if (expr) str += String(evaluate(expr));
      }

      if (confident) return str;
    }

    if (path.isConditionalExpression()) {
      if (evaluate(path.get("test"))) {
        return evaluate(path.get("consequent"));
      } else {
        return evaluate(path.get("alternate"));
      }
    }

    if (path.isTypeCastExpression()) {
      return evaluate(path.get("expression"));
    }

    if (path.isIdentifier() && !path.scope.hasBinding(node.name, true)) {
      if (node.name === "undefined") {
        return undefined;
      } else if (node.name === "Infinity") {
        return Infinity;
      } else if (node.name === "NaN") {
        return NaN;
      }
    }

    // "foo".length
    if (path.isMemberExpression() && !path.parentPath.isCallExpression({ callee: node })) {
      let property = path.get("property");
      let object = path.get("object");

      if (object.isLiteral() && property.isIdentifier()) {
        let value = object.node.value;
        let type = typeof value;
        if (type === "number" || type === "string") {
          return value[property.node.name];
        }
      }
    }

    if (path.isReferencedIdentifier()) {
      var binding = path.scope.getBinding(node.name);
      if (binding && binding.hasValue) {
        return binding.value;
      } else {
        var resolved = path.resolve();
        if (resolved === path) {
          return confident = false;
        } else {
          return evaluate(resolved);
        }
      }
    }

    if (path.isUnaryExpression({ prefix: true })) {
      var arg = evaluate(path.get("argument"));
      switch (node.operator) {
        case "void": return undefined;
        case "!": return !arg;
        case "+": return +arg;
        case "-": return -arg;
        case "~": return ~arg;
      }
    }

    if (path.isArrayExpression() || path.isObjectExpression()) {
      // we could evaluate these but it's probably impractical and not very useful
    }

    if (path.isLogicalExpression()) {
      let left = evaluate(path.get("left"));
      let right = evaluate(path.get("right"));

      switch (node.operator) {
        case "||": return left || right;
        case "&&": return left && right;
      }
    }

    if (path.isBinaryExpression()) {
      let left = evaluate(path.get("left"));
      let right = evaluate(path.get("right"));

      switch (node.operator) {
        case "-": return left - right;
        case "+": return left + right;
        case "/": return left / right;
        case "*": return left * right;
        case "%": return left % right;
        case "**": return left ** right;
        case "<": return left < right;
        case ">": return left > right;
        case "<=": return left <= right;
        case ">=": return left >= right;
        case "==": return left == right;
        case "!=": return left != right;
        case "===": return left === right;
        case "!==": return left !== right;
      }
    }

    if (path.isCallExpression()) {
      var callee = path.get("callee");
      var context;
      var func;

      // Number(1);
      if (callee.isIdentifier() && !path.scope.getBinding(callee.node.name, true) && VALID_CALLEES.indexOf(callee.node.name) >= 0) {
        func = global[node.callee.name];
      }

      if (callee.isMemberExpression()) {
        let object = callee.get("object");
        var property = callee.get("property");

        // Math.min(1, 2)
        if (object.isIdentifier() && property.isIdentifier() && VALID_CALLEES.indexOf(object.node.name) >= 0 && INVALID_METHODS.indexOf(property.node.name) < 0) {
          context = global[object.node.name];
          func = context[property.node.name];
        }

        // "abc".charCodeAt(4)
        if (object.isLiteral() && property.isIdentifier()) {
          let type = typeof object.node.value;
          if (type === "string" || type === "number") {
            context = object.node.value;
            func = context[property.node.name];
          }
        }
      }

      if (func) {
        var args = path.get("arguments").map(evaluate);
        if (!confident) return;

        return func.apply(context, args);
      }
    }

    confident = false;
  }
}
<|endoftext|>


<commit_before>'use strict';

let Utils = require('./Utils');

/**
 * High Roller - Achievement for wager amount (chips spent in one spin)
 */
class HighRollerAchievementCompiler {

  /**
   * Compiles a high roller achievement object to a trigger object.
   */
  static compile(hr_object) {
    let rank = Utils.checkNonEmptyString(hr_object.rank);
    let wager = Utils.checkNumber(hr_object.wager);
    let bonus = Utils.checkNumber(hr_object.bonus);
    let xp = Utils.checkNumber(hr_object.xp);
    if (wager < 0) throw new RangeError('Invalid wager value');
    if (bonus < 0) throw new RangeError('Invalid bonus value');
    if (xp < 0) throw new RangeError('Invalid xp value');
    let name = 'hr_' + rank;
    let trigger_object = {
      'name': name,
      'queue': 'hr',
      'target': 'spin',
      'condition': {
        'wager': { '$gte': wager }
      },
      'action': {
        '$push': {
          'mails': {
            'name': name,
            'bonus': bonus,
            'xp': xp
          }
        }
      }
    };
    //TODO: trigger_object.__proto__ = Trigger.prototype;
    return trigger_object;
  }

}

module.exports = HighRollerAchievementCompiler;
<commit_msg>Updated to use new Utils methods; Updated variable style; Updated "let" to "const"<commit_after>'use strict';

const Utils = require('./Utils');

/**
 * High Roller - Achievement for wager amount (chips spent in one spin)
 */
class HighRollerAchievementCompiler {

  /**
   * Compiles a high roller achievement object to a trigger object.
   */
  static compile(hr_object) {
    const rank = Utils.checkNonEmptyString(hr_object.rank);
    const wager = Utils.checkNumberGTE(hr_object.wager, 0);
    const xp = Utils.checkNumberGTE(hr_object.xp, 0);
    const bonus = Utils.checkNumberGTE(hr_object.bonus, 0);
    const name = 'hr_' + rank;
    const trigger_object = {
      'name': name,
      'queue': 'hr',
      'target': 'spin',
      'condition': {
        'wager': { '$gte': wager }
      },
      'action': {
        '$push': {
          'mails': {
            'name': name,
            'xp': xp,
            'bonus': bonus
          }
        }
      }
    };
    //TODO: trigger_object.__proto__ = Trigger.prototype;
    return trigger_object;
  }

}

module.exports = HighRollerAchievementCompiler;
<|endoftext|>


<commit_before>import addCommas from '../../system/addCommas';
import closestTr from '../../common/closestTr';
import createDiv from '../../common/cElement/createDiv';
import getCombat from './getCombat';
import insertElement from '../../common/insertElement';
import insertHtmlAfterBegin from '../../common/insertHtmlAfterBegin';
import querySelectorArray from '../../common/querySelectorArray';

const green = 'fshGreen';
const red = 'fshRed';

const notGuildCombat = ([, msgHtml]) => !/\(Guild Conflict\)/.test(msgHtml);
const getCombats = async ([r, msgHtml]) => [
  r, msgHtml, await getCombat(r, /combat_id=(\d+)/.exec(msgHtml)[1]),
];

function parseCombatWinner(r, msgHtml) {
  const victory = /You were victorious over/.test(msgHtml);
  if (victory) {
    return [green, `You were <span class="${green}">victorious</span> over `];
  }
  const defeat = /You were defeated by/.test(msgHtml);
  if (defeat) {
    return [red, `You were <span class="${red}">defeated</span> by `];
  }
  return ['', r.cells[2].firstChild];
}

function result(stat, desc, color) {
  if (stat !== 0) {
    return `${desc}:<span class="${color}">${addCommas(stat)}</span> `;
  }
  return '';
}

function highlightSpecials(acc, el) {
  if (el.id === 18) {
    return `${acc}
${
      el.params[0]} leeched the buff '${el.params[1]}'.`;
  }
  if (el.id === 21) {
    return `${acc}
${
      el.params[0]} was mesmerized by Spell Breaker, losing the '${
      el.params[1]}' buff.`;
  }
  return acc;
}

function parseCombat(json, color) {
  return result(json.r.xp_gain, 'XP stolen', color)
    + result(json.r.gold_gain, 'Gold lost', color)
    + result(json.r.gold_stolen, 'Gold stolen', color)
    + result(json.r.pvp_prestige_gain, 'Prestige gain', color)
    + result(json.r.pvp_rating_change, 'PvP change', color)
    + json.r.specials.reduce(highlightSpecials, '');
}

function updateTd([r, msgHtml, json]) {
  const [color, pre] = parseCombatWinner(r, msgHtml);
  const summaryDiv = parseCombat(json, color);
  r.cells[2].firstChild.remove();
  insertHtmlAfterBegin(r.cells[2], pre);
  insertElement(r.cells[2], createDiv({ innerHTML: summaryDiv }));
}

export default async function addPvPSummary(logTable) {
  const combatLinks = querySelectorArray('a[href*="&combat_id="]', logTable);
  if (combatLinks.length === 0) { return; }
  const combatRows = combatLinks.map(closestTr);
  const withHtml = combatRows.map((r) => [r, r.cells[2].innerHTML]);
  const notGuild = withHtml.filter(notGuildCombat);
  const combats = await Promise.all(notGuild.map(getCombats));
  const goodCombats = combats.filter(([, , json]) => json && json.s);
  goodCombats.forEach(updateTd);
}
<commit_msg>PvP Summary bug fixes<commit_after>import addCommas from '../../system/addCommas';
import closestTr from '../../common/closestTr';
import { combatSelector } from '../../support/constants';
import createDiv from '../../common/cElement/createDiv';
import getCombat from './getCombat';
import insertElement from '../../common/insertElement';
import insertHtmlAfterBegin from '../../common/insertHtmlAfterBegin';
import querySelector from '../../common/querySelector';
import querySelectorArray from '../../common/querySelectorArray';

const green = 'fshGreen';
const red = 'fshRed';

const isPvp = ([r]) => querySelector(combatSelector, r);
const notGuildCombat = ([, msgHtml]) => !/\(Guild Conflict\)/.test(msgHtml);
const getCombats = async ([r, msgHtml]) => [
  r, msgHtml, await getCombat(r, /combat_id=(\d+)/.exec(msgHtml)[1]),
];

function parseCombatWinner(r, msgHtml) {
  const victory = /You were victorious over/.test(msgHtml);
  if (victory) {
    return [green, `You were <span class="${green}">victorious</span> over `];
  }
  const defeat = /You were defeated by/.test(msgHtml);
  if (defeat) {
    return [red, `You were <span class="${red}">defeated</span> by `];
  }
  return ['', r.cells[2].firstChild.textContent];
}

function result(stat, desc, color) {
  if (stat !== 0) {
    return `${desc}:<span class="${color}">${addCommas(stat)}</span> `;
  }
  return '';
}

function highlightSpecials(acc, el) {
  if (el.id === 18) {
    return `${acc}
${
      el.params[0]} leeched the buff '${el.params[1]}'.`;
  }
  if (el.id === 21) {
    return `${acc}
${
      el.params[0]} was mesmerized by Spell Breaker, losing the '${
      el.params[1]}' buff.`;
  }
  return acc;
}

function parseCombat(json, color) {
  return result(json.r.xp_gain, 'XP stolen', color)
    + result(json.r.gold_gain, 'Gold lost', color)
    + result(json.r.gold_stolen, 'Gold stolen', color)
    + result(json.r.pvp_prestige_gain, 'Prestige gain', color)
    + result(json.r.pvp_rating_change, 'PvP change', color)
    + json.r.specials.reduce(highlightSpecials, '');
}

function updateTd([r, msgHtml, json]) {
  const [color, pre] = parseCombatWinner(r, msgHtml);
  const summaryDiv = parseCombat(json, color);
  r.cells[2].firstChild.remove();
  insertHtmlAfterBegin(r.cells[2], pre);
  insertElement(r.cells[2], createDiv({ innerHTML: summaryDiv }));
}

export default async function addPvPSummary(logTable) {
  const combatLinks = querySelectorArray('a[href*="&combat_id="]', logTable);
  if (combatLinks.length === 0) { return; }
  const combatRows = combatLinks.map(closestTr).filter(isPvp);
  const withHtml = combatRows.map((r) => [r, r.cells[2].innerHTML]);
  const notGuild = withHtml.filter(notGuildCombat);
  const combats = await Promise.all(notGuild.map(getCombats));
  const goodCombats = combats.filter(([, , json]) => json && json.s);
  goodCombats.forEach(updateTd);
}
<|endoftext|>