<commit_before>import eventize from '@spearwolf/eventize'
import tinycolor from 'tinycolor2'

import ComponentRegistry from './ecs/component_registry'
import EntityManager from './ecs/entity_manager'
import ResourceLibrary from './core/resource_library'
import TextureLibrary from './core/texture_library'
import WebGlContext from './render/web_gl_context'
import WebGlRenderer from './render/web_gl_renderer'

import registerDefaultComponents from './dom/registerDefaultComponents'

const now = () => window.performance.now() / 1000

const defaultOption = (options, key, defaultValueFn) => {
  if (options && key in options) {
    return options[key]
  }
  return typeof defaultValueFn === 'function' ? defaultValueFn() : defaultValueFn
}

class App {
  constructor (options) {
    eventize(this)

    const getOption = defaultOption.bind(null, options)

    this.componentRegistry = getOption('componentRegistry', () => new ComponentRegistry())
    this.entityManager = getOption('entityManager', () => new EntityManager())
    this.resourceLibrary = getOption('resourceLibrary', () => new ResourceLibrary())
    this.textureLibrary = getOption('textureLibrary', () => new TextureLibrary())

    /**
     * @type {CanvasHTMLElement}
     */
    this.canvas = getOption('canvas', () => document.createElement('canvas'))

    /**
     * The initial attributes used to create the webgl context
     * @type {Object}
     * @see https://developer.mozilla.org/de/docs/Web/API/HTMLCanvasElement/getContext
     */
    this.contextAttributes = {
      alpha: getOption('alpha', false),
      depth: getOption('depth', false),
      stencil: getOption('stencil', false),
      antialias: getOption('antialias', false),
      premultipliedAlpha: getOption('premultipliedAlpha', false),
      preserveDrawingBuffer: getOption('preserveDrawingBuffer', false)
    }

    /**
     * Seconds since App startup
     * @type {number}
     */
    this.time = getOption('time', 0)

    /** @private */
    this.lastFrameTime = 0

    /**
     * Seconds since last frame
     * @type {number}
     */
    this.timeFrameOffset = 0

    /**
     * Frame counter since application startup
     * @type {number}
     */
    this.frameNo = getOption('frameNo', 0)

    this.clearColor = getOption('clearColor')

    this.createGlContext = getOption('createGlContext', () => () => createGlContext(this.canvas, this.contextAttributes))

    registerDefaultComponents(this.componentRegistry)

    this.entity = this.entityManager.createEntity()
    this.entity.setComponent('blitpunk', this)
    this.entity.setComponent('resourceLibrary', this.resourceLibrary)
    this.entity.setComponent('textureLibrary', this.textureLibrary)
    this.componentRegistry.createComponent(this.entity, 'children')
  }

  get clearColor () {
    return this.renderer ? this.renderer.clearColor : this._clearColor
  }

  set clearColor (color) {
    this._clearColor = color == null ? color : tinycolor(color)
    if (this.renderer) {
      this.renderer.setClearColor(this._clearColor)
    }
  }

  start (el = this) {
    this.el = el

    /**
     * @type {WebGlContext}
     */
    this.glx = new WebGlContext(this.createGlContext())

    /**
     * @type {WebGlRenderer}
     */
    this.renderer = new WebGlRenderer(this.glx)

    if (this._clearColor) {
      this.renderer.setClearColor(this._clearColor)
    }

    /**
     * Startup time in seconds.
     * @type {number}
     */
    this.startTime = now()

    this.el.appendChild(this.canvas)
    this.resize()
    this.requestAnimate()
  }

  destroy () {
    window.cancelAnimationFrame(this.rafSubscription)
  }

  requestAnimate () {
    this.rafSubscription = window.requestAnimationFrame(() => this.animate())
  }

  /**
   * Start the main animation loop.
   */
  animate () {
    this.renderFrame()
    this.requestAnimate()<commit_msg>refactor App .start() .stop() .destroy()<commit_after>import eventize from '@spearwolf/eventize'
import tinycolor from 'tinycolor2'

import ComponentRegistry from './ecs/component_registry'
import EntityManager from './ecs/entity_manager'
import ResourceLibrary from './core/resource_library'
import TextureLibrary from './core/texture_library'
import WebGlContext from './render/web_gl_context'
import WebGlRenderer from './render/web_gl_renderer'

import registerDefaultComponents from './dom/registerDefaultComponents'

const now = () => window.performance.now() / 1000

const defaultOption = (options, key, defaultValueFn) => {
  if (options && key in options) {
    return options[key]
  }
  return typeof defaultValueFn === 'function' ? defaultValueFn() : defaultValueFn
}

class App {
  constructor (options) {
    eventize(this)

    const getOption = defaultOption.bind(null, options)

    this.componentRegistry = getOption('componentRegistry', () => new ComponentRegistry())
    this.entityManager = getOption('entityManager', () => new EntityManager())
    this.resourceLibrary = getOption('resourceLibrary', () => new ResourceLibrary())
    this.textureLibrary = getOption('textureLibrary', () => new TextureLibrary())

    /**
     * @type {CanvasHTMLElement}
     */
    this.canvas = getOption('canvas', () => document.createElement('canvas'))

    /**
     * The initial attributes used to create the webgl context
     * @type {Object}
     * @see https://developer.mozilla.org/de/docs/Web/API/HTMLCanvasElement/getContext
     */
    this.contextAttributes = {
      alpha: getOption('alpha', false),
      depth: getOption('depth', false),
      stencil: getOption('stencil', false),
      antialias: getOption('antialias', false),
      premultipliedAlpha: getOption('premultipliedAlpha', false),
      preserveDrawingBuffer: getOption('preserveDrawingBuffer', false)
    }

    /**
     * Seconds since App startup
     * @type {number}
     */
    this.time = getOption('time', 0)

    /** @private */
    this.lastFrameTime = 0

    /**
     * Seconds since last frame
     * @type {number}
     */
    this.timeFrameOffset = 0

    /**
     * Frame counter since application startup
     * @type {number}
     */
    this.frameNo = getOption('frameNo', 0)

    this.clearColor = getOption('clearColor')

    this.createGlContext = getOption('createGlContext', () => () => createGlContext(this.canvas, this.contextAttributes))

    registerDefaultComponents(this.componentRegistry)

    this.entity = this.entityManager.createEntity()
    this.entity.setComponent('blitpunk', this)
    this.entity.setComponent('resourceLibrary', this.resourceLibrary)
    this.entity.setComponent('textureLibrary', this.textureLibrary)
    this.componentRegistry.createComponent(this.entity, 'children')

    this.el = null

    this.started = false
    this.stopped = false
    this.destroyed = false
  }

  get clearColor () {
    return this.renderer ? this.renderer.clearColor : this._clearColor
  }

  set clearColor (color) {
    this._clearColor = color == null ? color : tinycolor(color)
    if (this.renderer) {
      this.renderer.setClearColor(this._clearColor)
    }
  }

  get canStart () {
    return (!this.started || (this.started && this.stopped)) && !this.destroyed
  }

  start (el = this) {
    if (!this.canStart) return

    if (this.stopped) {
      this.stopped = false
      this.resize()
      this.requestAnimate()
      return
    }

    this.el = el
    this.started = true

    /**
     * @type {WebGlContext}
     */
    this.glx = new WebGlContext(this.createGlContext())

    /**
     * @type {WebGlRenderer}
     */
    this.renderer = new WebGlRenderer(this.glx)

    if (this._clearColor) {
      this.renderer.setClearColor(this._clearColor)
    }

    /**
     * Startup time in seconds.
     * @type {number}
     */
    this.startTime = now()

    this.el.appendChild(this.canvas)
    this.resize()
    this.requestAnimate()
  }

  requestAnimate () {
    this.rafSubscription = window.requestAnimationFrame(() => this.animate())
  }

  cancelAnimate () {
    window.cancelAnimationFrame(this.rafSubscription)
  }

  get canStop () {
    return this.started && !this.stopped && !this.destroyed
  }

  stop () {
    if (!this.canStop) return
    this.stopped = true
    this.cancelAnimate()
  }

  destroy () {
    if (this.destroyed) return
    this.destroyed = true
    this.cancelAnimate()
  }

  get canAnimate () {
    return this.started && !this.stopped && !this.destroyed
  }

  /**
   * Start the main animation loop.
   */
  animate () {
    if (!this.canAnimate) return
    this.renderFrame()
    this.requestAnimate()
{'fraction_non_alphanumeric': 0.13057735097786627, 'fraction_numerical': 0.0021079751727368545, 'mean_word_length': 3.265734265734266, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 23, 'https://': 2, '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': '5339385', 'n_tokens_mistral': 2550, 'n_tokens_neox': 2476, 'n_words': 513}