text:
<?php

namespace Spiral\Reactor;

use Spiral\Reactor\ClassElements\MethodElement;
use Spiral\Reactor\ClassElements\PHPConstant;
use Spiral\Reactor\ClassElements\PropertyElement;

/**
 * Represent class declaration.
 */
class ClassElement extends AbstractElement
{
    /**
     * Parent class (extends).
     *
     * @var string
     */
    private $parent = '';

    /**
     * @var array
     */
    private $interfaces = [];

    /**
     * @var array
     */
    private $constants = [];

    /**
     * @var PropertyElement[]
     */
    private $properties = [];

    /**
     * @var MethodElement[]
     */
    private $methods = [];

    /**
     * @return string
     */
    public function getParent()
    {
        return $this->parent;
    }

    /**
     * @param string $class Class name.
     * @return $this
     */
    public function setParent($class)
    {
        $this->parent = $class;

        return $this;
    }

    /**
     * Set new list of implemented interfaces.
     *
     * @param array $interfaces
     * @return $this
     */
    public function setInterfaces(array $interfaces)
    {
        $this->interfaces = $interfaces;

        return $this;
    }

    /**
     * @param string $interface
     * @return $this
     */
    public function addInterface($interface)
    {
        $interface = ltrim($interface, '\\');
        if (array_search($interface, $this->interfaces) === false) {
            $this->interfaces[] = $interface;
        }

        return $this;
    }

    /**
     * @param string $interface
     * @return $this
     */
    public function removeInterface($interface)
    {
        $interface = ltrim($interface, '\\');
        if (($index = array_search($interface, $this->interfaces)) !== false) {
            unset($this->interfaces[$index]);
        }

        return $this;
    }

    /**
     * @return array
     */
    public function getInterfaces()
    {
        return $this->interfaces;
    }

    /**
     * @param string            $name
     * @param mixed|PHPConstant $value
     * @return $this
     */
    public function setConstant($name, $value)
    {
        $this->constants[$name] = $value;

        return $this;
    }

    /**
     * @param string $name
     * @return bool
     */
    public function hasConstant($name)
    {
        return array_key_exists($name, $this->constants);
    }

    /**
     * @param string $name
     * @return $this
     */
    public function removeConstant($name)
    {
        unset($this->constants[$name]);

        return $this;
    }

    /**
     * @return array
     */
    public function getConstants()
    {
        return $this->constants;
    }

    /**
     * Get existed or create new property under given name.
     *
     * @param string $name
     * @param mixed  $docComment Forced property docComment.
     * @return PropertyElement
     */
    public function property($name, $docComment = null)
    {
        if (!$this->hasProperty($name)) {
            $this->properties[$name] = new PropertyElement($name);
        }

        !empty($docComment) && $this->properties[$name]->setComment($docComment);

        return $this->properties[$name];
    }

    /**
     * @param string $name
     * @return bool
     */
    public function hasProperty($name)
    {
        return array_key_exists($name, $this->properties);
    }

    /**
     * @param string $name
     * @return $this
     */
    public function removeProperty($name)
    {
        unset($this->properties[$name]);

        return $this;
    }

    /**
     * @return PropertyElement[]
     */
    public function getProperties()
    {
        return $this->properties;
    }

    /**
     * Get existed or create new class method.
     *
     * @param string $name       Method name.
     * @param mixed  $docComment Forced method doc comment.
     * @param array  $parameters Forced list of parameters in a form [name => type] or just names.
     * @return MethodElement
     */
    public function method($name, $docComment = null, array $parameters = [])
    {
        if (!$this->hasMethod($name)) {
            $this->methods[$name] = new MethodElement($name);
        }

        !empty($docComment) && $this->methods[$name]->setComment($docComment);

        foreach ($parameters as $parameter => $docComment) {
            if (is_numeric($parameter)) {
                //Provided as non associated array
                $this->methods[$name]->parameter($parameter = $docComment);
            } else {
                $this->methods[$name]->parameter($parameter, $docComment);
            }
        }

        return $this->methods[$name];
    }

    /**
     * @param string $name
     * @return bool
     */
    public function hasMethod($name)
    {
        return array_key_exists($name, $this->methods);
    }

    /**
     * @param string $name
     * @return $this
     */
    public function removeMethod($name)
    {
        unset($this->methods[$name]);

        return $this;
    }

    /**
     * @return MethodElement[]
     */
    public function getMethods()
    {
        return $this->methods;
    }

    /**
     * {@inheritdoc}
     */
    public function replaceComments($search, $replace)
    {
        parent::replaceComments($search, $replace);

        foreach ($this->methods as $method) {
            $method->replaceComments($search, $replace);
        }

        foreach ($this->properties as $property) {
            $property->replaceComments($search, $replace);
        }

        return $this;
    }

    /**
     * {@inheritdoc}
     *
     * @param ArraySerializer $serializer Class used to render array values for default properties and etc.
     */
    public function render($indentLevel = 0, ArraySerializer $serializer = null)
    {
        $result = [$this->renderComment($indentLevel)];
        $header = 'class ' . $this->getName() . ($this->parent ? ' extends ' . $this->parent : '');

        if (!empty($this->interfaces)) {
            $header .= ' implements ' . join(', ', $this->interfaces);
        }

        $result[] = $header;
        $result[] = "{";

        foreach ($this->constants as $constant => $value) {

            if ($value instanceof PHPConstant) {
                $value = $value->getValue();
            } else {
                $value = var_export($value, true);
            }

            $result[] = $this->indent(
                'const ' . $constant . ' = ' . $value . ';',
                $indentLevel + 1
            );
        }

        if (!empty($this->constants)) {
            //Blank line
            $result[] = '';
        }

        $position = 0;
        foreach ($this->properties as $property) {
            $result[] = $property->render($indentLevel + 1, $serializer, $position++);
        }

        foreach ($this->methods as $method) {
            $result[] = $method->render($indentLevel + 1, $position++);
        }

        $result[] = '}';

        return $this->join($result, $indentLevel);
    }

    /**
     * Copy properties, methods and constants from existed class using reflection.
     *
     * @param string $class
     * @param bool   $ownData     Copy only data declared in specified class, not in it's parents.
     * @param bool   $flushSchema Flush existed schema before copy.
     * @return $this
     */
    public function cloneSchema($class, $ownData = false, $flushSchema = true)
    {
        $reflection = new \ReflectionClass($class);

        $flushSchema && $this->flushSchema();

        !empty($reflection->getParentClass()) && $this->setParent(
            $reflection->getParentClass()->getName()
        );

        $this->setComment($reflection->getDocComment());

        $this->interfaces = array_unique(
            array_merge($this->interfaces, $reflection->getInterfaceNames())
        );

        $this->constants = array_unique(
            array_merge($this->constants, $reflection->getConstants())
        );

        foreach ($reflection->getProperties() as $property) {
            if ($ownData && !empty($reflection->getParentClass())) {
                if ($reflection->getParentClass()->hasProperty($property->getName())) {
                    continue;
                }
            }

            $this->property($property->getName())->cloneSchema($property);
        }

        foreach ($reflection->getMethods() as $method) {
            if ($ownData && !empty($reflection->getParentClass())) {
                if ($reflection->getParentClass()->hasMethod($method->getName())) {
                    continue;
                }
            }

            $this->method($method->getName())->cloneSchema($method);
        }

        return $this;
    }

    /**
     * Remove all properties, methods and constants.
     */
    public function flushSchema()
    {
        $this->properties = [];
        $this->constants = [];
        $this->methods = [];
        $this->parent = [];
        $this->interfaces = [];

        parent::flushSchema();
    }
}


text:
class gpu_program
{
public:
	REFLECTABLE(gpu_program)
	SERIALIZABLE(gpu_program)

	//-----------------------------------------------------------------------------
	//  Name : gpu_program (Constructor)
	/// <summary>
	/// Creates a program form a compute shader asset.
	/// </summary>
	gpu_program(asset_handle<gfx::shader> compute_shader);

	//-----------------------------------------------------------------------------
	//  Name : gpu_program (Constructor)
	/// <summary>
	/// Creates a program form a vertex and fragment shader assets.
	/// </summary>
	//-----------------------------------------------------------------------------
	gpu_program(asset_handle<gfx::shader> vertex_shader, asset_handle<gfx::shader> fragment_shader);

	//-----------------------------------------------------------------------------
	//  Name : begin ()
	/// <summary>
	/// Begins usage of the program. Checks validity of attached shaders and
	/// recreates the internal program if necessary.
	/// </summary>
	//-----------------------------------------------------------------------------
	bool begin();

	//-----------------------------------------------------------------------------
	//  Name : end ()
	/// <summary>
	/// Indicates end of working with a program.
	/// </summary>
	//-----------------------------------------------------------------------------
	void end();

	//-----------------------------------------------------------------------------
	//  Name : set_texture ()
	/// <summary>
	///
	///
	///
	/// </summary>
	//-----------------------------------------------------------------------------
	void set_texture(std::uint8_t _stage, const std::string& _sampler, gfx::frame_buffer* _handle,
					 uint8_t _attachment = 0,
					 std::uint32_t _flags = std::numeric_limits<std::uint32_t>::max());

	//-----------------------------------------------------------------------------
	//  Name : set_texture ()
	/// <summary>
	///
	///
	///
	/// </summary>
	//-----------------------------------------------------------------------------
	void set_texture(std::uint8_t _stage, const std::string& _sampler, gfx::texture* _texture,
					 std::uint32_t _flags = std::numeric_limits<std::uint32_t>::max());

	//-----------------------------------------------------------------------------
	//  Name : set_uniform ()
	/// <summary>
	///
	///
	///
	/// </summary>
	//-----------------------------------------------------------------------------
	void set_uniform(const std::string& _name, const void* _value, std::uint16_t _num = 1);
	void set_uniform(const std::string& _name, const math::vec4& _value, std::uint16_t _num = 1);
	void set_uniform(const std::string& _name, const math::vec3& _value, std::uint16_t _num = 1);
	void set_uniform(const std::string& _name, const math::vec2& _value, std::uint16_t _num = 1);

	//-----------------------------------------------------------------------------
	//  Name : get_uniform ()
	/// <summary>
	///
	///
	///
	/// </summary>
	//-----------------------------------------------------------------------------
	std::shared_ptr<gfx::uniform> get_uniform(const std::string& _name, bool texture = false);

	//-----------------------------------------------------------------------------
	//  Name : native_handle ()
	/// <summary>
	/// Retrieves the native handle of the internal shader program.
	/// </summary>
	//-----------------------------------------------------------------------------
	gfx::program::handle_type_t native_handle() const;

	//-----------------------------------------------------------------------------
	//  Name : get_shaders ()
	/// <summary>
	/// Retrieves the shader assets that created the shader program.
	/// </summary>
	//-----------------------------------------------------------------------------
	const std::vector<asset_handle<gfx::shader>>& get_shaders() const;

private:
	void populate();
	void attach_shader(asset_handle<gfx::shader> shader);

	/// Shaders that created this program.
	std::vector<asset_handle<gfx::shader>> shaders_;
	/// Shaders that created this program.
	std::vector<std::uint16_t> shaders_cached_;
	/// program
	std::unique_ptr<gfx::program> program_;
};

redpajama_set_name: RedPajamaGithub


text:
<?php

namespace Pb\Test\Domain\Calculator;

use Money\Money;
use Pb\Domain\Calculator\BasicCalculator;
use Pb\Domain\Calculator\Calculator;
use Pb\Domain\PriceBreakdown\TaxableCollection\TaxableCollection;
use Pb\Domain\PriceBreakdown\TaxableCollection\TaxableCollectionFactory;
use Pb\Domain\PriceBreakdown\TaxableItem\TaxableItemFactory;
use Pb\Test\Domain\PriceBreakdown\PriceBreakdownTestHelper;

/**
 * Class CalculatorTestHelper
 * @package Pb\Test\Domain\Calculator
 */
abstract class CalculatorTestHelper extends PriceBreakdownTestHelper
{
    /**
     * @param TaxableCollectionFactory $collectionFactory
     * @param TaxableItemFactory $itemFactory
     * @return Calculator
     */
    protected function getCalculator(
        TaxableCollectionFactory $collectionFactory = null, TaxableItemFactory $itemFactory = null
    )
    {
        return new BasicCalculator(
            $collectionFactory === null ? $this->getTaxableCollectionFactory() : $collectionFactory,
            $itemFactory === null ? $this->getTaxableItemFactory() : $itemFactory
        );
    }

    /**
     * @param $currencyCode
     * @return TaxableCollection
     */
    protected function getEmptyCollection($currencyCode = 'EUR')
    {
        return $this->getTaxableCollectionFactory()->build($this->getCurrency($currencyCode));
    }

    /**
     * @param TaxableCollectionFactory $taxableCollectionFactory
     * @param TaxableItemFactory $taxableItemFactory
     * @param string $currencyCode
     * @param string $conceptName
     * @param Money $gross
     * @return TaxableCollection
     */
    protected function getCollectionWithSingleItem(
        TaxableCollectionFactory $taxableCollectionFactory,
        TaxableItemFactory $taxableItemFactory,
        $currencyCode,
        $conceptName,
        Money $gross
    )
    {
        $expectedCollection = $taxableCollectionFactory->build($this->getCurrency($currencyCode));
        $expectedCollection->addUp(
            $conceptName,
            $taxableItemFactory->buildWithGross($gross)
        );
        return $expectedCollection;
    }
}


text:
package buildlet

import (
	"context"
	"fmt"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"
)

func TestBuildletClient(t *testing.T) {
	var httpCalled, OnBeginBuildletProbeCalled, OnEndBuildletProbeCalled bool
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		httpCalled = true
		fmt.Fprintln(w, "buildlet endpoint reached")
	}))
	defer ts.Close()

	u, err := url.Parse(ts.URL)
	if err != nil {
		t.Fatalf("unable to parse http server url %s", err)
	}

	kp, err := NewKeyPair()
	if err != nil {
		t.Fatalf("unable to create key pair %s", err)
	}

	opt := &VMOpts{
		TLS:                  kp,
		OnBeginBuildletProbe: func(string) { OnBeginBuildletProbeCalled = true },
		OnEndBuildletProbe:   func(*http.Response, error) { OnEndBuildletProbeCalled = true },
	}

	gotClient, gotErr := buildletClient(context.Background(), ts.URL, u.Host, opt)
	if gotErr != nil {
		t.Errorf("buildletClient(ctx, %s, %s, %v) error %s", ts.URL, u.Host, opt, gotErr)
	}
	if gotClient == nil {
		t.Errorf("client should not be nil")
	}
	if !httpCalled {
		t.Error("http endpoint never called")
	}
	if !OnBeginBuildletProbeCalled {
		t.Error("OnBeginBuildletProbe() was not called")
	}
	if !OnEndBuildletProbeCalled {
		t.Error("OnEndBuildletProbe() was not called")
	}
}

func TestBuildletClientError(t *testing.T) {
	var httpCalled, OnBeginBuildletProbeCalled, OnEndBuildletProbeCalled bool
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		httpCalled = true
		fmt.Fprintln(w, "buildlet endpoint reached")
	}))
	defer ts.Close()

	u, err := url.Parse(ts.URL)
	if err != nil {
		t.Fatalf("unable to parse http server url %s", err)
	}

	kp, err := NewKeyPair()
	if err != nil {
		t.Fatalf("unable to create key pair %s", err)
	}

	opt := &VMOpts{
		TLS:                  kp,
		OnBeginBuildletProbe: func(string) { OnBeginBuildletProbeCalled = true },
		OnEndBuildletProbe:   func(*http.Response, error) { OnEndBuildletProbeCalled = true },
	}

	ctx, cancel := context.WithCancel(context.Background())
	cancel()
	gotClient, gotErr := buildletClient(ctx, ts.URL, u.Host, opt)
	if gotErr == nil {
		t.Errorf("buildletClient(ctx, %s, %s, %v) error %s", ts.URL, u.Host, opt, gotErr)
	}
	if gotClient != nil {
		t.Errorf("client should be nil")
	}
	if httpCalled {
		t.Error("http endpoint called")
	}
	if OnBeginBuildletProbeCalled {
		t.Error("OnBeginBuildletProbe() was called")
	}
	if OnEndBuildletProbeCalled {
		t.Error("OnEndBuildletProbe() was called")
	}
}

func TestProbeBuildlet(t *testing.T) {
	var httpCalled, OnBeginBuildletProbeCalled, OnEndBuildletProbeCalled bool
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		httpCalled = true
		fmt.Fprintln(w, "buildlet endpoint reached")
	}))
	defer ts.Close()
	opt := &VMOpts{
		OnBeginBuildletProbe: func(string) { OnBeginBuildletProbeCalled = true },
		OnEndBuildletProbe:   func(*http.Response, error) { OnEndBuildletProbeCalled = true },
	}
	gotErr := probeBuildlet(context.Background(), ts.URL, opt)
	if gotErr != nil {
		t.Errorf("probeBuildlet(ctx, %q, %+v) = %s; want no error", ts.URL, opt, gotErr)
	}
	if !httpCalled {
		t.Error("http endpoint never called")
	}
	if !OnBeginBuildletProbeCalled {
		t.Error("OnBeginBuildletProbe() was not called")
	}
	if !OnEndBuildletProbeCalled {
		t.Error("OnEndBuildletProbe() was not called")
	}
}

func TestProbeBuildletError(t *testing.T) {
	var httpCalled bool
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		httpCalled = true
		http.Error(w, "all types of broken", http.StatusInternalServerError)
	}))
	defer ts.Close()
	opt := &VMOpts{}
	gotErr := probeBuildlet(context.Background(), ts.URL, opt)
	if gotErr == nil {
		t.Errorf("probeBuildlet(ctx, %q, %+v) = nil; want error", ts.URL, opt)
	}
	if !httpCalled {
		t.Error("http endpoint never called")
	}
}


text:
<?xml version="1.0" encoding="utf-8"?>
<!--
     Copyright (C) 2017 Angel Newton

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.xengar.android.movieguide">

    <!-- Include required permissions for Google Mobile Ads to run. -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!-- Include required permissions for Google Firebase to run. -->
    <uses-permission android:name="android.permission.WAKE_LOCK" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <!-- This meta-data tag is required to use Google Play Services. -->
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />

        <!-- https://firebase.google.com/docs/notifications/android/console-audience
             NOTE: There is a bug in the library displaying the icon, it doesn't show colors.
             Workaround: Use drawable image
             Set custom default icon. This is used when no icon is set for incoming notification messages.
             See README(https://goo.gl/l4GJaQ) for more. -->
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_icon"
            android:resource="@drawable/ic_stat_ic_notification" />
        <!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
             notification message. See README(https://goo.gl/6BKBk7) for more. -->
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_color"
            android:resource="@color/colorAccent" />

        <activity
            android:name=".ui.MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity
            android:name=".ui.MovieActivity"
            android:parentActivityName=".ui.MainActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".ui.MainActivity" />
        </activity>

        <activity
            android:name=".ui.PersonActivity"
            android:parentActivityName=".ui.MovieActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".ui.MovieActivity" />
        </activity>

        <activity
            android:name=".ui.SettingsActivity"
            android:label="@string/menu_option_settings"
            android:theme="@style/AppTheme.Settings"
            android:parentActivityName=".ui.MainActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".ui.MainActivity" />
        </activity>

        <activity
            android:name=".ui.TVShowActivity"
            android:label="@string/title_activity_tvshow"
            android:parentActivityName=".ui.MainActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".ui.MainActivity" />
        </activity>

        <activity
            android:name=".ui.SearchActivity"
            android:parentActivityName=".ui.MainActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".ui.MainActivity" />
        </activity>

        <provider
            android:name=".data.FavoritesProvider"
            android:authorities="com.xengar.android.movieguide"
            android:enabled="true"
            android:exported="true"
            android:protectionLevel="signature" />

    </application>

</manifest>


text:
import {Component} from '@angular/core';
import {MatChipInputEvent} from '@angular/material';
import {ENTER, COMMA} from '@angular/cdk/keycodes';

/**
 * @title Chips with input
 */
@Component({
  selector: 'chips-input-example',
  templateUrl: 'chips-input-example.html',
  styleUrls: ['chips-input-example.css']
})
export class ChipsInputExample {
  visible: boolean = true;
  selectable: boolean = true;
  removable: boolean = true;
  addOnBlur: boolean = true;

  // Enter, comma
  separatorKeysCodes = [ENTER, COMMA];

  fruits = [
    { name: 'Lemon' },
    { name: 'Lime' },
    { name: 'Apple' },
  ];

  add(event: MatChipInputEvent): void {
    let input = event.input;
    let value = event.value;

    // Add our fruit
    if ((value || '').trim()) {
      this.fruits.push({ name: value.trim() });
    }

    // Reset the input value
    if (input) {
      input.value = '';
    }
  }

  remove(fruit: any): void {
    let index = this.fruits.indexOf(fruit);

    if (index >= 0) {
      this.fruits.splice(index, 1);
    }
  }
}


text:
/**
 *  @since 4.0.0 This class has been split
 *
 * @typedef {Object} RegionsPluginParams
 * @property {?boolean} dragSelection Enable creating regions by dragging with
 * the mouse
 * @property {?RegionParams[]} regions Regions that should be added upon
 * initialisation
 * @property {number} slop=2 The sensitivity of the mouse dragging
 * @property {?number} snapToGridInterval Snap the regions to a grid of the specified multiples in seconds
 * @property {?number} snapToGridOffset Shift the snap-to-grid by the specified seconds. May also be negative.
 * @property {?boolean} deferInit Set to true to manually call
 * @property {number} maxRegions Maximum number of regions that may be created by the user at one time.
 * `initPlugin('regions')`
 * @property {function} formatTimeCallback Allows custom formating for region tooltip.
 * @property {?number} edgeScrollWidth='5% from container edges' Optional width for edgeScroll to start
 */

/**
 * @typedef {Object} RegionParams
 * @desc The parameters used to describe a region.
 * @example wavesurfer.addRegion(regionParams);
 * @property {string} id=→random The id of the region
 * @property {number} start=0 The start position of the region (in seconds).
 * @property {number} end=0 The end position of the region (in seconds).
 * @property {?boolean} loop Whether to loop the region when played back.
 * @property {boolean} drag=true Allow/disallow dragging the region.
 * @property {boolean} resize=true Allow/disallow resizing the region.
 * @property {string} [color='rgba(0, 0, 0, 0.1)'] HTML color code.
 * @property {?number} channelIdx Select channel to draw the region on (if there are multiple channel waveforms).
 * @property {?object} handleStyle A set of CSS properties used to style the left and right handle.
 * @property {?boolean} preventContextMenu=false Determines whether the context menu is prevented from being opened.
 * @property {boolean} showTooltip=true Enable/disable tooltip displaying start and end times when hovering over region.
 */

import {Region} from "./region.js";

/**
 * Regions are visual overlays on waveform that can be used to play and loop
 * portions of audio. Regions can be dragged and resized.
 *
 * Visual customization is possible via CSS (using the selectors
 * `.wavesurfer-region` and `.wavesurfer-handle`).
 *
 * @implements {PluginClass}
 * @extends {Observer}
 *
 * @example
 * // es6
 * import RegionsPlugin from 'wavesurfer.regions.js';
 *
 * // commonjs
 * var RegionsPlugin = require('wavesurfer.regions.js');
 *
 * // if you are using <script> tags
 * var RegionsPlugin = window.WaveSurfer.regions;
 *
 * // ... initialising wavesurfer with the plugin
 * var wavesurfer = WaveSurfer.create({
 *   // wavesurfer options ...
 *   plugins: [
 *     RegionsPlugin.create({
 *       // plugin options ...
 *     })
 *   ]
 * });
 */
export default class RegionsPlugin {
    /**
     * Regions plugin definition factory
     *
     * This function must be used to create a plugin definition which can be
     * used by wavesurfer to correctly instantiate the plugin.
     *
     * @param {RegionsPluginParams} params parameters use to initialise the plugin
     * @return {PluginDefinition} an object representing the plugin
     */
    static create(params) {
        return {
            name: 'regions',
            deferInit: params && params.deferInit ? params.deferInit : false,
            params: params,
            staticProps: {
                addRegion(options) {
                    if (!this.initialisedPluginList.regions) {
                        this.initPlugin('regions');
                    }
                    return this.regions.add(options);
                },

                clearRegions() {
                    this.regions && this.regions.clear();
                },

                enableDragSelection(options) {
                    if (!this.initialisedPluginList.regions) {
                        this.initPlugin('regions');
                    }
                    this.regions.enableDragSelection(options);
                },

                disableDragSelection() {
                    this.regions.disableDragSelection();
                }
            },
            instance: RegionsPlugin
        };
    }

    constructor(params, ws) {
        this.params = params;
        this.wavesurfer = ws;
        this.util = {
            ...ws.util,
            getRegionSnapToGridValue: value => {
                return this.getRegionSnapToGridValue(value, params);
            }
        };
        this.maxRegions = params.maxRegions;
        this.regionsMinLength = params.regionsMinLength || null;

        // turn the plugin instance into an observer
        const observerPrototypeKeys = Object.getOwnPropertyNames(
            this.util.Observer.prototype
        );
        observerPrototypeKeys.forEach(key => {
            Region.prototype[key] = this.util.Observer.prototype[key];
        });
        this.wavesurfer.Region = Region;

        // By default, scroll the container if the user drags a region
        // within 5% (based on its initial size) of its edge
        const scrollWidthProportion = 0.05;
        this._onBackendCreated = () => {
            this.wrapper = this.wavesurfer.drawer.wrapper;
            this.orientation = this.wavesurfer.drawer.orientation;
            this.defaultEdgeScrollWidth = this.wrapper.clientWidth * scrollWidthProportion;
            if (this.params.regions) {
                this.params.regions.forEach(region => {
                    this.add(region);
                });
            }
        };

        // Id-based hash of regions
        this.list = {};
        this._onReady = () => {
            this.wrapper = this.wavesurfer.drawer.wrapper;
            this.vertical = this.wavesurfer.drawer.params.vertical;
            if (this.params.dragSelection) {
                this.enableDragSelection(this.params);
            }
            Object.keys(this.list).forEach(id => {
                this.list[id].updateRender();
            });
        };
    }

    init() {
        // Check if ws is ready
        if (this.wavesurfer.isReady) {
            this._onBackendCreated();
            this._onReady();
        } else {
            this.wavesurfer.once('ready', this._onReady);
            this.wavesurfer.once('backend-created', this._onBackendCreated);
        }
    }

    destroy() {
        this.wavesurfer.un('ready', this._onReady);
        this.wavesurfer.un('backend-created', this._onBackendCreated);
        // Disabling `region-removed' because destroying the plugin calls
        // the Region.remove() method that is also used to remove regions based
        // on user input. This can cause confusion since teardown is not a
        // user event, but would emit `region-removed` as if it was.
        this.wavesurfer.setDisabledEventEmissions(['region-removed']);
        this.disableDragSelection();
        this.clear();
    }

    /**
     * check to see if adding a new region would exceed maxRegions
     * @return {boolean} whether we should proceed and create a region
     * @private
     */
    wouldExceedMaxRegions() {
        return (
            this.maxRegions && Object.keys(this.list).length >= this.maxRegions
        );
    }

    /**
     * Add a region
     *
     * @param {object} params Region parameters
     * @return {Region} The created region
     */
    add(params) {
        if (this.wouldExceedMaxRegions()) {
            return null;
        }

        params = {
            edgeScrollWidth: this.params.edgeScrollWidth || this.defaultEdgeScrollWidth,
            ...params
        };

        // Take formatTimeCallback from plugin params if not already set
        if (!params.formatTimeCallback && this.params.formatTimeCallback) {
            params = {...params, formatTimeCallback: this.params.formatTimeCallback};
        }

        if (!params.minLength && this.regionsMinLength) {
            params = {...params, minLength: this.regionsMinLength};
        }

        const region = new this.wavesurfer.Region(params, this.util, this.wavesurfer);

        this.list[region.id] = region;

        region.on('remove', () => {
            delete this.list[region.id];
        });

        return region;
    }

    /**
     * Remove all regions
     */
    clear() {
        Object.keys(this.list).forEach(id => {
            this.list[id].remove();
        });
    }

    enableDragSelection(params) {
        this.disableDragSelection();

        const slop = params.slop || 2;
        const container = this.wavesurfer.drawer.container;
        const scroll =
            params.scroll !== false && this.wavesurfer.params.scrollParent;
        const scrollSpeed = params.scrollSpeed || 1;
        const scrollThreshold = params.scrollThreshold || 10;
        let drag;
        let duration = this.wavesurfer.getDuration();
        let maxScroll;
        let start;
        let region;
        let touchId;
        let pxMove = 0;
        let scrollDirection;
        let wrapperRect;

        // Scroll when the user is dragging within the threshold
        const edgeScroll = e => {
            if (!region || !scrollDirection) {
                return;
            }

            // Update scroll position
            let scrollLeft =
                this.wrapper.scrollLeft + scrollSpeed * scrollDirection;
            this.wrapper.scrollLeft = scrollLeft = Math.min(
                maxScroll,
                Math.max(0, scrollLeft)
            );

            // Update range
            const end = this.wavesurfer.drawer.handleEvent(e);
            region.update({
                start: Math.min(end * duration, start * duration),
                end: Math.max(end * duration, start * duration)
            });

            // Check that there is more to scroll and repeat
            if (scrollLeft < maxScroll && scrollLeft > 0) {
                window.requestAnimationFrame(() => {
                    edgeScroll(e);
                });
            }
        };

        const eventDown = e => {
            if (e.touches && e.touches.length > 1) {
                return;
            }
            duration = this.wavesurfer.getDuration();
            touchId = e.targetTouches ? e.targetTouches[0].identifier : null;

            // Store for scroll calculations
            maxScroll = this.wrapper.scrollWidth -
                this.wrapper.clientWidth;
            wrapperRect = this.util.withOrientation(
                this.wrapper.getBoundingClientRect(),
                this.vertical
            );

            // set the region channel index based on the clicked area
            if (this.wavesurfer.params.splitChannels && this.wavesurfer.params.splitChannelsOptions.splitDragSelection) {
                const y = (e.touches ? e.touches[0].clientY : e.clientY) - wrapperRect.top;
                const channelCount = this.wavesurfer.backend.buffer != null ? this.wavesurfer.backend.buffer.numberOfChannels : 1;
                const channelHeight = this.wrapper.clientHeight / channelCount;
                const channelIdx = Math.floor(y / channelHeight);
                params.channelIdx = channelIdx;
                const channelColors = this.wavesurfer.params.splitChannelsOptions.channelColors[channelIdx];
                if (channelColors && channelColors.dragColor) {
                    params.color = channelColors.dragColor;
                }
            }

            drag = true;
            start = this.wavesurfer.drawer.handleEvent(e, true);
            region = null;
            scrollDirection = null;
        };
        this.wrapper.addEventListener('mousedown', eventDown);
        this.wrapper.addEventListener('touchstart', eventDown);
        this.on('disable-drag-selection', () => {
            this.wrapper.removeEventListener('touchstart', eventDown);
            this.wrapper.removeEventListener('mousedown', eventDown);
        });

        const eventUp = e => {
            if (e.touches && e.touches.length > 1) {
                return;
            }

            drag = false;
            pxMove = 0;
            scrollDirection = null;

            if (region) {
                this.util.preventClick();
                region.fireEvent('update-end', e);
                this.wavesurfer.fireEvent('region-update-end', region, e);
            }

            region = null;
        };
        this.wrapper.addEventListener('mouseleave', eventUp);
        this.wrapper.addEventListener('mouseup', eventUp);
        this.wrapper.addEventListener('touchend', eventUp);

        document.body.addEventListener('mouseup', eventUp);
        document.body.addEventListener('touchend', eventUp);
        this.on('disable-drag-selection', () => {
            document.body.removeEventListener('mouseup', eventUp);
            document.body.removeEventListener('touchend', eventUp);
            this.wrapper.removeEventListener('touchend', eventUp);
            this.wrapper.removeEventListener('mouseup', eventUp);
            this.wrapper.removeEventListener('mouseleave', eventUp);
        });

        const eventMove = event => {
            if (!drag) {
                return;
            }
            if (++pxMove <= slop) {
                return;
            }

            if (event.touches && event.touches.length > 1) {
                return;
            }
            if (event.targetTouches && event.targetTouches[0].identifier != touchId) {
                return;
            }

            // auto-create a region during mouse drag, unless region-count would exceed "maxRegions"
            if (!region) {
                region = this.add(params || {});
                if (!region) {
                    return;
                }
            }

            const end = this.wavesurfer.drawer.handleEvent(event);
            const startUpdate = this.wavesurfer.regions.util.getRegionSnapToGridValue(
                start * duration
            );
            const endUpdate = this.wavesurfer.regions.util.getRegionSnapToGridValue(
                end * duration
            );
            region.update({
                start: Math.min(endUpdate, startUpdate),
                end: Math.max(endUpdate, startUpdate)
            });

            let orientedEvent = this.util.withOrientation(event, this.vertical);

            // If scrolling is enabled
            if (scroll && container.clientWidth < this.wrapper.scrollWidth) {
                // Check threshold based on mouse
                const x = orientedEvent.clientX - wrapperRect.left;
                if (x <= scrollThreshold) {
                    scrollDirection = -1;
                } else if (x >= wrapperRect.right - scrollThreshold) {
                    scrollDirection = 1;
                } else {
                    scrollDirection = null;
                }
                scrollDirection && edgeScroll(event);
            }
        };
        this.wrapper.addEventListener('mousemove', eventMove);
        this.wrapper.addEventListener('touchmove', eventMove);
        this.on('disable-drag-selection', () => {
            this.wrapper.removeEventListener('touchmove', eventMove);
            this.wrapper.removeEventListener('mousemove', eventMove);
        });

        this.wavesurfer.on('region-created', region => {
            if (this.regionsMinLength) {
                region.minLength = this.regionsMinLength;
            }
        });
    }

    disableDragSelection() {
        this.fireEvent('disable-drag-selection');
    }

    /**
     * Get current region
     *
     * The smallest region that contains the current time. If several such
     * regions exist, take the first. Return `null` if none exist.
     *
     * @returns {Region} The current region
     */
    getCurrentRegion() {
        const time = this.wavesurfer.getCurrentTime();
        let min = null;
        Object.keys(this.list).forEach(id => {
            const cur = this.list[id];
            if (cur.start <= time && cur.end >= time) {
                if (!min || cur.end - cur.start < min.end - min.start) {
                    min = cur;
                }
            }
        });

        return min;
    }

    /**
     * Match the value to the grid, if required
     *
     * If the regions plugin params have a snapToGridInterval set, return the
     * value matching the nearest grid interval. If no snapToGridInterval is set,
     * the passed value will be returned without modification.
     *
     * @param {number} value the value to snap to the grid, if needed
     * @param {Object} params the regions plugin params
     * @returns {number} value
     */
    getRegionSnapToGridValue(value, params) {
        if (params.snapToGridInterval) {
            // the regions should snap to a grid
            const offset = params.snapToGridOffset || 0;
            return (
                Math.round((value - offset) / params.snapToGridInterval) *
                    params.snapToGridInterval +
                offset
            );
        }

        // no snap-to-grid
        return value;
    }
}


text:
REPORTER ?= dot
TM_BUNDLE = JavaScript\ mocha.tmbundle
SRC = $(shell find lib -name "*.js" -type f | sort)
SUPPORT = $(wildcard support/*.js)

all: mocha.js

lib/browser/diff.js: node_modules/diff/diff.js
	cp node_modules/diff/diff.js lib/browser/diff.js

mocha.js: $(SRC) $(SUPPORT) lib/browser/diff.js
	@node support/compile $(SRC)
	@cat \
	  support/head.js \
	  _mocha.js \
	  support/tail.js \
	  support/foot.js \
	  > mocha.js

clean:
	rm -f mocha.js
	rm -fr lib-cov
	rm -f coverage.html

test-cov: lib-cov
	@COV=1 $(MAKE) test REPORTER=html-cov > coverage.html

lib-cov:
	@rm -fr ./$@
	@jscoverage lib $@

test: test-unit

test-all: test-bdd test-tdd test-qunit test-exports test-unit test-grep test-jsapi test-compilers test-sort test-glob test-requires test-reporters test-only

test-jsapi:
	@node test/jsapi

test-unit:
	@./bin/mocha \
		--reporter $(REPORTER) \
		test/acceptance/*.js \
		--growl \
		test/*.js

test-compilers:
	@./bin/mocha \
		--reporter $(REPORTER) \
		--compilers coffee:coffee-script,foo:./test/compiler/foo \
		test/acceptance/test.coffee \
		test/acceptance/test.foo

test-requires:
	@./bin/mocha \
		--reporter $(REPORTER) \
		--compilers coffee:coffee-script \
		--require test/acceptance/require/a.js \
		--require test/acceptance/require/b.coffee \
		--require test/acceptance/require/c.js \
		--require test/acceptance/require/d.coffee \
		test/acceptance/require/require.js

test-bdd:
	@./bin/mocha \
		--reporter $(REPORTER) \
		--ui bdd \
		test/acceptance/interfaces/bdd

test-tdd:
	@./bin/mocha \
		--reporter $(REPORTER) \
		--ui tdd \
		test/acceptance/interfaces/tdd

test-qunit:
	@./bin/mocha \
		--reporter $(REPORTER) \
		--ui qunit \
		test/acceptance/interfaces/qunit

test-exports:
	@./bin/mocha \
		--reporter $(REPORTER) \
		--ui exports \
		test/acceptance/interfaces/exports

test-grep:
	@./bin/mocha \
	  --reporter $(REPORTER) \
	  --grep fast \
	  test/acceptance/misc/grep

test-invert:
	@./bin/mocha \
	  --reporter $(REPORTER) \
	  --grep slow \
	  --invert \
	  test/acceptance/misc/grep

test-bail:
	@./bin/mocha \
		--reporter $(REPORTER) \
		--bail \
		test/acceptance/misc/bail

test-async-only:
	@./bin/mocha \
	  --reporter $(REPORTER) \
	  --async-only \
	  test/acceptance/misc/asyncOnly

test-glob:
	@./test/acceptance/glob/glob.sh

test-reporters:
	@./bin/mocha \
		--reporter $(REPORTER) \
		test/reporters/*.js

test-only:
	@./bin/mocha \
		--reporter $(REPORTER) \
		--ui tdd \
		test/acceptance/misc/only/tdd

	@./bin/mocha \
		--reporter $(REPORTER) \
		--ui bdd \
		test/acceptance/misc/only/bdd

	@./bin/mocha \
		--reporter $(REPORTER) \
		--ui qunit \
		test/acceptance/misc/only/qunit

test-sort:
	@./bin/mocha \
		--reporter $(REPORTER) \
		--sort \
		test/acceptance/sort

non-tty:
	@./bin/mocha \
		--reporter dot \
		test/acceptance/interfaces/bdd 2>&1 > /tmp/dot.out

	@echo dot:
	@cat /tmp/dot.out

	@./bin/mocha \
		--reporter list \
		test/acceptance/interfaces/bdd 2>&1 > /tmp/list.out

	@echo list:
	@cat /tmp/list.out

	@./bin/mocha \
		--reporter spec \
		test/acceptance/interfaces/bdd 2>&1 > /tmp/spec.out

	@echo spec:
	@cat /tmp/spec.out

tm:
	@open editors/$(TM_BUNDLE)

.PHONY: test-cov test-jsapi test-compilers watch test test-all test-bdd test-tdd test-qunit test-exports test-unit non-tty test-grep tm clean


text:
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';

import { E2EImportsModule } from 'e2e-imports.module';

import { MotionCommentSectionListComponent } from './motion-comment-section-list.component';

describe('MotionCommentSectionListComponent', () => {
    let component: MotionCommentSectionListComponent;
    let fixture: ComponentFixture<MotionCommentSectionListComponent>;

    beforeEach(
        waitForAsync(() => {
            TestBed.configureTestingModule({
                imports: [E2EImportsModule],
                declarations: [MotionCommentSectionListComponent]
            }).compileComponents();
        })
    );

    beforeEach(() => {
        fixture = TestBed.createComponent(MotionCommentSectionListComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

    it('should create', () => {
        expect(component).toBeTruthy();
    });
});