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

import * as React from 'react';
import {
  events,
  client,
  SkillStateProgression,
  SkillStateStatusEnum,
} from 'camelot-unchained';
import { cx } from 'react-emotion';

import SkillButtonView from './SkillButtonView';
import skillStateConnector from './SkillStateConnector';
import {
  getClassNames,
  makeGlowPathFor,
  SkillStateInfo,
  InterruptedState,
  HitState,
  StartCastState,
} from './lib';
export * from './lib';

export interface SkillButtonProps {
  skillState?: SkillStateInfo;
  children?: React.ReactNode;
  name: string;
  description: any;
  index: number;
}

interface RingState {
  current: number;
}

export interface SkillButtonState {
  outer: RingState;
  inner: RingState;
  label: string;
  startCast: boolean;
  hit: boolean;
}

interface RingTimer {
  event: {
    when: number;
    remaining: number;
    direction: number;
    clockwise: boolean;
  };
  timer: any;
}

const INNER = 0;
const OUTER = 1;
const CLOCKWISE = true;

class SkillButton extends React.PureComponent<SkillButtonProps, SkillButtonState> {

  private rings: RingTimer[] = [undefined, undefined];
  private listener: any;
  private prevEvent: SkillStateInfo;
  private startCastTimeout: any;
  private hitTimeout: any;

  constructor(props: SkillButtonProps) {
    super(props);
    this.state = {
      outer: {
        current: 0,
      },
      inner: {
        current: 0,
      },
      label: '',
      startCast: false,
      hit: false,
    };
  }

  public render() {
    const props = this.props;
    if (props.skillState && props.skillState.info) {
      // extract button state from props
      const { timing, disruption } = props.skillState;

      const outer = 'M 29.999 6 A 25 25 0 1 0 30 6 Z';
      const inner = 'M 29.999 9 A 22 22 0 1 0 30 9 Z';

      const classNames: string[] = getClassNames(props.skillState);

      const x = 30;
      const y = 30;
      const outerRadius = 25;
      const innerRadius = 22;
      const outerDirection = this.rings[OUTER] && this.rings[OUTER].event.clockwise;
      const innerDirection = this.rings[INNER] && this.rings[INNER].event.clockwise;

      let outerPath;
      let innerPath;

      // Includes a timer, render timer in outer circle
      if (timing) {
        if (!disruption || disruption.current < disruption.end) {
          innerPath = makeGlowPathFor(timing.end, this.state.inner.current, x, y, innerRadius, innerDirection);
        }
      }

      if (disruption) {
        if (disruption.current >= disruption.end) {
          classNames.push(InterruptedState);
          innerPath = makeGlowPathFor(500, this.state.inner.current, x, y, innerRadius, innerDirection);
        }
        outerPath = makeGlowPathFor(disruption.end, this.state.outer.current || 0, x, y, outerRadius, outerDirection);
      } else {
        outerPath = makeGlowPathFor(360, 0, x, y, outerRadius, outerDirection);
      }

      if (this.state.hit) {
        outerPath = makeGlowPathFor(360, 359.9, x, y, outerRadius, outerDirection);
        classNames.push(HitState);
      } else if (this.hitTimeout && !this.state.hit) {
        clearTimeout(this.hitTimeout);
      }

      if (this.state.startCast) {
        outerPath = makeGlowPathFor(360, 359.9, x, y, outerRadius, outerDirection);
        classNames.push(StartCastState);
      } else if (this.startCastTimeout && !this.state.startCast) {
        clearTimeout(this.startCastTimeout);
      }

      // output button
      return (
        <SkillButtonView
          skillState={this.props.skillState}
          name={this.props.name}
          description={this.props.description}
          timer={this.state.label}
          outer={outer}
          outerPath={outerPath || outer}
          inner={inner}
          innerPath={innerPath || inner}
          classNames={cx(classNames)}
          onSkillClick={this.performAbility}
        />
      );
    }

    return null;
  }

  public componentWillReceiveProps(nextProps: SkillButtonProps) {
    if (!this.listener) {
      const { id } = (nextProps.skillState);
      this.listener = events.on('skillsbutton-' + id, (data: SkillStateInfo) => this.processEvent(data));
    }
  }
<commit_msg>Set timeouts equal to null after clearing them<commit_after>
/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

import * as React from 'react';
import {
  events,
  client,
  SkillStateProgression,
  SkillStateStatusEnum,
} from 'camelot-unchained';
import { cx } from 'react-emotion';

import SkillButtonView from './SkillButtonView';
import skillStateConnector from './SkillStateConnector';
import {
  getClassNames,
  makeGlowPathFor,
  SkillStateInfo,
  InterruptedState,
  HitState,
  StartCastState,
} from './lib';
export * from './lib';

export interface SkillButtonProps {
  skillState?: SkillStateInfo;
  children?: React.ReactNode;
  name: string;
  description: any;
  index: number;
}

interface RingState {
  current: number;
}

export interface SkillButtonState {
  outer: RingState;
  inner: RingState;
  label: string;
  startCast: boolean;
  hit: boolean;
}

interface RingTimer {
  event: {
    when: number;
    remaining: number;
    direction: number;
    clockwise: boolean;
  };
  timer: any;
}

const INNER = 0;
const OUTER = 1;
const CLOCKWISE = true;

class SkillButton extends React.PureComponent<SkillButtonProps, SkillButtonState> {

  private rings: RingTimer[] = [undefined, undefined];
  private listener: any;
  private prevEvent: SkillStateInfo;
  private startCastTimeout: any;
  private hitTimeout: any;

  constructor(props: SkillButtonProps) {
    super(props);
    this.state = {
      outer: {
        current: 0,
      },
      inner: {
        current: 0,
      },
      label: '',
      startCast: false,
      hit: false,
    };
  }

  public render() {
    const props = this.props;
    if (props.skillState && props.skillState.info) {
      // extract button state from props
      const { timing, disruption } = props.skillState;

      const outer = 'M 29.999 6 A 25 25 0 1 0 30 6 Z';
      const inner = 'M 29.999 9 A 22 22 0 1 0 30 9 Z';

      const classNames: string[] = getClassNames(props.skillState);

      const x = 30;
      const y = 30;
      const outerRadius = 25;
      const innerRadius = 22;
      const outerDirection = this.rings[OUTER] && this.rings[OUTER].event.clockwise;
      const innerDirection = this.rings[INNER] && this.rings[INNER].event.clockwise;

      let outerPath;
      let innerPath;

      // Includes a timer, render timer in outer circle
      if (timing) {
        if (!disruption || disruption.current < disruption.end) {
          innerPath = makeGlowPathFor(timing.end, this.state.inner.current, x, y, innerRadius, innerDirection);
        }
      }

      if (disruption) {
        if (disruption.current >= disruption.end) {
          classNames.push(InterruptedState);
          innerPath = makeGlowPathFor(500, this.state.inner.current, x, y, innerRadius, innerDirection);
        }
        outerPath = makeGlowPathFor(disruption.end, this.state.outer.current || 0, x, y, outerRadius, outerDirection);
      } else {
        outerPath = makeGlowPathFor(360, 0, x, y, outerRadius, outerDirection);
      }

      if (this.state.hit) {
        outerPath = makeGlowPathFor(360, 359.9, x, y, outerRadius, outerDirection);
        classNames.push(HitState);
      } else if (this.hitTimeout && !this.state.hit) {
        clearTimeout(this.hitTimeout);
        this.hitTimeout = null;
      }

      if (this.state.startCast) {
        outerPath = makeGlowPathFor(360, 359.9, x, y, outerRadius, outerDirection);
        classNames.push(StartCastState);
      } else if (this.startCastTimeout && !this.state.startCast) {
        clearTimeout(this.startCastTimeout);
        this.startCastTimeout = null;
      }

      // output button
      return (
        <SkillButtonView
          skillState={this.props.skillState}
          name={this.props.name}
          description={this.props.description}
          timer={this.state.label}
          outer={outer}
          outerPath={outerPath || outer}
          inner={inner}
          innerPath={innerPath || inner}
          classNames={cx(classNames)}
          onSkillClick={this.performAbility}
        />
      );
    }

    return null;
  }

  public componentWillReceiveProps(nextProps: SkillButtonProps) {
    if (!this.listener) {
      const { id } = (nextProps.skillState);
      this.listener = events.on('skillsbutton-' + id, (data: SkillStateInfo) => this.processEvent(data));
    }
  }

{'fraction_non_alphanumeric': 0.11279631502078419, 'fraction_numerical': 0.015728569823615323, 'mean_word_length': 2.7371956339210746, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6435651', 'n_tokens_mistral': 2856, 'n_tokens_neox': 2719, 'n_words': 701}