[![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg)](https://github.com/RichardLitt/standard-readme)
[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)][Gitter]
[![Releases](https://img.shields.io/github/downloads/atom/atom/total.svg)][Releases]

> Ethereum miner with OpenCL, CUDA and stratum support

The ethminer is an Ethereum GPU mining worker. This is the actively maintained version of ethminer. It originates from [cpp-ethereum] project (where GPU mining has been discontinued) and builds on the improvements made in [Genoil's fork]. See [FAQ](#faq) for more details.

### Features

- OpenCL mining
- Nvidia CUDA mining
- realistic benchmarking against arbitrary epoch/DAG/blocknumber
- on-GPU DAG generation (no more DAG files on disk)
- stratum mining without proxy
- OpenCL devices picking
- farm failover (getwork + stratum)

## Table of Contents

- [Install](#install)
- [Usage](#usage)
- [Build](#build)
  - [Continuous Integration and development builds](#continuous-integration-and-development-builds)
  - [Building from source](#building-from-source)
  - [CMake configuration options](#cmake-configuration-options)
- [Maintainer](#maintainer)
- [Contribute](#contribute)
- [F.A.Q.](#faq)

## Install

[![Releases](https://img.shields.io/github/downloads/atom/atom/total.svg)][Releases]

Standalone **executables** for _Linux_, _macOS_ and _Windows_ are provided in
the [Releases] section.
Download an archive for your operating system and unpack the content to a place
accessible from command line. The ethminer is ready to go.

## Usage

The **ethminer** is a command line program. This means you launch it either
from a Windows command prompt or Linux console, or create shortcuts to
predefined command lines using a Linux Bash script or Windows batch/cmd file.
For a full list of available command, please run

```sh
ethminer --help
```

## Build

### Continuous Integration and development builds

| CI            | OS            | Status  | Development builds |
| ------------- | ------------- | -----   | -----------------  |
| [Travis CI]   | Linux, macOS  | [![Travis CI](https://img.shields.io/travis/ethereum-mining/ethminer.svg)][Travis CI]    | ✗ No build artifacts, [Amazon S3 is needed] for this |
| [AppVeyor]    | Windows       | [![AppVeyor](https://img.shields.io/appveyor/ci/ethereum-mining/ethminer.svg)][AppVeyor] | ✓ Build artifacts available for all PRs and branches |

The AppVeyor system automatically builds a Windows .exe for every commit. The latest version is always available [on the landing page](https://ci.appveyor.com/project/ethereum-mining/ethminer) or you can [browse the history](https://ci.appveyor.com/project/ethereum-mining/ethminer/history) to access previous builds.

To download the .exe on a build under 'JOB NAME' select 'Configuration: Release', choose 'ARTIFACTS' then download the zip file.

### Building from source

This project uses [CMake] and [Hunter] package manager.

1. Create a build directory.

   ```sh
   mkdir build; cd build
   ```

2. Configure the project with CMake. Check out additional
   [configuration options](#cmake-configuration-options).

   ```sh
   cmake ..
   ```

3. Build the project using [CMake Build Tool Mode]. This is a portable variant
   of `make`.

   ```sh
   cmake --build .
   ```

4. _(Optional, Linux only)_ Install the built executable.

   ```sh
   sudo make install
   ```

#### OpenCL support on Linux

If you're planning to use [OpenCL on Linux](https://github.com/ruslo/hunter/wiki/pkg.opencl#pitfalls)
you have to install OpenGL libraries. E.g. on Ubuntu run:

```sh
sudo apt-get install mesa-common-dev
```

#### Disable Hunter

If you want to install dependencies yourself or use system package manager
you can disable Hunter by adding
[-DHUNTER_ENABLED=OFF](https://docs.hunter.sh/en/latest/reference/user-variables.html#hunter-enabled)
to configuration options.

### CMake configuration options

Pass these options to CMake configuration command, e.g.

```sh
cmake .. -DETHASHCUDA=ON -DETHASHCL=OFF
```

- `-DETHASHCL=ON` - enable OpenCL mining, `ON` by default,
- `-DETHASHCUDA=ON` - enable CUDA mining, `OFF` by default,
- `-DETHSTRATUM=ON` - build with Stratum protocol support, `ON` by default.

## Maintainer

[![Gitter](https://img.shields.io/gitter/room/ethereum-mining/ethminer.svg)][Gitter]

- Paweł Bylica [@chfast](https://github.com/chfast)

## Contribute

[![Gitter](https://img.shields.io/gitter/room/ethereum-mining/ethminer.svg)][Gitter]

To meet the community, ask general questions and chat about ethminer join [the ethminer channel on Gitter][Gitter].

All bug reports, pull requests and code reviews are very much welcome.

## F.A.Q

1. Why is my hashrate with Nvidia cards on Windows 10 so low?

   The new WDDM 2.x driver on Windows 10 uses a different way of addressing the GPU. This is good for a lot of things, but not for ETH mining.
   For Kepler GPUs: I actually don't know. Please let me know what works best for good old Kepler.
   For Maxwell 1 GPUs: Unfortunately the issue is a bit more serious on the GTX750Ti, already causing suboptimal performance on Win7 and Linux. Apparently about 4MH/s can still be reached on Linux, which, depending on ETH price, could still be profitable, considering the relatively low power draw.
   For Maxwell 2 GPUs: There is a way of mining ETH at Win7/8/Linux speeds on Win10, by downgrading the GPU driver to a Win7 one (350.12 recommended) and using a build that was created using CUDA 6.5.
   For Pascal GPUs: You have to use the latest WDDM 2.1 compatible drivers in combination with Windows 10 Anniversary edition in order to get the full potential of your Pascal GPU.

2. Why is a GTX 1080 slower than a GTX 1070?

   Because of the GDDR5X memory, which can't be fully utilized for ETH mining (yet).

3. Are AMD cards also affected by slowdowns with increasing DAG size?

   Only GCN 1.0 GPUs (78x0, 79x0, 270, 280), but in a different way. You'll see that on each new epoch (30K blocks), the hashrate will go down a little bit.

4. Can I still mine ETH with my 2GB GPU?

   No.

5. What are the optimal launch parameters?

   The default parameters are fine in most scenario's (CUDA). For OpenCL it varies a bit more. Just play around with the numbers and use powers of 2. GPU's like powers of 2.

6. What does the ```--cuda-parallel-hash``` flag do?

   @davilizh made improvements to the CUDA kernel hashing process and added this flag to allow changing the number of tasks it runs in parallel. These improvements were optimised for GTX 1060 GPUs which saw a large increase in hashrate, GTX 1070 and GTX 1080/Ti GPUs saw some, but less, improvement. The default value is 4 (which does not need to be set with the flag) and in most cases this will provide the best performance.

7. What is ethminer's relationship with [Genoil's fork]?

   [Genoil's fork] was the original source of this version, but as Genoil is no longer consistently maintaining that fork it became almost impossible for developers to get new code merged there. In the interests of progressing development without waiting for reviews this fork should be considered the active one and Genoil's as legacy code.

[Amazon S3 is needed]: https://docs.travis-ci.com/user/uploading-artifacts/
[AppVeyor]: https://ci.appveyor.com/project/ethereum-mining/ethminer
[CMake]: https://cmake.org
[CMake Build Tool Mode]: https://cmake.org/cmake/help/latest/manual/cmake.1.html#build-tool-mode
[cpp-ethereum]: https://github.com/ethereum/cpp-ethereum
[Genoil's fork]: https://github.com/Genoil/cpp-ethereum
[Gitter]: https://gitter.im/ethereum-mining/ethminer
[Hunter]: https://docs.hunter.sh
[Releases]: https://github.com/ethereum-mining/ethminer/releases
[Travis CI]: https://travis-ci.org/ethereum-mining/ethminer


from accessData import getHDFData
from voronoi import voronoi
import inSituCluster as clusterLib
import matplotlib.pyplot as plt
from IPython import embed
import numpy as np
#import cv2
import os
import scipy.spatial as kd

kdt = None
arr = None
gradx = None
grady = None
grad = None
imgCntr = 0
yPts = None
xPts = None

def createHist(inputData, lowerBound=None, upperBound=None, ignore=None):
    """ Create Histogram with matplotlib
        Parameters:
            data - The input data to be processed
            lowerBound - The smallest value to consider for the histogram
            upperBound - the largest value to consider for the histogram
            ignore - A list of values to ignore from the histogram
    """

    data = inputData.copy()
    if ignore is not None:
        for val in ignore:  # Consecutively remove the values to be ignored
            data = data[np.where(data != val)]
    if lowerBound is None:
        lowerBound = data.min()
    if upperBound is None:
        upperBound = data.max()
    sampleData = data[np.where(data < upperBound)]
    sampleData = sampleData[np.where(sampleData >= lowerBound)]
    sampleSize = sampleData.size
# Scott's (1979) bin width. Based on the standard deviation
# and the data size
    n = np.power(sampleSize, 1.0 / 3)
    std = np.std(sampleData)
    bin_width = (3.49 * std) / n
    histSize = int((upperBound - lowerBound) / bin_width)
    ranges = (lowerBound, upperBound)
    hist = plt.hist(sampleData, histSize, ranges)
    plt.axes().set_aspect('equal')
    plt.show()

    return hist

def quantize(data, cutoff, numRegions=8, tolerance=0.0001):

    newData = data[::4, ::4]  # Downsample data to speed up by a factor of 16
    # Next remove clouds poorly represented data
    cleanData = newData[np.logical_and(newData > 0, newData < cutoff)]

    tess = voronoi(cleanData, numRegions, tolerance, data)

    thresh = []
    for val in tess.values():
        thresh.append(np.min(val))
    thresh = np.sort(thresh)

    (rows, cols) = data.shape
    qData = np.ndarray((rows, cols), dtype='uint8')
    qData.fill(255)

    for val, t in enumerate(thresh):
        qData[data > t] = val + 1

    qData[data == 0] = 0  # Put back the land values
    qData[data == -1] = 255  # Put back the cloud values

    return qData

def colorMap(data):

    colors = [(123, 0, 255), (0, 0, 255), (0, 255, 255), (0, 255, 0),
              (123, 255, 0), (255, 255, 0), (255, 123, 0), (255, 0, 0)]

    (rows, cols) = data.shape
    color = np.ndarray((rows, cols, 3), dtype='uint8')
    color.fill(255)

    # Fill land with black
    color[data == 0] = (0, 0, 0)

    for i, c in enumerate(colors):
        color[data == i + 1] = c
    #plt.imshow(color)
    #plt.show()

    return color

def writeClouds(data):

    # Only clouds should be left as -1
    locs = np.where(data == -1)
    numPts = locs[0].size
    with open("data/clouds.dat", 'w') as fd:
        for i in xrange(numPts):
            if i % 100000 == 0:
                print i
            x = locs[0][i]
            y = locs[1][i]
            fd.write("%d %d\n" % (x, y))

def findSurroundingVal(qData, cluster, clusterVal=255):
    """ Summary:
            Check and see if the cluster is surrounded by a solid value, if it
            is, return the value which surrounds it. This one checks for border
            conditions
        Parameters:
            qData: The quantized satellite data.
            cluster: A 2D array of shape (2,n) where n is the number of points
                composing the cluster. The two rows are parallel arrays of x
                then y coordinates respectively.
        Returns:
            theValue: The surrounding value found.
    """

    theValue = None

    lk = set([(0, 1), (1, 1), (1, 0), (-1, 0), (-1, 1)])  # Left Kernel
    rk = set([(1, -1), (1, 0), (-1, 0), (-1, -1), (0, -1)])  # Right Kernel
    tk = set([(1, -1), (0, 1), (1, 1), (0, -1), (1, 0)])  # Top Kernel
    bk = set([(-1, -1), (0, 1), (-1, 1), (0, -1), (-1, 0)])  # Bottom Kernel
    mk = np.array(tuple(lk.union(rk)))  # Middle Kernel
    tlk = np.array(tuple(tk.intersection(lk)))  # Top Left Kernel
    trk = np.array(tuple(tk.intersection(rk)))  # Top Right Kernel
    blk = np.array(tuple(bk.intersection(lk)))  # Bottom Left Kernel
    brk = np.array(tuple(bk.intersection(rk)))  # Bottom Right Kernel
    lk = np.array(tuple(lk))
    rk = np.array(tuple(rk))
    tk = np.array(tuple(tk))
    bk = np.array(tuple(bk))

    rows, cols = qData.shape
    neighbors = {}

    for pt in cluster.T:
        row, col = pt
        k = None
        kused = None
        if row > 0:
            if col > 0:
                if row < rows - 1:
                    if col < cols - 1:
                        k = (mk + pt).T
                        kused = "middle"
                    else:
                        k = (rk + pt).T
                        kused = "right"
                elif col < cols - 1:
                    k = (bk + pt).T
                    kused = "bottom"
                else:
                    k = (brk + pt).T
                    kused = "bottom right"
            elif row < rows - 1:
                k = (lk + pt).T
                kused = "left"
            else:
                k = (blk + pt).T
                kused = "bottom left"
        elif col > 0:
            if col < cols - 1:
                k = (tk + pt).T
                kused = "top"
            else:
                k = (trk + pt).T
                kused = "top right"
        else:
            k = (tlk + pt).T
            kused = "top left"

        try:
            values = qData[tuple(k)]
        except:
            print "row %d out of %d" % (row, rows)
            print "col %d out of %d" % (col, cols)
            print "pt = ", pt
            print "k used = ", kused
            print "resulting k = ", k
            qData.fill(0)
            qData[tuple(pt)] = 255
            plt.imshow(qData)
            plt.axes().set_aspect('equal')
            plt.show()

        if clusterVal == 255:
            for value in values:
                if value == clusterVal or value == 0 or value == 255:
                    continue

                if theValue is None:
                    theValue = value
                elif value != theValue:
                    return None
        else:
            for value in values:
                if value == clusterVal or value == 0:
                    continue

                if value in neighbors.keys():
                    neighbors[value] += 1
                else:
                    neighbors[value] = 1

            maximum = 0
            for k, v in neighbors.iteritems():
                if v > maximum:
                    theValue = k

    if theValue is None:
        return clusterVal
    else:
        return theValue

def filter(img):
    """
    Summary: A filter to remove all points with less than 3 neighbors.
    Parameters:
        img - The image to be filtered
    Returns:
        output - The filtered dataset. Same dimensions as img
    """

    # Add the border mask
    cpy = np.ndarray((img.shape[0] + 2, img.shape[1] + 2))
    cpy[:, 0] = 0
    cpy[0, :] = 0
    cpy[:, -1] = 0
    cpy[-1, :] = 0
    cpy[1:-1, 1:-1] = img.copy()
    h, w = cpy.shape
    for y in xrange(1, h - 2):
        for x in xrange(1, w - 2):
            val = img[y, x]
            # Extract a 3x3 sub matrix
            submat = cpy[y - 1:y + 2, x - 1:x + 2]
            #print "submat \n", submat
            #print "kernel \n", kernel
            numOccurence = submat[submat == val].size

            if numOccurence < 3:
                cpy[y, x] = 0.0  # So remove it!

    output = np.where(cpy == 1)

    return output

def findMaximama(array):
    """ Find the maxima of a 1D array """

    binSizes = array[0]
    binVals = array[1][:-1]
    c = (np.diff(np.sign(np.diff(binSizes))) < 0).nonzero()[0] + 1  # local max

    # Set to True to plot the maxima
    if False:
        plt.plot(binVals, binSizes)
        plt.plot(binVals[c], binSizes[c], "o", label="max")
        plt.legend()
        plt.axes().set_aspect('equal')
        plt.show()

    return binVals[c]

def extractStepEdges(img):
    """
    Summary: A filter to find all step edges in the dataset:
        img - The image to be filtered
    Returns:
        output - The filtered dataset. Same dimensions as img
    """

    subImg = img[1:-1, 1:-1]
    pts = np.array(np.where(subImg == 1))

    yVals = []
    xVals = []
    for y, x in pts.T:
        y += 1  # Pts were found with borders extracted
        x += 1  # Pts were found with borders extracted
        val = img[y,x]
        # Extract a 3x3 sub matrix
        submat = img[y - 1:y + 2, x - 1:x + 2]
        targetPts = np.logical_and(submat != val, submat != 255)
        numOccurence = submat[targetPts].size

        if numOccurence > 0:
            yVals.append(y)
            xVals.append(x)

    edgePts = np.array((yVals, xVals))

    #img[(yVals, xVals)] = 8
    #plt.imshow(colorMap(img))
    #plt.show()

    return edgePts

def buildKDTree(data):
    global kdt, arr

    arr = np.asarray(zip(data[0], data[1]))
    kdt = kd.cKDTree(arr)

def getGrads(img, kernelSize):
    global gradx, grady, grad

    print "Computing xderiv"
    gradx = xDeriv(img, kernelSize)
    print "Computing yderiv"
    grady = yDeriv(img, kernelSize)

def getSobelKernel(size, direction):
    if size % 2 == 0:
        print "\nKernel size must be odd!\n"
        exit()

    magic = size / 2
    kernel = list()
    for i in xrange(-magic, magic + 1):
        row = list()
        if i < 0:
            pivot = i - magic
            for j in xrange(-magic, magic + 1):
                e = pivot + np.abs(j)
                row.append(e)
            kernel.append(row)
        elif i == 0:
            row = [0] * size
            kernel.append(row)
        else:
            pivot = i + magic
            for j in xrange(-magic, magic + 1):
                e = pivot - np.abs(j)
                row.append(e)
            kernel.append(row)

    if direction == 'y':
        return np.asarray(kernel)
    elif direction == 'x':
        return np.asarray(kernel).T

def xDeriv(img, kernelSize):

    s = kernelSize
    if s % 2 == 0:
        sys.exit("Kernel size must be odd!\n")
    kx = getSobelKernel(s, 'x')

    h, w = img.shape
    xgrad = np.zeros(img.shape)
    sigma = s / 2
    #blurImg = cv2.GaussianBlur(img, (s, s), sigma)
    for j in xrange(s / 2, h - s / 2):
        for i in xrange(s / 2, w - s / 2):
            submat = blurImg[j - s / 2: j + s / 2 + 1, i - s / 2: i + s / 2 + 1]
            val = (kx * submat).sum()
            xgrad[j, i] = val

    return xgrad

def yDeriv(img, kernelSize):

    s = kernelSize
    if s % 2 == 0:
        sys.exit("Kernel size must be odd!\n")
    ky = getSobelKernel(s, 'y')

    h, w = img.shape
    ygrad = np.zeros(img.shape)
    sigma = s / 2
    #blurImg = cv2.GaussianBlur(img, (s, s), sigma)
    for j in xrange(s / 2, h - s / 2):
        for i in xrange(s / 2, w - s / 2):
            submat = blurImg[j - s / 2: j + s / 2 + 1, i - s / 2: i + s / 2 + 1]
            val = (ky * submat).sum()
            ygrad[j, i] = val

    return ygrad

def preprocess(data, cutoff):

    global kdt

    numRegions = 8
    clustDist = 1

    print "Quantizing the Data...\n"
    qData = quantize(data, cutoff, numRegions)

    #plt.figure(0)
    #plt.title("After Quantization")
    #plt.imshow(colorMap(qData))

    # Cluster the Clouds using efficient KDT
    print "Clustering Clouds...\n"
    cloudsB4 = np.array(np.where(qData == 255))
    C = clusterLib.Cluster()
    cloudClusters = C.clusterGrid(cloudsB4, clustDist)

    # Remove the clouds once and prepare for filtering
    print "Removing clouds...\n"
    cloudsB4 = np.array(np.where(qData == 255))
    for cluster in cloudClusters:
        c = type(cluster)
        if c is int:
            c = [cluster]
        else:
            c = list(cluster)

        cloud = cloudsB4[:, c]
        val = findSurroundingVal(qData, cloud)
        if val is not None:
            qData[tuple(cloud)] = val

    #plt.figure(1)
    #plt.title("After Removing Clouds")
    #plt.imshow(colorMap(qData))

    # Filter the data
    print "Filtering out Small Clusters...\n"
    for region in xrange(numRegions):
        clusterVal = numRegions - region
        if not clusterVal in qData:
            continue
        dataPts = np.array(np.where(qData == clusterVal))
        print "\tFiltering %d Data Points in Region %d..." % \
            (dataPts[0].size, clusterVal)
        C = clusterLib.Cluster()
        regionClusters = C.clusterGrid(dataPts, clustDist)
        for cluster in regionClusters:
            if type(cluster) is int or len(cluster) > 250:
                continue
            r = dataPts[:, tuple(cluster)]
            val = findSurroundingVal(qData, r, clusterVal)
            qData[tuple(r)] = val

    #plt.figure(2)
    #plt.title("After Filtering Data")
    #plt.imshow(colorMap(qData))

    # Remove the clouds again
    print "Removing Clouds Again..."
    cloudsB4 = np.array(np.where(qData == 255))
    C = clusterLib.Cluster()
    cloudClusters = C.clusterGrid(cloudsB4, clustDist)

    for cluster in cloudClusters:
        c = type(cluster)
        if c is int:
            c = [cluster]
        else:
            c = list(cluster)
        try:
            cloud = cloudsB4[:, c]
        except:
            embed()
        val = findSurroundingVal(qData, cloud)
        if val is not None:
            qData[tuple(cloud)] = val

    #plt.figure(3)
    #plt.title("After Removing Clouds After Filtering Data")
    #plt.imshow(colorMap(qData))
    #plt.axes().set_aspect('equal')
    #plt.show()

    #print "Getting Gradient Values...\n"
    #if gradx is None or grady is None:
        #getGrads(qData, ptsBtwnKnts)

    print "Extracting Edges...\n"
    edgePts = extractStepEdges(qData)

    #colorData = colorMap(qData)
    #plt.imshow(colorData)
    #plt.axes().set_aspect('equal')
    #plt.show()

    return edgePts


"""Expectation value for a diagonal observable using a sampler primitive."""

from __future__ import annotations

from collections.abc import Callable, Sequence, Mapping
from typing import Any

from dataclasses import dataclass

import numpy as np
from qiskit.algorithms.algorithm_job import AlgorithmJob
from qiskit.circuit import QuantumCircuit
from qiskit.primitives import BaseSampler, BaseEstimator, EstimatorResult
from qiskit.primitives.utils import init_observable, _circuit_key
from qiskit.opflow import PauliSumOp
from qiskit.quantum_info import SparsePauliOp
from qiskit.quantum_info.operators.base_operator import BaseOperator

@dataclass(frozen=True)
class _DiagonalEstimatorResult(EstimatorResult):
    """A result from an expectation of a diagonal observable."""

    # TODO make each measurement a dataclass rather than a dict
    best_measurements: Sequence[Mapping[str, Any]] | None = None

class _DiagonalEstimator(BaseEstimator):
    """An estimator for diagonal observables."""

    def __init__(
        self,
        sampler: BaseSampler,
        aggregation: float | Callable[[Sequence[tuple[float, float]]], float] | None = None,
        callback: Callable[[Sequence[Mapping[str, Any]]], None] | None = None,
        **options,
    ) -> None:
        r"""Evaluate the expectation of quantum state with respect to a diagonal operator.

        Args:
            sampler: The sampler used to evaluate the circuits.
            aggregation: The aggregation function to aggregate the measurement outcomes. If a float
                this specified the CVaR :math:`\alpha` parameter.
            callback: A callback which is given the best measurements of all circuits in each
                evaluation.
            run_options: Options for the sampler.

        """
        super().__init__(options=options)
        self.sampler = sampler
        if not callable(aggregation):
            aggregation = _get_cvar_aggregation(aggregation)

        self.aggregation = aggregation
        self.callback = callback

    def _run(
        self,
        circuits: Sequence[QuantumCircuit],
        observables: Sequence[BaseOperator | PauliSumOp],
        parameter_values: Sequence[Sequence[float]],
        **run_options,
    ) -> AlgorithmJob:
        circuit_indices = []
        for circuit in circuits:
            key = _circuit_key(circuit)
            index = self._circuit_ids.get(key)
            if index is not None:
                circuit_indices.append(index)
            else:
                circuit_indices.append(len(self._circuits))
                self._circuit_ids[key] = len(self._circuits)
                self._circuits.append(circuit)
                self._parameters.append(circuit.parameters)
        observable_indices = []
        for observable in observables:
            index = self._observable_ids.get(id(observable))
            if index is not None:
                observable_indices.append(index)
            else:
                observable_indices.append(len(self._observables))
                self._observable_ids[id(observable)] = len(self._observables)
                converted_observable = init_observable(observable)
                _check_observable_is_diagonal(converted_observable)  # check it's diagonal
                self._observables.append(converted_observable)
        job = AlgorithmJob(
            self._call, circuit_indices, observable_indices, parameter_values, **run_options
        )
        job.submit()
        return job

    def _call(
        self,
        circuits: Sequence[int],
        observables: Sequence[int],
        parameter_values: Sequence[Sequence[float]],
        **run_options,
    ) -> _DiagonalEstimatorResult:
        job = self.sampler.run(
            [self._circuits[i] for i in circuits],
            parameter_values,
            **run_options,
        )
        sampler_result = job.result()
        samples = sampler_result.quasi_dists

        # a list of dictionaries containing: {state: (measurement probability, value)}
        evaluations = [
            {
                state: (probability, _evaluate_sparsepauli(state, self._observables[i]))
                for state, probability in sampled.items()
            }
            for i, sampled in zip(observables, samples)
        ]

        results = np.array([self.aggregation(evaluated.values()) for evaluated in evaluations])

        # get the best measurements
        best_measurements = []
        num_qubits = self._circuits[0].num_qubits
        for evaluated in evaluations:
            best_result = min(evaluated.items(), key=lambda x: x[1][1])
            best_measurements.append(
                {
                    "state": best_result[0],
                    "bitstring": bin(best_result[0])[2:].zfill(num_qubits),
                    "value": best_result[1][1],
                    "probability": best_result[1][0],
                }
            )

        if self.callback is not None:
            self.callback(best_measurements)

        return _DiagonalEstimatorResult(
            values=results, metadata=sampler_result.metadata, best_measurements=best_measurements
        )

def _get_cvar_aggregation(alpha):
    """Get the aggregation function for CVaR with confidence level ``alpha``."""
    if alpha is None:
        alpha = 1
    elif not 0 <= alpha <= 1:
        raise ValueError(f"alpha must be in [0, 1] but was {alpha}")

    # if alpha is close to 1 we can avoid the sorting
    if np.isclose(alpha, 1):

        def aggregate(measurements):
            return sum(probability * value for probability, value in measurements)

    else:

        def aggregate(measurements):
            # sort by values
            sorted_measurements = sorted(measurements, key=lambda x: x[1])

            accumulated_percent = 0  # once alpha is reached, stop
            cvar = 0
            for probability, value in sorted_measurements:
                cvar += value * max(probability, alpha - accumulated_percent)
                accumulated_percent += probability
                if accumulated_percent >= alpha:
                    break

            return cvar / alpha

    return aggregate

def _evaluate_sparsepauli(state: int, observable: SparsePauliOp) -> complex:
    return sum(
        coeff * _evaluate_bitstring(state, paulistring)
        for paulistring, coeff in observable.label_iter()
    )

def _evaluate_bitstring(state: int, paulistring: str) -> float:
    """Evaluate a bitstring on a Pauli label."""
    n = len(paulistring) - 1
    return np.prod(
        [-1 if state & (1 << (n - i)) else 1 for i, pauli in enumerate(paulistring) if pauli == "Z"]
    )

def _check_observable_is_diagonal(observable: SparsePauliOp) -> bool:
    is_diagonal = not np.any(observable.paulis.x)
    if not is_diagonal:
        raise ValueError("The observable must be diagonal.")


/*jslint es5:true, indent:2, maxlen:80, node:true*/
/*global suite:true, test:true, suiteSetup:true, suiteTeardown:true, setup:true,
 teardown:true*/ // Mocha
'use strict';

// this module

// http://stackoverflow.com/questions/1606797
function construct(constructor, args) {
  function F() {
    return constructor.apply(this, args);
  }
  F.prototype = constructor.prototype;
  return new F();
}

// exports

module.exports = function (SubArray, suite, test, assert) {
      [
        [],
        ['a', 'b', 'c']
      ].forEach(function (args) {
          suite('constructed with: ' + JSON.stringify(args), function () {
            var subArray;

            test('constructed without incident', function () {
              subArray = construct(SubArray, args);
              assert(true, 'made it without throwing errors');
            });

            test('detectable as an Array', function () {
              assert.equal(Object.prototype.toString.call(subArray),
                '[object Array]');
            });

            test('inherits from global Array', function () {
              assert(subArray instanceof Array, 'instanceof Array');
            });

            test('initial length is correct', function () {
              assert.equal(subArray.length, args.length);
            });

            test('"last" method returns last of initial args', function () {
              var last = args.length ? args[args.length - 1] : undefined;
              assert(subArray.last, '"last" method exists');
              assert.equal(subArray.last(), last);
            });

            test('"push" adds a new last element', function () {
              subArray.push('last');
              assert(subArray.last, '"last" method exists');
              assert.equal(subArray.last(), 'last');
            });

            test('length is incremented post-"push"', function () {
              assert.equal(subArray.length, args.length + 1);
            });

            test('"pop" returns last element', function () {
              assert.equal(subArray.pop(), 'last');
            });

            test('"last" method returns last of initial args', function () {
              var last = args.length ? args[args.length - 1] : undefined;
              assert(subArray.last, '"last" method exists');
              assert.equal(subArray.last(), last);
            });

            test('length is decremented post-"pop"', function () {
              assert.equal(subArray.length, args.length);
            });

            test('setting length higher changes highest index', function () {
              subArray.length = 10;
              assert.equal(subArray.length, 10);
              subArray.push('last');
              assert.equal(subArray.length, 11);
              assert.equal(subArray[10], 'last');
            });

            test('setting length lower changes highest index', function () {
              subArray.length = 0;
              assert.equal(subArray.length, 0);
              subArray.push('last');
              assert.equal(subArray.length, 1);
              assert.equal(subArray[0], 'last');
            });

            test('add an element by direct index', function () {
              subArray[0] = 'abc';
              assert.equal(subArray.length, 1, 'length is updated');
              assert.equal(subArray[0], 'abc', 'element was stored/retrieved');
              assert.equal(subArray.last(), 'abc', '"last" finds element');
            });

            test('add an element by higher direct index', function () {
              subArray[2] = 'abc';
              assert.equal(subArray.length, 3, 'length is updated');
              assert(!subArray[1], 'skipped index is falsey');
              assert.equal(subArray[2], 'abc', 'element was stored/retrieved');
              assert.equal(subArray.last(), 'abc', '"last" finds element');
            });
          });
        });
    }


/**
 * Keyboard class handles the keyboard state for the InputHandler
 */
class Keyboard {
  /**
   * Constructor for the Keyboard class
   */
  constructor() {
    // Store state
    this.keys = {};

    // Setup listeners for key events
    document.addEventListener('keydown', (e) => this._onKeyDown(e), false);
    document.addEventListener('keyup', (e) => this._onKeyUp(e), false);
  }

  /**
   * Callback listener for keydown event
   */
  _onKeyDown(e) {
    this.keys[e.key.toLowerCase()] = true;
    e.preventDefault();
    e.stopPropagation();
  }

  /**
   * Callback listener for keyup event
   */
  _onKeyUp(e) {
    this.keys[e.key.toLowerCase()] = false;
  }

  /**
   * Check if a key is down,
   * @param {string} key The key to check
   */
  keyIsPressed(key) {
    if (this.keys[key.toLowerCase()]) {
      return true;
    } else {
      return false;
    }
  }
}

export { Keyboard as default };


--TEST--
phpunit-skelgen --class -- BankAccountTest _fixture/BankAccountTest.php BankAccount php://stdout
--FILE--
<?php
$_SERVER['argv'][1] = '--class';
$_SERVER['argv'][2] = '--';
$_SERVER['argv'][3] = 'BankAccountTest';
$_SERVER['argv'][4] = __DIR__ . DIRECTORY_SEPARATOR . '_fixture' . DIRECTORY_SEPARATOR . 'BankAccountTest.php';
$_SERVER['argv'][5] = 'BankAccount';
$_SERVER['argv'][6] = 'php://stdout';

require __DIR__ . '/../src/autoload.php';
$textui = new SebastianBergmann\PHPUnit\SkeletonGenerator\Command;
$textui->main();
?>
--EXPECTF--
PHPUnit Skeleton Generator %s by Sebastian Bergmann.

<?php
/**
 * Generated by PHPUnit_SkeletonGenerator %s on %s at %s.
 */
class BankAccount
{
    /**
     * @todo Implement depositMoney().
     */
    public function depositMoney()
    {
        // Remove the following line when you implement this method.
        throw new RuntimeException('Not yet implemented.');
    }

    /**
     * @todo Implement getBalance().
     */
    public function getBalance()
    {
        // Remove the following line when you implement this method.
        throw new RuntimeException('Not yet implemented.');
    }

    /**
     * @todo Implement withdrawMoney().
     */
    public function withdrawMoney()
    {
        // Remove the following line when you implement this method.
        throw new RuntimeException('Not yet implemented.');
    }
}
Wrote skeleton for "BankAccount" to "php://stdout".


'use strict';

import Promise from 'bluebird';
import Joi from 'joi';

export default [
  {
    path: '/v1/teams',
    method: 'GET',
    config: {
      handler: {
        async: Promise.coroutine(function* (request, reply) {
          let result = yield Promise.resolve([]);
          reply(result);
        })
      }
    }
  },
  {
    path: '/v1/teams',
    method: 'POST',
    config: {
      validate: {
        payload: Joi.object({
          name: Joi.string().required().min(2).description('Team Name'),
          description: Joi.string().description('Team description'),
          members: Joi.array().unique().min(1).items(Joi.string().required()).description('Team Members'),
          isPublic: Joi.boolean().default(false).description('Is Public'),
          isActive: Joi.boolean().default(true).description('Is Active')
        })
      },
      handler: {
        async: Promise.coroutine(function* (request, reply) {
          let result = yield Promise.resolve({});
          reply(result);
        })
      }
    }
  },
  {
    path: '/v1/teams/:id',
    method: 'GET',
    config: {
      validate: {
        params: {
          id: Joi.string()
        }
      },
      handler: {
        async: Promise.coroutine(function* (request, reply) {
          let result = yield Promise.resolve({});
          reply(result);
        })
      }
    }
  },
  {
    path: '/v1/teams/:id',
    method: 'PUT',
    config: {
      validate: {
        params: {
          id: Joi.string()
        },
        payload: Joi.object({
          name: Joi.string().required().min(2).description('Team Name'),
          description: Joi.string().description('Team description'),
          isPublic: Joi.boolean().default(false).description('Is Public'),
          isActive: Joi.boolean().default(true).description('Is Active')
        })
      },
      handler: {
        async: Promise.coroutine(function* (request, reply) {
          let result = yield Promise.resolve({});
          reply(result);
        })
      }
    }
  },
  {
    path: '/v1/teams/:id',
    method: 'DELETE',
    config: {
      validate: {
        params: {
          id: Joi.string()
        }
      },
      handler: {
        async: Promise.coroutine(function* (request, reply) {
          let result = yield Promise.resolve({});
          reply(result);
        })
      }
    }
  },
  {
    path: '/v1/teams/:id/users/:userId',
    method: 'POST',
    config: {
      validate: {
        params: {
          id: Joi.string(),
          userId: Joi.string()
        },
        payload: Joi.array().items(Joi.string())
      },
      handler: {
        async: Promise.coroutine(function* (request, reply) {
          let result = yield Promise.resolve({});
          reply(result);
        })
      }
    }
  },
  {
    path: '/v1/teams/:id/users/:userId',
    method: 'DELETE',
    config: {
      validate: {
        params: {
          id: Joi.string(),
          userId: Joi.string()
        }
      },
      handler: {
        async: Promise.coroutine(function* (request, reply) {
          let result = yield Promise.resolve({});
          reply(result);
        })
      }
    }
  }
]


            Load Devices

            Devices:
                <select ng-model="myDev" ng-options="dev.name for dev in devices"></select>

            Load Ports

        First Port:
            <select ng-model="myPort1" ng-options="port.name for port in ports"></select>

        Second Port:
            <select ng-model="myPort2" ng-options="port.name for port in ports"></select>

            Patch!

            {{data.message}}

            ConnectPoints in use

            {{data.cpoints}}


export const REQUESTS_BEGIN = 'REQUESTS_BEGIN';
export const REQUESTS_END = 'REQUESTS_END';
export const REQUESTS_ERROR = 'REQUESTS_ERROR';

// UI
export const UPDATE_EQUIPMENT_LIST_UI = 'UPDATE_EQUIPMENT_LIST_UI';
export const UPDATE_PHYSICAL_ATTACHMENTS_UI = 'UPDATE_PHYSICAL_ATTACHMENTS_UI';
export const UPDATE_OWNERS_UI = 'UPDATE_OWNERS_UI';
export const UPDATE_OWNER_CONTACTS_UI = 'UPDATE_OWNER_CONTACTS_UI';
export const UPDATE_OWNER_EQUIPMENT_UI = 'UPDATE_OWNER_EQUIPMENT_UI';
export const UPDATE_USERS_UI = 'UPDATE_USERS_UI';
export const UPDATE_PROJECTS_UI = 'UPDATE_PROJECTS_UI';
export const UPDATE_PROJECT_CONTACTS_UI = 'UPDATE_PROJECT_CONTACTS_UI';
export const UPDATE_RENTAL_REQUESTS_UI = 'UPDATE_RENTAL_REQUESTS_UI';
export const UPDATE_USER_ROLES_UI = 'UPDATE_USER_ROLES_UI';
export const UPDATE_GROUPS_LOOKUP = 'UPDATE_GROUPS_LOOKUP';
export const UPDATE_PERMISSIONS_LOOKUP = 'UPDATE_PERMISSIONS_LOOKUP';
export const UPDATE_ROLES_UI = 'UPDATE_ROLES_UI';
export const UPDATE_HISTORY_UI = 'UPDATE_HISTORY_UI';
export const UPDATE_DOCUMENTS_UI = 'UPDATE_DOCUMENTS_UI';

// Search
export const UPDATE_EQUIPMENT_LIST_SEARCH = 'UPDATE_EQUIPMENT_LIST_SEARCH';
export const UPDATE_OWNERS_SEARCH = 'UPDATE_OWNERS_SEARCH';
export const UPDATE_PROJECTS_SEARCH = 'UPDATE_PROJECTS_SEARCH';
export const UPDATE_RENTAL_REQUESTS_SEARCH = 'UPDATE_RENTAL_REQUESTS_SEARCH';
export const UPDATE_USERS_SEARCH = 'UPDATE_USERS_SEARCH';
export const UPDATE_ROLES_SEARCH = 'UPDATE_ROLES_SEARCH';

// Lookups
export const UPDATE_CITIES_LOOKUP = 'UPDATE_CITIES';
export const UPDATE_DISTRICTS_LOOKUP = 'UPDATE_DISTRICTS';
export const UPDATE_REGIONS_LOOKUP = 'UPDATE_REGIONS';
export const UPDATE_SERVICE_AREAS_LOOKUP = 'UPDATE_SERVICE_AREAS';
export const UPDATE_LOCAL_AREAS_LOOKUP = 'UPDATE_LOCAL_AREAS';
export const UPDATE_OWNERS_LOOKUP = 'UPDATE_OWNERS_LOOKUP';
export const UPDATE_DISTRICT_EQUIPMENT_TYPES_LOOKUP = 'UPDATE_DISTRICT_EQUIPMENT_TYPES_LOOKUP';
export const UPDATE_EQUIPMENT_TYPES_LOOKUP = 'UPDATE_EQUIPMENT_TYPES_LOOKUP';
export const UPDATE_ROLES_LOOKUP = 'UPDATE_ROLES_LOOKUP';
export const UPDATE_PROJECTS_LOOKUP = 'UPDATE_PROJECTS_LOOKUP';
export const UPDATE_USERS_LOOKUP = 'UPDATE_USERS_LOOKUP';

// Current User
export const UPDATE_CURRENT_USER = 'UPDATE_CURRENT_USER';

// Users
export const UPDATE_USERS = 'UPDATE_USERS';
export const UPDATE_USER = 'UPDATE_USER';
export const ADD_USER = 'ADD_USER';
export const DELETE_USER = 'DELETE_USER';

// Favourites
export const UPDATE_FAVOURITES = 'UPDATE_FAVOURITES';
export const ADD_FAVOURITE = 'ADD_FAVOURITE';
export const UPDATE_FAVOURITE = 'UPDATE_FAVOURITE';
export const DELETE_FAVOURITE = 'DELETE_FAVOURITE';

// Contacts
export const UPDATE_CONTACTS = 'UPDATE_CONTACTS';
export const ADD_CONTACT = 'ADD_CONTACT';
export const UPDATE_CONTACT = 'UPDATE_CONTACT';
export const DELETE_CONTACT = 'DELETE_CONTACT';

// Documents
export const UPDATE_DOCUMENTS = 'UPDATE_DOCUMENTS';
export const ADD_DOCUMENT = 'ADD_DOCUMENT';
export const UPDATE_DOCUMENT = 'UPDATE_DOCUMENT';
export const DELETE_DOCUMENT = 'DELETE_DOCUMENT';

// Roles, Permissions
export const UPDATE_ROLES = 'UPDATE_ROLES';
export const UPDATE_ROLE = 'UPDATE_ROLE';
export const ADD_ROLE = 'ADD_ROLE';
export const DELETE_ROLE = 'DELETE_ROLE';
export const UPDATE_ROLE_PERMISSIONS = 'UPDATE_ROLE_PERMISSIONS';

// Equipment
export const UPDATE_EQUIPMENT_LIST = 'UPDATE_EQUIPMENT_LIST';
export const ADD_EQUIPMENT = 'ADD_EQUIPMENT';
export const UPDATE_EQUIPMENT = 'UPDATE_EQUIPMENT';

// Owners
export const UPDATE_OWNERS = 'UPDATE_OWNERS';
export const UPDATE_OWNER = 'UPDATE_OWNER';
export const ADD_OWNER = 'ADD_OWNER';
export const DELETE_OWNER = 'DELETE_OWNER';

// Projects
export const UPDATE_PROJECTS = 'UPDATE_PROJECTS';
export const UPDATE_PROJECT = 'UPDATE_PROJECT';
export const ADD_PROJECT = 'ADD_PROJECT';

// Rental Requests
export const UPDATE_RENTAL_REQUESTS = 'UPDATE_RENTAL_REQUESTS';
export const UPDATE_RENTAL_REQUEST = 'UPDATE_RENTAL_REQUEST';
export const ADD_RENTAL_REQUEST = 'ADD_RENTAL_REQUEST';

// Rotation List
export const UPDATE_RENTAL_REQUEST_ROTATION_LIST = 'UPDATE_RENTAL_REQUEST_ROTATION_LIST';

// Rental Agreements
export const UPDATE_RENTAL_AGREEMENT = 'UPDATE_RENTAL_AGREEMENT';
export const ADD_RENTAL_AGREEMENT = 'ADD_RENTAL_AGREEMENT';

// Rental Rates, Conditions
export const ADD_RENTAL_RATE = 'ADD_RENTAL_RATE';
export const UPDATE_RENTAL_RATE = 'UPDATE_RENTAL_RATE';
export const DELETE_RENTAL_RATE = 'DELETE_RENTAL_RATE';
export const ADD_RENTAL_CONDITION = 'ADD_RENTAL_CONDITION';
export const UPDATE_RENTAL_CONDITION = 'UPDATE_RENTAL_CONDITION';
export const DELETE_RENTAL_CONDITION = 'DELETE_RENTAL_CONDITION';

// Version
export const UPDATE_VERSION = 'UPDATE_VERSION';

// History
export const UPDATE_HISTORY = 'UPDATE_HISTORY';


'use strict';

describe('Controller: MainCtrl', function () {

  // load the controller's module
  beforeEach(module('autocompleteApp'));

  var MainCtrl,
    scope;

  // Initialize the controller and a mock scope
  beforeEach(inject(function ($controller, $rootScope) {
    scope = $rootScope.$new();
    MainCtrl = $controller('MainCtrl', {
      $scope: scope
    });
  }));

  it('should attach a list of awesomeThings to the scope', function () {
    expect(scope.awesomeThings.length).toBe(3);
  });
});


import {LocalStore} from "fluxx"
import * as actions from "./playFormActions"
import {
  defaultFieldValidation, FieldValidation, updateFieldValidation,
  updateUnchangedFieldValidation, Valid
} from "../../../framework/utils/Validation"
import {
  validateFuture, validateNonBlank, validateNonEmptyArray,
  validateNotNull, validatePositiveNumber
} from "../../../common/commonValidations"
import {copy} from "../../../framework/utils/object";
import {Theater} from "../../theater/theaterModel";
import messages from "../../../framework/messages";
import * as arrays from "../../../framework/utils/arrays";
import {Company} from "../../company/companyModel";
import {Show} from "../../show/showModel";

export interface PlayFormState {
  step: "loading" | "form" | "success"
  company: Company
  show: Show
  availableTheaters: Array<Theater>
  id?: string
  theater: FieldValidation<string>
  dates: FieldValidation<Array<DateValidation>>
  prices: FieldValidation<Array<PriceValidation>>
  errors?: Array<string>
}

export interface PriceValidation {
  name: FieldValidation<string>
  value: FieldValidation<number>
  condition: FieldValidation<string>
}

export interface DateValidation {
  date: FieldValidation<Date>
  reservationEndDate: FieldValidation<Date>
}

const defaultDateValidation: DateValidation = {
  date: defaultFieldValidation(null),
  reservationEndDate: defaultFieldValidation(null)
}

const defaultPriceValidation: PriceValidation = {
  name: defaultFieldValidation(""),
  value: defaultFieldValidation(0),
  condition: defaultFieldValidation("")
}

const initialState: PlayFormState = {
  step: "loading",
  company: null,
  show: null,
  availableTheaters: [],
  theater: defaultFieldValidation(""),
  dates: defaultFieldValidation([defaultDateValidation]),
  prices: defaultFieldValidation([defaultPriceValidation])
}

export const playFormStore = () => LocalStore(initialState, on => {
  on(actions.initialize, (state, {company, show, play, theaters}) => {
    if (play) {
      return copy(state, {
        step: "form",
        company,
        show,
        availableTheaters: theaters,
        id: play.id,
        theater: defaultFieldValidation(play.theater.id),
        dates: defaultFieldValidation([{
          date: defaultFieldValidation(play.date),
          reservationEndDate: defaultFieldValidation(play.reservationEndDate)
        }]),
        prices: defaultFieldValidation(
          play.prices.map(price => ({
            name: defaultFieldValidation(price.name),
            value: defaultFieldValidation(price.value),
            condition: defaultFieldValidation(price.condition)
          }))
        )
      })
    } else {
      return copy(state, {step: "form", company, show, availableTheaters: theaters})
    }
  })

  on(actions.updateTheater, (state, value) => {
    return copy(state, {
      theater: updateFieldValidation(state.theater, value, validateNonBlank(value))
    })
  })

  on(actions.addDate, (state) => {
    return updateDates(state, arrays.append(state.dates.value, defaultDateValidation))
  })

  on(actions.removeDate, (state, index) => {
    return updateDates(state, arrays.remove(state.dates.value, index))
  })

  on(actions.updateDate, (state, {index, value}) => {
    const currentDate = state.dates.value[index]
    return updateDates(state, arrays.replace(state.dates.value, index, copy(currentDate, {
      date: updateFieldValidation(currentDate.date, value, validateNotNull(value).flatMap(validateFuture)),
      reservationEndDate: updateUnchangedFieldValidation(currentDate.reservationEndDate, currentDate.reservationEndDate.value, validateReservationEndDate(currentDate.reservationEndDate.value, value))
    })))
  })

  on(actions.updateReservationEndDate, (state, {index, value}) => {
    const currentDate = state.dates.value[index]
    return updateDates(state, arrays.replace(state.dates.value, index, copy(currentDate, {
      reservationEndDate: updateFieldValidation(currentDate.reservationEndDate, value, validateReservationEndDate(value, currentDate.date.value))
    })))
  })

  on(actions.addPrice, (state) => {
    return updatePrices(state, arrays.append(state.prices.value, defaultPriceValidation))
  })

  on(actions.removePrice, (state, index) => {
    return updatePrices(state, arrays.remove(state.prices.value, index))
  })

  on(actions.updatePriceName, (state, {index, value}) => {
    const currentPrice = state.prices.value[index]
    return updatePrices(state, arrays.replace(state.prices.value, index, copy(currentPrice, {
      name: updateFieldValidation(currentPrice.name, value, validateNonBlank(value))
    })))
  })

  on(actions.updatePriceValue, (state, {index, value}) => {
    const currentPrice = state.prices.value[index]
    return updatePrices(state, arrays.replace(state.prices.value, index, copy(currentPrice, {
      value: updateFieldValidation(currentPrice.value, value, validatePositiveNumber(value))
    })))
  })

  on(actions.updatePriceCondition, (state, {index, value}) => {
    const currentPrice = state.prices.value[index]
    return updatePrices(state, arrays.replace(state.prices.value, index, copy(currentPrice, {
      condition: updateFieldValidation(currentPrice.condition, value, Valid(value))
    })))
  })

  on(actions.closeErrors, (state) => {
    return copy(state, {errors: null})
  })

  on(actions.success, (state) => {
    return copy(state, {step: "success"})
  })
})

function validateReservationEndDate(reservationEndDate: Date, date: Date) {
  return validateNotNull(reservationEndDate)
    .flatMap(validateFuture)
    .filter(reservationEndDate => reservationEndDate < date, messages.production.play.form.reservationEndDateAfterDate)
}

function updateDates(state: PlayFormState, dates: Array<DateValidation>) {
  return copy(state, {
    dates: updateFieldValidation(state.dates, dates, validateDates(dates))
  })
}

function validateDates(dates: Array<DateValidation>) {
  return validateNonEmptyArray(dates)
}

function updatePrices(state: PlayFormState, prices: Array<PriceValidation>) {
  return copy(state, {
    prices: updateFieldValidation(state.prices, prices, validatePrices(prices))
  })
}

function validatePrices(prices: Array<PriceValidation>) {
  return validateNonEmptyArray(prices)
}


[![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)

> HTTP frontend to the Cisco Webex JS SDK

Why would we put an http server in front of our SDK? Encryption is hard and this lets all of our client test suites (potentially written in languages for which we do not have sdks) do encrypted things without a major time expenditure

- [Install](#install)
- [Usage](#usage)
- [Contribute](#contribute)
- [Maintainers](#maintainers)
- [License](#license)

## Install

```bash
  npm install -g @webex/webex-server
```

## Usage

Start the daemon

```bash
webex-server
```

Create a session (make sure to copy your set cookie header)

```bash
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"clientId":"<your client id>","clientSecret":"<your client secret>","redirectUri":"<your  redirect_uri>","scope":"<your scopes>"}' \
  http://localhost:3000/api/v1/session
```

(optional) Create a conversation

> SDK: webex.internal.conversation.create({comment: 'first comment', displayName: 'title', participants: ['<userId1>', '<userId2>', '<userId3>']})

```
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Cookie: <connect.sid cookie from step one>" \
  -d '[{"comment":"first message","displayName":"title","participants":["userId1","userId2","userId3"]}]'
  -v \
  http://localhost:3000/api/v1/session/invoke/internal/conversation/create
```

(optional) Post a message

> SDK: `webex.inernal.conversation.post({url: '<conversation url>', {displayName: 'second comment'}})`

```
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Cookie: <connect.sid cookie from step one>" \
  -d [{"url":"<conversation url>"},{"displayName":"second comment"}]
  -v \
  http://localhost:3000/api/v1/session/invoke/internal/conversation/post
```

(optional) Fetch a conversation

> SDK: `webex.internal.conversation.get({url: '<conversation url>'})`
> SDK: `webex.internal.conversation.get({url: '<conversation url>'})`

```
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Cookie: <connect.sid cookie from step one>" \
  -d [{"url":"<conversation url>"}]
  -v \
  http://localhost:3000/api/v1/session/invoke/internal/conversation/get
```

Clean up your session (If you don't do this, you'll have a bunch of long-running web socket connections)

```
curl -X DELETE \
  -H "Content-Type: application/json" \
  -H "Cookie: <connect.sid cookie from step one>" \
  -v \
  http://localhost:3000/api/v1/session
```

## Maintainers

This package is maintained by [Cisco Webex for Developers](https://developer.webex.com/).

## Contribute

Pull requests welcome. Please see [CONTRIBUTING.md](https://github.com/webex/webex-js-sdk/blob/master/CONTRIBUTING.md) for more details.

## License

© 2016-2019 Cisco and/or its affiliates. All Rights Reserved.