text:
#==============================================================================#
# CloudHSM.jl
#
# This file is generated from:
# https://github.com/aws/aws-sdk-js/blob/master/apis/cloudhsm-2014-05-30.normal.json
#==============================================================================#

__precompile__()

module CloudHSM

using AWSCore

"""
    using AWSSDK.CloudHSM.add_tags_to_resource
    add_tags_to_resource([::AWSConfig], arguments::Dict)
    add_tags_to_resource([::AWSConfig]; ResourceArn=, TagList=)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "AddTagsToResource", arguments::Dict)
    cloudhsm([::AWSConfig], "AddTagsToResource", ResourceArn=, TagList=)

# AddTagsToResource Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Adds or overwrites one or more tags for the specified AWS CloudHSM resource.

Each tag consists of a key and a value. Tag keys must be unique to each resource.

# Arguments

## `ResourceArn = ::String` -- *Required*
The Amazon Resource Name (ARN) of the AWS CloudHSM resource to tag.

## `TagList = [[ ... ], ...]` -- *Required*
One or more tags.
```
 TagList = [[
        "Key" => <required> ::String,
        "Value" => <required> ::String
    ], ...]
```

# Returns

`AddTagsToResourceResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/AddTagsToResource)
"""
@inline add_tags_to_resource(aws::AWSConfig=default_aws_config(); args...) = add_tags_to_resource(aws, args)

@inline add_tags_to_resource(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "AddTagsToResource", args)

@inline add_tags_to_resource(args) = add_tags_to_resource(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.create_hapg
    create_hapg([::AWSConfig], arguments::Dict)
    create_hapg([::AWSConfig]; Label=)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "CreateHapg", arguments::Dict)
    cloudhsm([::AWSConfig], "CreateHapg", Label=)

# CreateHapg Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Creates a high-availability partition group. A high-availability partition group is a group of partitions that spans multiple physical HSMs.

# Arguments

## `Label = ::String` -- *Required*
The label of the new high-availability partition group.

# Returns

`CreateHapgResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/CreateHapg)
"""
@inline create_hapg(aws::AWSConfig=default_aws_config(); args...) = create_hapg(aws, args)

@inline create_hapg(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "CreateHapg", args)

@inline create_hapg(args) = create_hapg(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.create_hsm
    create_hsm([::AWSConfig], arguments::Dict)
    create_hsm([::AWSConfig]; SubnetId=, SshKey=, IamRoleArn=, SubscriptionType=, <keyword arguments>)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "CreateHsm", arguments::Dict)
    cloudhsm([::AWSConfig], "CreateHsm", SubnetId=, SshKey=, IamRoleArn=, SubscriptionType=, <keyword arguments>)

# CreateHsm Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Creates an uninitialized HSM instance.

There is an upfront fee charged for each HSM instance that you create with the `CreateHsm` operation. If you accidentally provision an HSM and want to request a refund, delete the instance using the [DeleteHsm](@ref) operation, go to the [AWS Support Center](https://console.aws.amazon.com/support/home), create a new case, and select **Account and Billing Support**.

**Important**
> It can take up to 20 minutes to create and provision an HSM. You can monitor the status of the HSM with the [DescribeHsm](@ref) operation. The HSM is ready to be initialized when the status changes to `RUNNING`.

# Arguments

## `SubnetId = ::String` -- *Required*
The identifier of the subnet in your VPC in which to place the HSM.

## `SshKey = ::String` -- *Required*
The SSH public key to install on the HSM.

## `EniIp = ::String`
The IP address to assign to the HSM's ENI.

If an IP address is not specified, an IP address will be randomly chosen from the CIDR range of the subnet.

## `IamRoleArn = ::String` -- *Required*
The ARN of an IAM role to enable the AWS CloudHSM service to allocate an ENI on your behalf.

## `ExternalId = ::String`
The external ID from `IamRoleArn`, if present.

## `SubscriptionType = "PRODUCTION"` -- *Required*

## `ClientToken = ::String`
A user-defined token to ensure idempotence. Subsequent calls to this operation with the same token will be ignored.

## `SyslogIp = ::String`
The IP address for the syslog monitoring server. The AWS CloudHSM service only supports one syslog monitoring server.

# Returns

`CreateHsmResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/CreateHsm)
"""
@inline create_hsm(aws::AWSConfig=default_aws_config(); args...) = create_hsm(aws, args)

@inline create_hsm(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "CreateHsm", args)

@inline create_hsm(args) = create_hsm(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.create_luna_client
    create_luna_client([::AWSConfig], arguments::Dict)
    create_luna_client([::AWSConfig]; Certificate=, <keyword arguments>)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "CreateLunaClient", arguments::Dict)
    cloudhsm([::AWSConfig], "CreateLunaClient", Certificate=, <keyword arguments>)

# CreateLunaClient Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Creates an HSM client.

# Arguments

## `Label = ::String`
The label for the client.

## `Certificate = ::String` -- *Required*
The contents of a Base64-Encoded X.509 v3 certificate to be installed on the HSMs used by this client.

# Returns

`CreateLunaClientResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/CreateLunaClient)
"""
@inline create_luna_client(aws::AWSConfig=default_aws_config(); args...) = create_luna_client(aws, args)

@inline create_luna_client(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "CreateLunaClient", args)

@inline create_luna_client(args) = create_luna_client(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.delete_hapg
    delete_hapg([::AWSConfig], arguments::Dict)
    delete_hapg([::AWSConfig]; HapgArn=)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "DeleteHapg", arguments::Dict)
    cloudhsm([::AWSConfig], "DeleteHapg", HapgArn=)

# DeleteHapg Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Deletes a high-availability partition group.

# Arguments

## `HapgArn = ::String` -- *Required*
The ARN of the high-availability partition group to delete.

# Returns

`DeleteHapgResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/DeleteHapg)
"""
@inline delete_hapg(aws::AWSConfig=default_aws_config(); args...) = delete_hapg(aws, args)

@inline delete_hapg(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "DeleteHapg", args)

@inline delete_hapg(args) = delete_hapg(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.delete_hsm
    delete_hsm([::AWSConfig], arguments::Dict)
    delete_hsm([::AWSConfig]; HsmArn=)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "DeleteHsm", arguments::Dict)
    cloudhsm([::AWSConfig], "DeleteHsm", HsmArn=)

# DeleteHsm Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Deletes an HSM. After completion, this operation cannot be undone and your key material cannot be recovered.

# Arguments

## `HsmArn = ::String` -- *Required*
The ARN of the HSM to delete.

# Returns

`DeleteHsmResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/DeleteHsm)
"""
@inline delete_hsm(aws::AWSConfig=default_aws_config(); args...) = delete_hsm(aws, args)

@inline delete_hsm(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "DeleteHsm", args)

@inline delete_hsm(args) = delete_hsm(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.delete_luna_client
    delete_luna_client([::AWSConfig], arguments::Dict)
    delete_luna_client([::AWSConfig]; ClientArn=)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "DeleteLunaClient", arguments::Dict)
    cloudhsm([::AWSConfig], "DeleteLunaClient", ClientArn=)

# DeleteLunaClient Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Deletes a client.

# Arguments

## `ClientArn = ::String` -- *Required*
The ARN of the client to delete.

# Returns

`DeleteLunaClientResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/DeleteLunaClient)
"""
@inline delete_luna_client(aws::AWSConfig=default_aws_config(); args...) = delete_luna_client(aws, args)

@inline delete_luna_client(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "DeleteLunaClient", args)

@inline delete_luna_client(args) = delete_luna_client(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.describe_hapg
    describe_hapg([::AWSConfig], arguments::Dict)
    describe_hapg([::AWSConfig]; HapgArn=)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "DescribeHapg", arguments::Dict)
    cloudhsm([::AWSConfig], "DescribeHapg", HapgArn=)

# DescribeHapg Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Retrieves information about a high-availability partition group.

# Arguments

## `HapgArn = ::String` -- *Required*
The ARN of the high-availability partition group to describe.

# Returns

`DescribeHapgResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/DescribeHapg)
"""
@inline describe_hapg(aws::AWSConfig=default_aws_config(); args...) = describe_hapg(aws, args)

@inline describe_hapg(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "DescribeHapg", args)

@inline describe_hapg(args) = describe_hapg(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.describe_hsm
    describe_hsm([::AWSConfig], arguments::Dict)
    describe_hsm([::AWSConfig]; <keyword arguments>)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "DescribeHsm", arguments::Dict)
    cloudhsm([::AWSConfig], "DescribeHsm", <keyword arguments>)

# DescribeHsm Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Retrieves information about an HSM. You can identify the HSM by its ARN or its serial number.

# Arguments

## `HsmArn = ::String`
The ARN of the HSM. Either the `HsmArn` or the `SerialNumber` parameter must be specified.

## `HsmSerialNumber = ::String`
The serial number of the HSM. Either the `HsmArn` or the `HsmSerialNumber` parameter must be specified.

# Returns

`DescribeHsmResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/DescribeHsm)
"""
@inline describe_hsm(aws::AWSConfig=default_aws_config(); args...) = describe_hsm(aws, args)

@inline describe_hsm(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "DescribeHsm", args)

@inline describe_hsm(args) = describe_hsm(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.describe_luna_client
    describe_luna_client([::AWSConfig], arguments::Dict)
    describe_luna_client([::AWSConfig]; <keyword arguments>)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "DescribeLunaClient", arguments::Dict)
    cloudhsm([::AWSConfig], "DescribeLunaClient", <keyword arguments>)

# DescribeLunaClient Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Retrieves information about an HSM client.

# Arguments

## `ClientArn = ::String`
The ARN of the client.

## `CertificateFingerprint = ::String`
The certificate fingerprint.

# Returns

`DescribeLunaClientResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/DescribeLunaClient)
"""
@inline describe_luna_client(aws::AWSConfig=default_aws_config(); args...) = describe_luna_client(aws, args)

@inline describe_luna_client(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "DescribeLunaClient", args)

@inline describe_luna_client(args) = describe_luna_client(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.get_config
    get_config([::AWSConfig], arguments::Dict)
    get_config([::AWSConfig]; ClientArn=, ClientVersion=, HapgList=)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "GetConfig", arguments::Dict)
    cloudhsm([::AWSConfig], "GetConfig", ClientArn=, ClientVersion=, HapgList=)

# GetConfig Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Gets the configuration files necessary to connect to all high availability partition groups the client is associated with.

# Arguments

## `ClientArn = ::String` -- *Required*
The ARN of the client.

## `ClientVersion = "5.1" or "5.3"` -- *Required*
The client version.

## `HapgList = [::String, ...]` -- *Required*
A list of ARNs that identify the high-availability partition groups that are associated with the client.

# Returns

`GetConfigResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/GetConfig)
"""
@inline get_config(aws::AWSConfig=default_aws_config(); args...) = get_config(aws, args)

@inline get_config(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "GetConfig", args)

@inline get_config(args) = get_config(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.list_available_zones
    list_available_zones([::AWSConfig], arguments::Dict)
    list_available_zones([::AWSConfig]; )

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "ListAvailableZones", arguments::Dict)
    cloudhsm([::AWSConfig], "ListAvailableZones", )

# ListAvailableZones Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Lists the Availability Zones that have available AWS CloudHSM capacity.

# Arguments

# Returns

`ListAvailableZonesResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/ListAvailableZones)
"""
@inline list_available_zones(aws::AWSConfig=default_aws_config(); args...) = list_available_zones(aws, args)

@inline list_available_zones(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "ListAvailableZones", args)

@inline list_available_zones(args) = list_available_zones(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.list_hapgs
    list_hapgs([::AWSConfig], arguments::Dict)
    list_hapgs([::AWSConfig]; <keyword arguments>)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "ListHapgs", arguments::Dict)
    cloudhsm([::AWSConfig], "ListHapgs", <keyword arguments>)

# ListHapgs Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Lists the high-availability partition groups for the account.

This operation supports pagination with the use of the `NextToken` member. If more results are available, the `NextToken` member of the response contains a token that you pass in the next call to `ListHapgs` to retrieve the next set of items.

# Arguments

## `NextToken = ::String`
The `NextToken` value from a previous call to `ListHapgs`. Pass null if this is the first call.

# Returns

`ListHapgsResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/ListHapgs)
"""
@inline list_hapgs(aws::AWSConfig=default_aws_config(); args...) = list_hapgs(aws, args)

@inline list_hapgs(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "ListHapgs", args)

@inline list_hapgs(args) = list_hapgs(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.list_hsms
    list_hsms([::AWSConfig], arguments::Dict)
    list_hsms([::AWSConfig]; <keyword arguments>)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "ListHsms", arguments::Dict)
    cloudhsm([::AWSConfig], "ListHsms", <keyword arguments>)

# ListHsms Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Retrieves the identifiers of all of the HSMs provisioned for the current customer.

This operation supports pagination with the use of the `NextToken` member. If more results are available, the `NextToken` member of the response contains a token that you pass in the next call to `ListHsms` to retrieve the next set of items.

# Arguments

## `NextToken = ::String`
The `NextToken` value from a previous call to `ListHsms`. Pass null if this is the first call.

# Returns

`ListHsmsResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/ListHsms)
"""
@inline list_hsms(aws::AWSConfig=default_aws_config(); args...) = list_hsms(aws, args)

@inline list_hsms(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "ListHsms", args)

@inline list_hsms(args) = list_hsms(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.list_luna_clients
    list_luna_clients([::AWSConfig], arguments::Dict)
    list_luna_clients([::AWSConfig]; <keyword arguments>)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "ListLunaClients", arguments::Dict)
    cloudhsm([::AWSConfig], "ListLunaClients", <keyword arguments>)

# ListLunaClients Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Lists all of the clients.

This operation supports pagination with the use of the `NextToken` member. If more results are available, the `NextToken` member of the response contains a token that you pass in the next call to `ListLunaClients` to retrieve the next set of items.

# Arguments

## `NextToken = ::String`
The `NextToken` value from a previous call to `ListLunaClients`. Pass null if this is the first call.

# Returns

`ListLunaClientsResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/ListLunaClients)
"""
@inline list_luna_clients(aws::AWSConfig=default_aws_config(); args...) = list_luna_clients(aws, args)

@inline list_luna_clients(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "ListLunaClients", args)

@inline list_luna_clients(args) = list_luna_clients(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.list_tags_for_resource
    list_tags_for_resource([::AWSConfig], arguments::Dict)
    list_tags_for_resource([::AWSConfig]; ResourceArn=)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "ListTagsForResource", arguments::Dict)
    cloudhsm([::AWSConfig], "ListTagsForResource", ResourceArn=)

# ListTagsForResource Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Returns a list of all tags for the specified AWS CloudHSM resource.

# Arguments

## `ResourceArn = ::String` -- *Required*
The Amazon Resource Name (ARN) of the AWS CloudHSM resource.

# Returns

`ListTagsForResourceResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/ListTagsForResource)
"""
@inline list_tags_for_resource(aws::AWSConfig=default_aws_config(); args...) = list_tags_for_resource(aws, args)

@inline list_tags_for_resource(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "ListTagsForResource", args)

@inline list_tags_for_resource(args) = list_tags_for_resource(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.modify_hapg
    modify_hapg([::AWSConfig], arguments::Dict)
    modify_hapg([::AWSConfig]; HapgArn=, <keyword arguments>)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "ModifyHapg", arguments::Dict)
    cloudhsm([::AWSConfig], "ModifyHapg", HapgArn=, <keyword arguments>)

# ModifyHapg Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Modifies an existing high-availability partition group.

# Arguments

## `HapgArn = ::String` -- *Required*
The ARN of the high-availability partition group to modify.

## `Label = ::String`
The new label for the high-availability partition group.

## `PartitionSerialList = [::String, ...]`
The list of partition serial numbers to make members of the high-availability partition group.

# Returns

`ModifyHapgResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/ModifyHapg)
"""
@inline modify_hapg(aws::AWSConfig=default_aws_config(); args...) = modify_hapg(aws, args)

@inline modify_hapg(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "ModifyHapg", args)

@inline modify_hapg(args) = modify_hapg(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.modify_hsm
    modify_hsm([::AWSConfig], arguments::Dict)
    modify_hsm([::AWSConfig]; HsmArn=, <keyword arguments>)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "ModifyHsm", arguments::Dict)
    cloudhsm([::AWSConfig], "ModifyHsm", HsmArn=, <keyword arguments>)

# ModifyHsm Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Modifies an HSM.

**Important**
> This operation can result in the HSM being offline for up to 15 minutes while the AWS CloudHSM service is reconfigured. If you are modifying a production HSM, you should ensure that your AWS CloudHSM service is configured for high availability, and consider executing this operation during a maintenance window.

# Arguments

## `HsmArn = ::String` -- *Required*
The ARN of the HSM to modify.

## `SubnetId = ::String`
The new identifier of the subnet that the HSM is in. The new subnet must be in the same Availability Zone as the current subnet.

## `EniIp = ::String`
The new IP address for the elastic network interface (ENI) attached to the HSM.

If the HSM is moved to a different subnet, and an IP address is not specified, an IP address will be randomly chosen from the CIDR range of the new subnet.

## `IamRoleArn = ::String`
The new IAM role ARN.

## `ExternalId = ::String`
The new external ID.

## `SyslogIp = ::String`
The new IP address for the syslog monitoring server. The AWS CloudHSM service only supports one syslog monitoring server.

# Returns

`ModifyHsmResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/ModifyHsm)
"""
@inline modify_hsm(aws::AWSConfig=default_aws_config(); args...) = modify_hsm(aws, args)

@inline modify_hsm(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "ModifyHsm", args)

@inline modify_hsm(args) = modify_hsm(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.modify_luna_client
    modify_luna_client([::AWSConfig], arguments::Dict)
    modify_luna_client([::AWSConfig]; ClientArn=, Certificate=)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "ModifyLunaClient", arguments::Dict)
    cloudhsm([::AWSConfig], "ModifyLunaClient", ClientArn=, Certificate=)

# ModifyLunaClient Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Modifies the certificate used by the client.

This action can potentially start a workflow to install the new certificate on the client's HSMs.

# Arguments

## `ClientArn = ::String` -- *Required*
The ARN of the client.

## `Certificate = ::String` -- *Required*
The new certificate for the client.

# Returns

`ModifyLunaClientResponse`

# Exceptions

`CloudHsmServiceException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/ModifyLunaClient)
"""
@inline modify_luna_client(aws::AWSConfig=default_aws_config(); args...) = modify_luna_client(aws, args)

@inline modify_luna_client(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "ModifyLunaClient", args)

@inline modify_luna_client(args) = modify_luna_client(default_aws_config(), args)

"""
    using AWSSDK.CloudHSM.remove_tags_from_resource
    remove_tags_from_resource([::AWSConfig], arguments::Dict)
    remove_tags_from_resource([::AWSConfig]; ResourceArn=, TagKeyList=)

    using AWSCore.Services.cloudhsm
    cloudhsm([::AWSConfig], "RemoveTagsFromResource", arguments::Dict)
    cloudhsm([::AWSConfig], "RemoveTagsFromResource", ResourceArn=, TagKeyList=)

# RemoveTagsFromResource Operation

This is documentation for **AWS CloudHSM Classic**. For more information, see [AWS CloudHSM Classic FAQs](http://aws.amazon.com/cloudhsm/faqs-classic/), the [AWS CloudHSM Classic User Guide](http://docs.aws.amazon.com/cloudhsm/classic/userguide/), and the [AWS CloudHSM Classic API Reference](http://docs.aws.amazon.com/cloudhsm/classic/APIReference/).

**For information about the current version of AWS CloudHSM**, see [AWS CloudHSM](http://aws.amazon.com/cloudhsm/), the [AWS CloudHSM User Guide](http://docs.aws.amazon.com/cloudhsm/latest/userguide/), and the [AWS CloudHSM API Reference](http://docs.aws.amazon.com/cloudhsm/latest/APIReference/).

Removes one or more tags from the specified AWS CloudHSM resource.

To remove a tag, specify only the tag key to remove (not the value). To overwrite the value for an existing tag, use [AddTagsToResource](@ref).

# Arguments

## `ResourceArn = ::String` -- *Required*
The Amazon Resource Name (ARN) of the AWS CloudHSM resource.

## `TagKeyList = [::String, ...]` -- *Required*
The tag key or keys to remove.

Specify only the tag key to remove (not the value). To overwrite the value for an existing tag, use [AddTagsToResource](@ref).

# Returns

`RemoveTagsFromResourceResponse`

# Exceptions

`CloudHsmServiceException`, `CloudHsmInternalException` or `InvalidRequestException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/cloudhsm-2014-05-30/RemoveTagsFromResource)
"""
@inline remove_tags_from_resource(aws::AWSConfig=default_aws_config(); args...) = remove_tags_from_resource(aws, args)

@inline remove_tags_from_resource(aws::AWSConfig, args) = AWSCore.Services.cloudhsm(aws, "RemoveTagsFromResource", args)

@inline remove_tags_from_resource(args) = remove_tags_from_resource(default_aws_config(), args)

end # module CloudHSM

#==============================================================================#
# End of file
#==============================================================================#


text:
print_all(Lexers.JuliaLexer, "jlcon")

tokentest(
    Lexers.JuliaConsoleLexer,
    "julia> x = 2\n2",
    NUMBER => "julia> ",
    NAME => "x",
    TEXT => " ",
    OPERATOR => "=",
    TEXT => " ",
    NUMBER_INTEGER => "2",
    TEXT => "\n2",
)

tokentest(
    Lexers.JuliaConsoleLexer,
    "julia> x\n2\n\nhelp?> sin\n...",
    NUMBER => "julia> ",
    NAME => "x",
    TEXT => "\n2\n\n",
    NUMBER => "help?> ",
    NAME => "sin",
    TEXT => "\n...",
)

tokentest(
    Lexers.JuliaConsoleLexer,
    """
    julia> A = [4. 3.; 6. 3.]
    2×2 Array{Float64,2}:
     4.0  3.0
     6.0  3.0

    julia> function f(x)
                x + 1
           end
           f(x)

           b = f(0.0)
    1.0
    """,
    NUMBER => "julia> ",
    NAME => "A",
    TEXT => " ",
    OPERATOR => "=",
    TEXT => " ",
    PUNCTUATION => "[",
    NUMBER_FLOAT => "4.",
    TEXT => " ",
    NUMBER_FLOAT => "3.",
    PUNCTUATION => ";",
    TEXT => " ",
    NUMBER_FLOAT => "6.",
    TEXT => " ",
    NUMBER_FLOAT => "3.",
    PUNCTUATION => "]",
    TEXT => "\n2×2 Array{Float64,2}:\n 4.0  3.0\n 6.0  3.0\n\n",
    NUMBER => "julia> ",
    KEYWORD => "function",
    TEXT => " ",
    NAME_FUNCTION => "f",
    PUNCTUATION => "(",
    NAME => "x",
    PUNCTUATION => ")",
    TEXT => "\n            ",
    NAME => "x",
    TEXT => " ",
    OPERATOR => "+",
    TEXT => " ",
    NUMBER_INTEGER => "1",
    TEXT => "\n       ",
    KEYWORD => "end",
    TEXT => "\n       ",
    NAME_FUNCTION => "f",
    PUNCTUATION => "(",
    NAME => "x",
    PUNCTUATION => ")",
    TEXT => "\n\n       ",
    NAME => "b",
    TEXT => " ",
    OPERATOR => "=",
    TEXT => " ",
    NAME_FUNCTION => "f",
    PUNCTUATION => "(",
    NUMBER_FLOAT => "0.0",
    PUNCTUATION => ")",
    TEXT => "\n1.0\n",
)

tokentest(
    Lexers.JuliaConsoleLexer,
    """
    julia> f(x) = x + 2
    f

    julia> a = f(1)

           b = f(2)
           a + b
    7
    """,
    NUMBER => "julia> ",
    NAME_FUNCTION => "f",
    PUNCTUATION => "(",
    NAME => "x",
    PUNCTUATION => ")",
    TEXT => " ",
    OPERATOR => "=",
    TEXT => " ",
    NAME => "x",
    TEXT => " ",
    OPERATOR => "+",
    TEXT => " ",
    NUMBER_INTEGER => "2",
    TEXT => "\nf\n\n",
    NUMBER => "julia> ",
    NAME => "a",
    TEXT => " ",
    OPERATOR => "=",
    TEXT => " ",
    NAME_FUNCTION => "f",
    PUNCTUATION => "(",
    NUMBER_INTEGER => "1",
    PUNCTUATION => ")",
    TEXT => "\n\n\n       ",
    NAME => "b",
    TEXT => " ",
    OPERATOR => "=",
    TEXT => " ",
    NAME_FUNCTION => "f",
    PUNCTUATION => "(",
    NUMBER_INTEGER => "2",
    PUNCTUATION => ")",
    TEXT => "\n       ",
    NAME => "a",
    TEXT => " ",
    OPERATOR => "+",
    TEXT => " ",
    NAME => "b",
    TEXT => "\n7\n",
)

tokentest(
    Lexers.JuliaConsoleLexer,
    """
    julia> @show β
    β = 10""",
    NUMBER => "julia> ",
    NAME_DECORATOR => "@show",
    TEXT => " ",
    NAME => "β",
    TEXT => "\nβ = 10",
)

ext: jl


text:
using Documenter
Documenter.makedocs(root="/",
  source="../src",
  build="build",
  clean= true,
  doctest=Module[all],
  repo="",
  highlightsig="true",
  sitename="col",
  expandfirst=[],
  pages=[
         "Index" => "index.md"
        ]
  )

max_stars_repo_name: timm/jut

max_issues_repo_name: timm/jut

max_forks_repo_name: timm/jut


text:
#using TensorToolbox, Test, LinearAlgebra

println("\n\n****Testing ktensor.jl")

Isz=5;J=4;K=3;
a=rand(Isz);
b=rand(J);
c=rand(K);
X=zeros(Isz,J,K);
for i=1:Isz,j=1:J,k=1:K
    X[i,j,k]=a[i]*b[j]*c[k];
end
println("\n**Test rank-1 tensor X of size: ", size(X))
println("...Testing cp_als.")
Z=cp_als(X,1)
err=norm(full(Z)-X)
println("norm(full(Xcp)-X) = ",err)
@test err ≈ 0 atol=1e-10

#Ax = rand(4,2)
#Bx = rand(3,2)
#Cx = rand(2,2)
#Xlambda=[0.5,2]
#X = ktensor(Xlambda,[Ax,Bx,Cx])
X=randktensor([4,3,2],2)
Ay = rand(4,3)
By = rand(3,3)
Cy = rand(2,3)
Ylambda=[2,3,1]
Y=ktensor(Ylambda,[Ay,By,Cy])

println("\n**Test ktensors X and Y of size: ", size(X))
println()

println("...Testing function ndims.")
println("X is of order: ",ndims(X))

println("...Testing function ttensor and full.")
T=ttensor(X)
@test norm(full(T)-full(X)) ≈ 0 atol=1e-10

println("...Testing scalar multiplication.")
err=norm(full(3*X) - 3*full(X))
println("norm(full(3*X) - 3*full(X)) = ",err)
@test norm(full(3*X) - 3*full(X)) ≈ 0 atol=1e-10

println("...Testing functions plus and minus.")
Z=X+Y
err=norm(full(Z)-(full(X)+full(Y)))
println("norm(full(Z)-(full(X)+full(Y))) = ",err)
@test err ≈ 0 atol=1e-10
Z=X-Y
err=norm(full(Z)-(full(X)-full(Y)))
println("norm(full(Z)-(full(X)-full(Y))) = ",err)
@test err ≈ 0 atol=1e-10

println("...Testing function innerprod.")
err=norm(innerprod(X,Y)-innerprod(full(X),full(Y)))
println("norm(innerprod(X,Y)-innerprod(full(X),full(Y))) = ",err)
@test err  ≈ 0 atol=1e-10
Z=rand(4,3,2)
@test norm(innerprod(X,Z)-innerprod(full(X),Z)) ≈ 0 atol=1e-10

println("...Testing function norm.")
@test abs(norm(X)-norm(full(X)))≈ 0 atol=1e-10

println("...Testing functions arrange and arrange!.")
Z=arrange(X)
err=norm(full(X)-full(Z))
println("norm(full(X)-full(Z)) = ",err)
@test err ≈ 0 atol=1e-10
Z=arrange(X,2)
@test norm(full(X)-full(Z)) ≈ 0 atol=1e-10
Z=arrange(X,[2,1])
@test norm(full(X)-full(Z)) ≈ 0 atol=1e-10
Xcopy=deepcopy(X)
arrange!(X)
@test norm(full(X)-full(Xcopy)) ≈ 0 atol=1e-10
arrange!(X,2)
@test norm(full(X)-full(Xcopy)) ≈ 0 atol=1e-10
arrange!(X,[2,1])
@test norm(full(X)-full(Xcopy)) ≈ 0 atol=1e-10

println("...Testing functions normalize and normalize!.")
Z=normalize(X)
err=norm(full(X)-full(Z))
println("norm(full(X)-full(Z)) = ",err)
@test err ≈ 0 atol=1e-10
Z=normalize(X,2)
@test norm(full(X)-full(Z)) ≈ 0 atol=1e-10
Z=normalize(X,3,normtype=1)
@test norm(full(X)-full(Z)) ≈ 0 atol=1e-10
Z=normalize(X,"sort")
@test norm(full(X)-full(Z)) ≈ 0 atol=1e-10
Z=normalize(X,factor=2)
@test norm(full(X)-full(Z)) ≈ 0 atol=1e-10
Xcopy=deepcopy(X)
normalize!(X)
@test norm(full(X)-full(Xcopy)) ≈ 0 atol=1e-10
normalize!(X,2)
@test norm(full(X)-full(Xcopy)) ≈ 0 atol=1e-10
normalize!(X,3,normtype=1)
@test norm(full(X)-full(Xcopy)) ≈ 0 atol=1e-10
normalize!(X,"sort")
@test norm(full(X)-full(Xcopy)) ≈ 0 atol=1e-10
normalize!(X,factor=2)
@test norm(full(X)-full(Xcopy)) ≈ 0 atol=1e-10

println("...Testing functions redistribute and redistribute!.")
mode=2
Z=redistribute(X,mode)
err=norm(full(X)-full(Z))
println("norm(full(X)-full(Z)) = ",err)
@test err ≈ 0 atol=1e-10
Xcopy=deepcopy(X)
redistribute!(X,mode)
@test norm(full(X)-full(Xcopy)) ≈ 0 atol=1e-10

println("...Testing functions fixsigns, fixsigns! and isequal.")
Xcopy=deepcopy(X)
X.fmat[1][:,1]=-X.fmat[1][:,1]
X.fmat[2][:,1]=-X.fmat[2][:,1]
Z=fixsigns(X)
err=norm(full(X)-full(Z))
println("norm(full(X)-full(Z)) = ",err)
@test err ≈ 0 atol=1e-10
fixsigns!(X)
@test norm(X-Xcopy) ≈ 0 atol=1e-7

println("...Testing functions ttm and ttv.")
M=MatrixCell(undef,2)
M[1]=rand(4,3)
M[2]=rand(4,2)
mode=[2,3]
Z=ttm(X,M,mode)
W=ttm(full(X),M,mode)
@test norm(W-full(Z)) ≈ 0 atol=1e-10
v=VectorCell(undef,2)
v[1]=rand(3)
v[2]=rand(2)
mode=[2,3]
Z=ttv(X,v,mode)
W=ttv(full(X),v,mode)
@test norm(W-full(Z)) ≈ 0 atol=1e-10

println("\n...Testing function tocell.")
M=tocell(X)
println("Is the output MatrixCell: ",isa(M,MatrixCell))
@test isa(M,MatrixCell)

mode=2;
println("\n...Testing function tenmat by mode $mode.")
Xn=tenmat(X,mode)
@test tenmat(full(X),mode) == Xn

println("\n...Testing function mttkrp.")
X=randktensor([5,4,3],3)
mode=1
M1=rand(5,5);
M2=rand(4,5);
M3=rand(3,5);
M=[M1,M2,M3]
println("Multiplying mode-$mode matricized tensor X by Khatri-Rao product of matrices.")
Z=mttkrp(X,M,mode)
err = norm(Z-tenmat(X,mode)*khatrirao(M3,M2))
println("Multiplication error: ",err)
@test err ≈ 0 atol=1e-10


text:
# Numerical Integration

struct GaussLegendre
    nip::Int  # number of integral points
    nodes::Vector{Float64}
    weights::Vector{Float64}
    function GaussLegendre(nip::Int)
        nodes, weights = gausslegendre(nip)
        return new(nip, nodes, weights)
    end
end

"""
Integrate on interval
"""
function integrate(func, I1::ClosedInterval{<:Real}, gl1)
    nip1, nodes1, weights1 = gl1.nip, gl1.nodes, gl1.weights
    dnodes1 = (IntervalSets.width(I1) * nodes1 .+ sum(extrema(I1))) / 2

    S1 = weights1[1] * func(dnodes1[1])
    for i1 in 2:nip1
        S1 += weights1[i1] * func(dnodes1[i1])
    end

    return S1 * IntervalSets.width(I1) / 2
end

"""
Integrate on rectangular region.
"""
function integrate(func, I1::ClosedInterval{<:Real}, I2::ClosedInterval{<:Real}, gl1, gl2)
    nip1, nodes1, weights1 = gl1.nip, gl1.nodes, gl1.weights
    nip2, nodes2, weights2 = gl2.nip, gl2.nodes, gl2.weights
    dnodes1 = (IntervalSets.width(I1) * nodes1 .+ sum(extrema(I1))) / 2
    dnodes2 = (IntervalSets.width(I2) * nodes2 .+ sum(extrema(I2))) / 2

    S2 = weights2[1] * func(dnodes1[1], dnodes2[1])
    for i2 in 2:nip2
        S2 += weights2[i2] * func(dnodes1[1], dnodes2[i2])
    end
    S1 = weights1[1] * S2
    for i1 in 2:nip1
        S2 = weights2[1] * func(dnodes1[i1], dnodes2[1])
        for i2 in 2:nip2
            S2 += weights2[i2] * func(dnodes1[i1], dnodes2[i2])
        end
        S1 += weights1[i1] * S2
    end

    return S1 * IntervalSets.width(I1) * IntervalSets.width(I2) / 4
end

"""
Integrate on rectangular solid
"""
function integrate(func, I1::ClosedInterval{<:Real}, I2::ClosedInterval{<:Real}, I3::ClosedInterval{<:Real}, gl1, gl2, gl3)
    nip1, nodes1, weights1 = gl1.nip, gl1.nodes, gl1.weights
    nip2, nodes2, weights2 = gl2.nip, gl2.nodes, gl2.weights
    nip3, nodes3, weights3 = gl3.nip, gl3.nodes, gl3.weights
    dnodes1 = (IntervalSets.width(I1) * nodes1 .+ sum(extrema(I1))) / 2
    dnodes2 = (IntervalSets.width(I2) * nodes2 .+ sum(extrema(I2))) / 2
    dnodes3 = (IntervalSets.width(I3) * nodes3 .+ sum(extrema(I3))) / 2

    S3 = weights3[1] * func(dnodes1[1],dnodes2[1],dnodes3[1])
    for i3 in 2:nip3
        S3 += weights3[i3] * func(dnodes1[1],dnodes2[1],dnodes3[i3])
    end
    S2 = weights2[1] * S3
    for i2 in 2:nip2
        S3 = weights3[1] * func(dnodes1[1],dnodes2[i2],dnodes3[1])
        for i3 in 2:nip3
            S3 += weights3[i3] * func(dnodes1[1],dnodes2[i2],dnodes3[i3])
        end
        S2 += weights2[i2] * S3
    end
    S1 = weights1[1] * S2
    for i1 in 2:nip1
        S3 = weights3[1] * func(dnodes1[i1],dnodes2[1],dnodes3[1])
        for i3 in 2:nip3
            S3 += weights3[i3] * func(dnodes1[i1],dnodes2[1],dnodes3[i3])
        end
        S2 = weights2[1] * S3
        for i2 in 2:nip2
            S3 = weights3[1] * func(dnodes1[i1],dnodes2[i2],dnodes3[1])
            for i3 in 2:nip3
                S3 += weights3[i3] * func(dnodes1[i1],dnodes2[i2],dnodes3[i3])
            end
            S2 += weights2[i2] * S3
        end
        S1 += weights1[i1] * S2
    end

    return S1 * IntervalSets.width(I1) * IntervalSets.width(I2)  * IntervalSets.width(I3) / 8
end


text:
using Documenter
using LightGraphsMatching
import LightGraphs; const lg = LightGraphs

makedocs(
    modules = [LightGraphsMatching],
    format = :html,
    sitename = "LightGraphsMatching",
	pages = Any[
		"Getting started"         => "index.md",
    ]
)

deploydocs(
    deps        = nothing,
    make        = nothing,
    repo        = "github.com/JuliaGraphs/LightGraphsMatching.jl.git",
    target      = "build",
    julia       = "0.6",
    osname      = "linux"
)


text:
using Distributed
using Images, FileIO
include("mpii.annotation.reader.jl")
include("../models.jl")

# TODO: prepare an image
# then stack them to create whole dataset
# ısValid size check atılabilir

# struct DataItem
#   id::Int
#  path::String
# size::Array{Float64}
# joints::Array
# end

# If w has dimensions (W1,W2,...,Cx,Cy)
# and x has dimensions (X1,X2,...,Cx,N), the result y will have dimensions (Y1,Y2,...,Cy,N)
# where Cx is the number of input channels, Cy is the number of output channels,
# N is the number of instances, and Wi,Xi,Yi are spatial dimensions with Yi determined by:

function make_even(x)
    return isodd(x) ? x + 1 : x
end

function preprocess_dataset(dataset; use_global_scaling = false)
    #max_h = findmax(map(data -> data.size[2], dataset))[1]
    #max_w = findmax(map(data -> data.size[3], dataset))[1]
    deconv_3 = Deconv(3, 3, 1, 1; padding = 1, stride = 2)
    raw_preprocessed = map(
        element -> preprocess_single_image_features(
            element[2];
            use_global_scaling = use_global_scaling,
            counter = element[1],
            mock_deepercut_head = deconv_3,
        ),
        enumerate(dataset),
    )
    return raw_preprocessed
end

# TODO: update global scaling for custom iterator
function preprocess_single_image_features(
    img_data;
    use_global_scaling = false,
    counter,
    mock_deepercut_head,
)

    if counter % 1024 == 1
        println("preprocessing $(counter)")
    end

    img_path = img_data.path
    loaded_image = load(img_path)

    if use_global_scaling
        jitter= rand(scale_jitter_interval[1]:0.01:scale_jitter_interval[2])
        jittered_scale = jitter * global_scale
        scale_h = jittered_scale
        scale_w = jittered_scale
        scales = (scale_h, scale_w)
        resized_image = imresize(loaded_image, ratio = jittered_scale)
    else
        scaled_max_w = read_image_w
        scaled_max_h = read_image_h
        scale_h = convert(Float32, scaled_max_h / img_data.size[3])
        scale_w = convert(Float32, scaled_max_w / img_data.size[2])
        scales = (scale_h, scale_w)
        resized_image = imresize(loaded_image, scaled_max_h, scaled_max_w)
    end

    arranged_img_data = arrange_img_data(resized_image)
    scaled_img_size = size(arranged_img_data)[1:2]

    # for using 3 x 3 deconvolution at the head
    #sm_size = Int.(ceil.(scaled_img_size ./ (preprocess_stride * 2))) .* 2
    sm_size_raw = scaled_img_size ./ (preprocess_stride * 2)

    mock_intermediate = Knet.atype()(randn(Float32, sm_size_raw[1] |> ceil |> Int, sm_size_raw[2] |> ceil |> Int , 1, 1))
    mock_result = mock_deepercut_head(mock_intermediate)
    sm_size = size(mock_result)[1:2]

    temp_holder = img_data.joints[:, 2:3]
    temp_holder = reshape(temp_holder, (:, 2))
    temp = zeros(size(img_data.joints))
    for i = 1:size(temp_holder)[1]
        j1 = temp_holder[i, 1] * scales[1]
        j2 = temp_holder[i, 2] * scales[2]
        temp[i, 2] = j1
        temp[i, 3] = j2
    end

    scaled_joints = temp[:, 2:3]

    joint_ids = img_data.joints[:, 1]

    (scmap, scmap_weights, locref_map, locref_mask) =
        compute_targets_weights(joint_ids, scaled_joints, sm_size)

    # TODO: check if this is working or not
    img_data = DataItem(img_data, scaled_img_size[1], scaled_img_size[2])

    return (img_data, arranged_img_data, scmap, scmap_weights, locref_map, locref_mask)
end

function arrange_img_data(img)
    b1 = img
    # ad-hoc solution for Mac-OS image
    macfix = convert(Array{FixedPointNumbers.Normed{UInt8,8},3}, channelview(b1))
    c1 = permutedims(macfix, (3, 2, 1))
    w, h, c = size(c1)
    d1 = convert(Array{Float32}, c1)
    f1 = reshape(d1[:, :, 1:3], (w, h, 3, 1))
    # H - W - C - N
    g1 = permutedims(f1, [2, 1, 3, 4])
    g1
end

# TODO: Check pose_dataset.py for pairwise implementation - currently skipped
function compute_targets_weights(joint_ids, coords, size)
    stride = preprocess_stride
    dist_thresh = pos_dist_thresh
    num_joints = global_num_joints
    half_stride = stride / 2
    scmap = zeros(size..., num_joints)

    locref_shape = (size..., num_joints * 2)
    locref_mask = zeros(locref_shape)
    locref_map = zeros(locref_shape)

    dist_thresh_sq = abs2(dist_thresh)

    width = size[2]
    height = size[1]

    for (k, j_id) in enumerate(joint_ids)
        joint_pt = coords[k, :]
        j_x = joint_pt[1]
        j_y = joint_pt[2]

        # don't loop over entire heatmap, but just relevant locations

        j_x_sm = round((j_x - half_stride) / stride) |> Int
        j_y_sm = round((j_y - half_stride) / stride) |> Int
        min_x = round(max(j_x_sm - dist_thresh - 1, 1)) |> Int
        max_x = round(min(j_x_sm + dist_thresh + 1, width)) |> Int
        min_y = round(max(j_y_sm - dist_thresh - 1, 1)) |> Int
        max_y = round(min(j_y_sm + dist_thresh + 1, height)) |> Int

        for j = min_y:max_y
            pt_y = j * stride + half_stride
            for i = min_x:max_x
                pt_x = i * stride + half_stride
                dx = j_x - pt_x
                dy = j_y - pt_y
                dist = abs2(dx) + abs2(dy)

                if dist <= dist_thresh_sq
                    locref_scale = 1.0 / global_locref_stdev
                    current_normalized_dist = dist * abs2(locref_scale)

                    prev_normalized_dist =
                        locref_map[j, i, j_id*2+1]^2 + locref_map[j, i, j_id*2+2]^2

                    update_scores =
                        (scmap[j, i, j_id+1] == 0) ||
                        prev_normalized_dist > current_normalized_dist

                    if update_scores
                        set_locref(
                            locref_map,
                            locref_mask,
                            locref_scale,
                            i,
                            j,
                            j_id,
                            dx,
                            dy,
                        )
                    end
                    scmap[j, i, j_id+1] = 1
                end
            end
        end
    end
    scmap_weights = compute_scmap_weights(size, joint_ids)
    return (scmap, scmap_weights, locref_map, locref_mask)
end

function set_locref(locref_map, locref_mask, locref_scale, i, j, j_id, dx, dy)
    locref_mask[j, i, j_id*2+1] = 1
    locref_mask[j, i, j_id*2+2] = 1
    locref_map[j, i, j_id*2+1] = dx * locref_scale
    locref_map[j, i, j_id*2+2] = dy * locref_scale
end

function compute_scmap_weights(scmap_size, joint_ids)
    # TODO: This can be extra feature => Check pose_dataset.py 402 from pose-tensorflow
    #     if cfg.weigh_only_present_joints:
    #             weights = np.zeros(scmap_shape)
    #             for person_joint_id in joint_id:
    #                 for j_id in person_joint_id:
    #                     weights[:, :, j_id] = 1.0
    #         else:
    weights = ones(scmap_size)
    return weights
end


text:
using InteractiveUtils

export showtypetree
"""
    parse_metadata(file)

Transform a metadata file into a dictionary.

File has to have one parameter per line. Returns a dictionary where parameter names
are stored as keys as strings and the parameter values are stored as values as strings.

# Examples
```julia-repl
shell> cat "test_Metadata.txt"
parameter_1=1
parameter_2=[1, 1]

julia> Jevo.parse_metadata("test_Metadata.txt")
Dict{String,String} with 2 entries:
  "parameter_1"         => "1"
  "parameter_2"         => "[1, 1]"
```
"""
function parse_metadata(file)
    lines = []
    open(file) do f
        lines = readlines(f)
    end
    parameter_array = split.(lines, "=") |> x->Array{String, 1}.(x)
    parameter_dict = Dict(parameter_array)
    return parameter_dict
end

"""
    function showtypetree(T, level=0)

Show the all subtypes in a tree. Taken from  https://en.wikibooks.org/wiki/Introducing_Julia/Types .

# Example
```julia-repl
julia> showtypetree(Real)
Real
	AbstractFloat
		BigFloat
		Float16
		Float32
		Float64
	AbstractIrrational
		Irrational
	Integer
		Bool
		Signed
			BigInt
			Int128
			Int16
			Int32
			Int64
			Int8
		Unsigned
			UInt128
			UInt16
			UInt32
			UInt64
			UInt8
	Rational
	StatsBase.TestStat
```
"""
function showtypetree(T, level=0)
    println("\t" ^ level, T)
    for t in subtypes(T)
        showtypetree(t, level+1)
    end
end


text:
### Day 17 - Problem 2
## Two Steps Forward
## Author: Thanasis Georgiou

workspace()
using Nettle

# Game state type, stores X/Y position and path followed to get there
immutable GameState
  x::Int
  y::Int
  path::Array{Char}
end

# Implement a simple queue type
type Queue
  arr::Array{GameState}
  index::Int
end
function Base.pop!(queue::Queue)::GameState
  state = queue.arr[queue.index]
  queue.index -= 1
  return state
end
function Base.append!(queue::Queue, state::GameState)::GameState
  queue.index += 1
  queue.arr[queue.index] = state
  return state
end
Base.getindex(queue::Queue, index::Int)::GameState = queue.arr[index]
Base.setindex!(queue::Queue, value::GameState, index::Int)::GameState = (queue.arr[index] = value)

# Input
input = "qtetzkpl"

# Characters that correspond to open doors
openChars = ['b', 'c', 'd', 'e', 'f']

# Store game states
queue = Queue(Array(GameState, 10000), 0)

# Add first position to queue to get started
append!(queue, GameState(1, 1, Array(Char, 0)))

# Create hasher
hasher = Hasher("md5")

# List of possible paths
paths = Array(String, 10000)
pathIndex = 1

# While the queue is not empty
while queue.index > 0
  # Grab current state
  state = pop!(queue)

  # If we are at the end append path to the list of possible paths
  if state.x == state.y == 4
    paths[pathIndex] = String(state.path)
    pathIndex += 1
    continue
  end

  # Calculate hash
  str = input * String(state.path)
  update!(hasher, str)
  hash = hexdigest!(hasher)[1:4]

  # For each open door add a new gamestate to the queue
  if in(hash[1], openChars) && state.y - 1 != 0 # Up
    newState = GameState(state.x, state.y - 1, Array(Char, length(state.path) + 1))
    newState.path[1:(end - 1)] = copy(state.path)
    newState.path[end] = 'U'
    append!(queue, newState)
  end
  if in(hash[2], openChars) && state.y + 1 != 5 # Down
    newState = GameState(state.x, state.y + 1, Array(Char, length(state.path) + 1))
    newState.path[1:(end - 1)] = copy(state.path)
    newState.path[end] = 'D'
    append!(queue, newState)
  end
  if in(hash[3], openChars) && state.x - 1 != 0 # Left
    newState = GameState(state.x - 1, state.y, Array(Char, length(state.path) + 1))
    newState.path[1:(end - 1)] = copy(state.path)
    newState.path[end] = 'L'
    append!(queue, newState)
  end
  if in(hash[4], openChars) && state.x + 1 != 5 # Right
    newState = GameState(state.x + 1, state.y, Array(Char, length(state.path) + 1))
    newState.path[1:(end - 1)] = copy(state.path)
    newState.path[end] = 'R'
    append!(queue, newState)
  end
end

# Find longest path
maxLen = maximum(map(str -> length(str), paths[1:(pathIndex - 1)]))
println("Max length: $maxLen")


text:
# = 2DPackGen =

# == Structures ==

# === Data/Problem Structures ===

@auto_hash_equals struct SLOPP{D, S, P}
	"Length of the large object."
	L :: S
	"Width of the large object."
	W :: S
	"Lengths of the small objects."
	l :: Vector{S}
	"Widths of the small objects."
	w :: Vector{S}
	"Lower bound on piece demand (minimum amount needed for a valid solution)."
	dlb :: Vector{D}
	"Upper bound on piece demand (maximum amount allowed for a valid solution)."
	dub :: Vector{D}
	"Profits of the small objects; contribution to objective function if packed."
	p :: Vector{P}
end

@auto_hash_equals struct MHLOPPW{D, S, P}
	"Lengths of the large objects."
	L :: Vector{S}
	"Widths of the large objects."
	W :: Vector{S}
	"Amount of copies available for each large object (cannot use more)."
	available :: Vector{D}
	"Lengths of the small objects."
	l :: Vector{S}
	"Widths of the small objects."
	w :: Vector{S}
	"Lower bound on piece demand (minimum amount needed for a valid solution)."
	dlb :: Vector{D}
	"Upper bound on piece demand (maximum amount allowed for a valid solution)."
	dub :: Vector{D}
	"Profit of the pieces (contribution to objective function if packed)."
	p :: Vector{P}
end

@auto_hash_equals struct ODPW{D, S, P}
	"Widths of the large objects."
	W :: Vector{S}
	"Amount of copies available for each large object (cannot use more)."
	available :: Vector{S}
	"Cost associated with the use of the large object, to be interpreted."
	cost :: Vector{S}
	"Lengths of the small objects."
	l :: Vector{S}
	"Widths of the small objects."
	w :: Vector{S}
	"The pieces to be packed (minimum amount needed for a valid solution)."
	d :: Vector{D}
end

# TODO: should this struct have the 'P' parameter?
@auto_hash_equals struct SSSCSP{D, S, P}
	"Length of the large object."
	L :: S
	"Width of the large object."
	W :: S
	"Lengths of the small objects."
	l :: Vector{S}
	"Widths of the small objects."
	w :: Vector{S}
	"The pieces to be packed (minimum amount needed for a valid solution)."
	d :: Vector{D}
end

# === Format/Instance Structures + `is_collection` ===

abstract type CPG_Format{D, S, P} end
struct CPG_SLOPP{D, S, P} <: CPG_Format{D, S, P} end
struct CPG_MHLOPPW{D, S, P} <: CPG_Format{D, S, P} end
struct CPG_ODPW{D, S, P} <: CPG_Format{D, S, P} end
struct CPG_SSSCSP{D, S, P} <: CPG_Format{D, S, P} end
is_collection(_ :: T) where {T <: CPG_Format} = true

# The Simple_CPG_SLOPP is not a real CPG format and does not return
# collections, is a simplified format that only has one instance inside
# and no header.
# TODO: in the future expand the simplified format to all supported
# CPG formats and create an abstract supertype for Simple_CPG formats.
struct Simple_CPG_SLOPP{D, S, P} end
is_collection(_ :: Val{:Simple_CPG_SLOPP}) = false
is_collection(_ :: T) where {T <: Simple_CPG_SLOPP} = false

const CPG_VALS = Union{
	Val{:CPG_SLOPP}, Val{:CPG_MHLOPPW}, Val{:CPG_ODPW}, Val{:CPG_SSSCSP}
}
is_collection(_ :: T) where {T <: CPG_VALS} = true

# === `parse_from_string` ===

# Replaces '(', ')', '*', and '/' by the escaped version.
_esc_for_regex(s) = replace(s, r"(\*|\(|\)|\/)" => s"\\\1")
_cpg_second_line(_::CPG_SLOPP) :: String = _esc_for_regex("***Instances for the Single Large Object Placement Problem (SLOPP)***")
_cpg_second_line(_::CPG_MHLOPPW) :: String = _esc_for_regex("***Instances for the Multiple Heterogeneous Large Object Placement Problem (MHLOPP/W)***")
_cpg_second_line(_::CPG_ODPW) :: String = _esc_for_regex("***Problem tests for the Open Dimension Problem (ODP/W)***")
_cpg_second_line(_::CPG_SSSCSP) :: String = _esc_for_regex("***Instances for the Single Stock Size Cutting Stock Problem (SSSCSP)***")

const CPG_DELIM = "^\\*+\$"
const CPG_DELIM_REGEX = Regex(CPG_DELIM)

function _expected_CPG_header(f) :: Regex
Regex("""
\\*\\*\\*2D Rectangular Problem\\*\\*\\*
$(_cpg_second_line(f))
Input parameter file:[^\\n]*
$CPG_DELIM
.*
$CPG_DELIM""", "mis")
#Regex("\\*\\*\\*2D Rectangular Problem\\*\\*\\*", "mi")
end

function _check_CPG_header(f, s :: AbstractString)
	expected_pattern = _expected_CPG_header(f)
	if match(expected_pattern, s) === nothing
		@warn "Could not match the header pattern for format:" *
			"\n$(f)\n; this is:\n" * string(expected_pattern)
	end

	return nothing
end

function _find_header_end(format :: T, lines) where {T}
	qt_delims_found :: Int = 0
	current_line :: Int = 1
	last_line :: Int = length(lines)

	while qt_delims_found < 2 && current_line <= last_line
		# strip is needed because \r\n newlines keep the \r after eachline
		if match(CPG_DELIM_REGEX, strip(lines[current_line])) !== nothing
			qt_delims_found += 1
		end
		current_line += 1
	end

	if qt_delims_found < 2
		throw(GenericParseError(format,
			"Parser expects to find two lines only with asterisks;" *
			" found $(qt_delims_found) line(s) like this." *
			" As the data should be after the second of these lines," *
			" the parser did not start gathering data."
		))
	end

	return current_line
end

_cpg_eltype(::Type{CPG_SLOPP{D,S,P}}) where {D,S,P} = SLOPP{D,S,P}
_cpg_eltype(::Type{CPG_MHLOPPW{D,S,P}}) where {D,S,P} = MHLOPPW{D,S,P}
_cpg_eltype(::Type{CPG_ODPW{D,S,P}}) where {D,S,P} = ODPW{D,S,P}
_cpg_eltype(::Type{CPG_SSSCSP{D,S,P}}) where {D,S,P} = SSSCSP{D,S,P}

function _get_numbers_from_line(
	format, lines, line_number, purpose, types; check_size = false
)
	if check_size
		last_line = length(lines)
		line_number > last_line && throw(GenericParseError(format,
			"Expected non-empty line number $line_number to have '$purpose'" *
			" but the file/string finished before this line."
		))
	end

	line = lines[line_number]
	qt_numbers = length(types)
	tokens = split(line)
	qt_tokens = length(tokens)

	qt_tokens != qt_numbers && throw(GenericParseError(format,
		"Expected $qt_numbers token(s) ($purpose) from $(repr(line))" *
		" (non-empty line number $line_number) got $qt_tokens" *
		" token(s) instead."
	))

	numbers = tryparse.(types, tuple(tokens...))

	any(isequal(nothing), numbers) && throw(GenericParseError(format,
		"Expected '$(join(string.(types), ' '))' ($purpose) from $(repr(line))" *
		" (non-empty line number $line_number) but could not parse some" *
		" of the tokens to their respective types."
	))

	return numbers
end

# For both SLOPP and SSSCSP (both have a Single Large Object)
const CPG_SLO{D, S, P} = Union{CPG_SLOPP{D, S, P}, CPG_SSSCSP{D, S, P}}

# As both SLOPP and SSSCSP have the same structure of Large Object they
# can be the same method.
function _read_large_objs(
	format :: CPG_SLO{D, S, P}, lines, next :: Int, last :: Int
) :: Tuple{Int, Tuple{S, S}} where {D, S, P}
	lo_data = _get_numbers_from_line(
		format, lines, next, "L and W", (S, S); check_size = true
	) :: Tuple{S, S}

	return (next + 1, lo_data)
end

# Both ODPW and MHLOPPW have Multiple Large Objects, so we use this
# union type for the part of the code that shares that logic.
const CPG_MLO{D, S, P} = Union{CPG_ODPW{D, S, P}, CPG_MHLOPPW{D, S, P}}

function _read_large_objs(
	format :: CPG_MLO{D, S, P}, lines, next :: Int, last :: Int
) :: Tuple{Int, <: Any} where {D, S, P}
	N = (_get_numbers_from_line(
		format, lines, next, "the number of large objects", (Int,);
		check_size = true
	) :: Tuple{Int})[1] :: Int

	next += 1

	last - next + 1 < N && throw(GenericParseError(format,
		"Started parsing the large objects of an instance (at non-empty line" *
		" number $(next)) but there are not enough lines left for all" *
		" the large objects (needed $(N) there are $(last - next + 1))."
	))

	return _read_large_objs_attrs(format, lines, next, N)
end

function _read_large_objs_attrs(
	format :: CPG_ODPW{D, S, P}, lines, next :: Int, N :: Int
) :: Tuple{Int, <: Any} where {D, S, P}
	W, available, cost = (Vector{S}(undef, N), Vector{D}(undef, N),
		Vector{P}(undef, N))
	lo_vectors = (W, available, cost)

	for lo_idx = 1:N
		# No check-size needed because we checked before.
		lo_line_data = _get_numbers_from_line(
			format, lines, next, "W, available, and cost", (S, D, P)
		) :: Tuple{S, D, P}
		setindex!.(lo_vectors, lo_line_data, lo_idx)

		next += 1
	end

	return (next, lo_vectors)
end

function _read_large_objs_attrs(
	format :: CPG_MHLOPPW{D, S, P}, lines, next :: Int, N :: Int
) :: Tuple{Int, <: Any} where {D, S, P}
	L, W, available = (Vector{S}(undef, N), Vector{S}(undef, N),
		Vector{D}(undef, N))
	lo_vectors = (L, W, available)

	for lo_idx = 1:N
		# No check-size needed because we checked before.
		lo_line_data = _get_numbers_from_line(
			format, lines, next, "L, W, and available", (S, S, D)
		) :: Tuple{S, S, D}
		setindex!.(lo_vectors, lo_line_data, lo_idx)

		next += 1
	end

	return (next, lo_vectors)
end

# Both SLOPP and MHLOPPW have the same kind of Complex Single Object
# (i.e., length, width, demand lower bound, demand upper bound,
# value/profit).
const CPG_CSO{D, S, P} = Union{CPG_SLOPP{D, S, P}, CPG_MHLOPPW{D, S, P}}

# Used for both SLOPP and MHLOPPW, as both have the exact same attributes
# on an item.
function _read_small_objs_attrs(
	format :: CPG_CSO{D, S, P}, lines, next :: Int, N :: Int
) :: Tuple{Int, <: Any} where {D, S, P}
	l, w, dlb, dub, p = (Vector{S}(undef, N), Vector{S}(undef, N),
		Vector{D}(undef, N), Vector{D}(undef, N), Vector{P}(undef, N))
	so_vectors = (l, w, dlb, dub, p)

	for so_idx = 1:N
		so_line_data = _get_numbers_from_line(
			format, lines, next, "length, width, demand LB, demand UB, and value",
			(S, S, D, D, P) # No check-size needed because we checked before.
		) :: Tuple{S, S, D, D, P}
		setindex!.(so_vectors, so_line_data, so_idx)

		next += 1
	end

	return (next, (l, w, dlb, dub, p))
end

# Both ODPW and SSSCSP have a Simple Small Objects (just length, width,
# and demand). So they can share the extraction of these attributes.
const CPG_SSO{D, S, P} = Union{CPG_ODPW{D, S, P}, CPG_SSSCSP{D, S, P}}

function _read_small_objs_attrs(
	format :: CPG_SSO{D, S, P}, lines, next :: Int, N :: Int
) :: Tuple{Int, <: Any} where {D, S, P}
	l, w, d = (Vector{S}(undef, N), Vector{S}(undef, N),
		Vector{D}(undef, N))
	so_vectors = (l, w, d)

	for so_idx = 1:N
		so_line_data = _get_numbers_from_line(
			format, lines, next, "length, width, demand",
			(S, S, D) # No check-size needed because we checked before.
		) :: Tuple{S, S, D}
		setindex!.(so_vectors, so_line_data, so_idx)

		next += 1
	end

	return (next, (l, w, d))
end

function _read_small_objs(
	format :: CPG_Format{D, S, P}, lines, next :: Int, last :: Int
) :: Tuple{Int, <: Any} where {D, S, P}
	N = (_get_numbers_from_line(
		format, lines, next, "the number of small objects", (Int,);
		check_size = true
	) :: Tuple{Int})[1] :: Int

	next += 1

	last - next + 1 < N && throw(GenericParseError(format,
		"Started parsing the small objects of an instance (at non-empty line" *
		" number $(next)) but there are not enough lines left for all" *
		" the small objects (needed $(N) there are $(last - next + 1))."
	))

	return _read_small_objs_attrs(format, lines, next, N)
end

function _read_instance(
	format :: T, lines, next :: Int, last :: Int
) where {T <: CPG_Format}
	next, lo = _read_large_objs(format, lines, next, last)
	next, so = _read_small_objs(format, lines, next, last)
	return next, _cpg_eltype(T)(lo..., so...)
end

# The format is passed to build error objects if necessary, otherwise it
# is not used.
function _read_number_of_instances(
	@nospecialize(format :: CPG_Format), lines, next :: Int
) :: Int # returns number of instances
	qt_instances = (_get_numbers_from_line(
		format, lines, next, "the number of problem instances", (Int,);
		check_size = true
	) :: Tuple{Int})[1] :: Int

	return qt_instances
end

function read_from_string(
	format :: CPG_Format{D, S, P}, s :: AbstractString
) where {D, S, P}
	_check_CPG_header(format, s)
	lines = split(s, isequal('\n'); keepempty = false)
	last_line_number = length(lines)
	line_number_after_header = _find_header_end(format, lines)

	qt_instances = _read_number_of_instances(
		format, lines, line_number_after_header
	)
	curr_line_number = line_number_after_header + 1

  instances = Vector{_cpg_eltype(typeof(format))}(undef, qt_instances)

	for curr_inst_number = 1:qt_instances
		curr_line_number, instances[curr_inst_number] =
			_read_instance(format, lines, curr_line_number, last_line_number) ::
				Tuple{Int, _cpg_eltype(typeof(format))}
	end

	if curr_line_number <= last_line_number
		@warn "The file/string indicated $(qt_instances) instance(s), after" *
			" consuming those some lines remained. Ignoring any further lines." *
			" The last parsed line was \"$(lines[curr_line_number - 1])\"" *
			" (line $(curr_line_number - 1) considering only non-empty lines)."
	end

	return instances
end

function read_from_string(
	format :: Simple_CPG_SLOPP{D, S, P}, s :: AbstractString
) where {D, S, P}
	lines = split(s, isequal('\n'); keepempty = false)
	last_line_number = length(lines)

	curr_line_number, instance =
		_read_instance(CPG_SLOPP{D, S, P}(), lines, 1, last_line_number) ::
			Tuple{Int, _cpg_eltype(CPG_SLOPP{D, S, P})}

	if curr_line_number <= last_line_number
		@warn "After consuming all lines of the instance" *
			" some lines remained. Ignoring any further lines." *
			" The last parsed line was \"$(lines[curr_line_number - 1])\"" *
			" (line $(curr_line_number - 1) considering only non-empty lines)."
	end

	return instance
end

function read_from_string(
	_ :: Val{:Simple_CPG_SLOPP}, s :: AbstractString
)
	return read_from_string(Simple_CPG_SLOPP{Int, Int, Int}(), s)
end

function read_from_string(
	_ :: Val{:CPG_SLOPP}, s :: AbstractString
)
	return read_from_string(CPG_SLOPP{Int, Int, Int}(), s)
end

function read_from_string(
	_ :: Val{:CPG_ODPW}, s :: AbstractString
)
	return read_from_string(CPG_ODPW{Int, Int, Int}(), s)
end

function read_from_string(
	_ :: Val{:CPG_MHLOPPW}, s :: AbstractString
)
	return read_from_string(CPG_MHLOPPW{Int, Int, Int}(), s)
end

function read_from_string(
	_ :: Val{:CPG_SSSCSP}, s :: AbstractString
)
	return read_from_string(CPG_SSSCSP{Int, Int, Int}(), s)
end

# === `write_to_file` implementations ===

function write_to_file(
	format :: Val{:Simple_CPG_SLOPP},
	instance :: SLOPP{D, S, P},
	io :: IO
) where {D, S, P}
	return write_to_file(Simple_CPG_SLOPP{Int, Int, Int}(), instance, io)
end

@timeit TIMER function write_to_file(
	format :: Simple_CPG_SLOPP{D, S, P},
	instance :: SLOPP{D, S, P},
	io :: IO
) where {D, S, P}
	@unpack L, W, l, w, dlb, dub, p = instance
	write(io, "$L $W\n")
	write(io, "$(length(p))\n")
	for (pl, pw, pdlb, pdub, pp) in zip(l, w, dlb, dub, p)
		write(io, "$pl $pw $pdlb $pdub $pp\n")
	end
	flush(io)
	return io
end

function write_to_file(
	format :: Val{:CPG_MHLOPPW}, instance, io :: IO
) where {D, S, P}
	return write_to_file(CPG_MHLOPPW{Int, Int, Int}(), instance, io)
end

const MHLOPPW_HEADER = """
***2D Rectangular Problem***
***Instances for the Multiple Heterogeneous Large Object Placement Problem (MHLOPP/W)***
Input parameter file: NONE
***************************************************************************************************************
Total number of instances
Number of different large objects (j)
LargeObject[j].Length	LargeObject[j].Width	LargeObject[j].Available
Number of different item types (i)
Item[i].Length	Item[i].Width	Item[i].LowerBoundDemand	Item[i].UpperBoundDemand	Item[i].Value
***************************************************************************************************************"""

@timeit TIMER function write_to_file(
	format :: CPG_MHLOPPW{D, S, P},
	instance :: MHLOPPW{D, S, P},
	io :: IO
) where {D, S, P}
	# Ideally we should wrap on a StaticArray because there is no reason for this
	# allocation, but this is not performance-critical code.
	write_to_file(CPG_MHLOPPW{D, S, P}(), [instance], io)
	return io
end

@timeit TIMER function write_to_file(
	format :: CPG_MHLOPPW{D, S, P},
	instances :: AbstractVector{MHLOPPW{D, S, P}},
	io :: IO
) where {D, S, P}
	println(io, MHLOPPW_HEADER)
	write(io, "$(length(instances))\n")
	for instance in instances
		@unpack L, W, available, l, w, dlb, dub, p = instance
		qt_plates = only(unique(length.((L, W, available))))
		write(io, "$qt_plates\n")
		for (PL, PW, PD) in zip(L, W, available)
			write(io, "$PL $PW $PD\n")
		end
		qt_pieces = only(unique(length.((l, w, dlb, dub, p))))
		write(io, "$qt_pieces\n")
		for (pl, pw, pdlb, pdub, pp) in zip(l, w, dlb, dub, p)
			write(io, "$pl $pw $pdlb $pdub $pp\n")
		end
	end
	flush(io)
	return io
end

# CPG_SSSCSP write_to_file

function write_to_file(
	format :: Val{:CPG_SSSCSP}, instance, io :: IO
) where {D, S, P}
	return write_to_file(CPG_SSSCSP{Int, Int, Int}(), instance, io)
end

const SSSCSP_HEADER = """
***2D Rectangular Problem***
***Instances for the Single Stock Size Cutting Stock Problem (SSSCSP)***
Input parameter file: NONE
****************************************************************************************************
Total number of instances
LargeObject.Length	LargeObject.Width
Number of different item types (i)
Item[i].Length	Item[i].Width	Item[i].Demand
*****************************************************************************************************"""

@timeit TIMER function write_to_file(
	format :: CPG_SSSCSP{D, S, P},
	instance :: SSSCSP{D, S, P},
	io :: IO
) where {D, S, P}
	# Ideally we should wrap on a StaticArray because there is no reason for this
	# allocation, but this is not performance-critical code.
	write_to_file(CPG_SSSCSP{D, S, P}(), [instance], io)
	return io
end

@timeit TIMER function write_to_file(
	format :: CPG_SSSCSP{D, S, P},
	instances :: AbstractVector{SSSCSP{D, S, P}},
	io :: IO
) where {D, S, P}
	write(io, SSSCSP_HEADER)
	write(io, '\n')
	write(io, "$(length(instances))\n")
	for instance in instances
		@unpack L, W, l, w, d = instance
		write(io, "$(L)\t$(W)\n")
		write(io, "$(length(d))\n")
		for (li, wi, di) in zip(l, w, d)
			write(io, "$(li)\t$(wi)\t$(di)\n")
		end
	end
	flush(io)
	return io
end

# === `GuillotineModels.solution_value` implementations

import ..CutPattern
function solution_value(
	:: Val{:G2KP}, i :: SLOPP{D, S, P}, cp :: CutPattern{D, S}
) where {D, S, P}
	@assert iszero(sum(i.dlb))
	g2kp_instance = G2KP{D, S, P}(i.L, i.W, i.l, i.w, i.dub, i.p)
	return solution_value(Val(:G2KP), g2kp_instance, cp)
end

# G2OPP does not have a solution value, because it is not an optimization
# problem but instead a decision problem. Ideally, a formulation that solves
# it will have no objective function set (or better, all coefficients of the
# objective function will bet set to the default, that is zero) and therefore
# we always return zero to match what the solver will return.
function solution_value(
	:: Val{:G2OPP}, instance, cp :: CutPattern{D, S}
) where {D, S}
	return 0
end

# The instance is taken to adhere to the signature but it is unneeded
# to compute the solution value.
function solution_value(
	:: Val{:G2CSP}, instance, bins :: Vector{CutPattern{D, S}}
) where {D, S}
	return length(bins)
end

function solution_value(
	:: Val{:G2MKP}, i :: MHLOPPW{D, S, P}, cps :: Vector{CutPattern{D, S}}
) where {D, S, P}
	@assert iszero(sum(i.dlb))
	g2kp_instance = G2KP{D, S, P}(only(i.L), only(i.W), i.l, i.w, i.dub, i.p)
	value = zero(P)
	for cp in cps
		value += solution_value(Val(:G2KP), g2kp_instance :: G2KP{D, S, P}, cp)
	end

	return value
end


text:
export
    GaussianSuffStats,
    DiagGaussianSuffStats,
    suffstats

immutable GaussianSuffStats <: SuffStats
    ss::Tuple{Vector{Float}, Symmetric{Float, Matrix{Float}}}
    function GaussianSuffStats(s1::Vector{Float}, s2::Matrix{Float})
        @assert length(s1)==size(s2)[1]==size(s2)[2] "Inconsistent dimensions"
        new((s1, Symmetric(s2)))
    end
end

immutable DiagGaussianSuffStats <: SuffStats
    ss::Tuple{Vector{Float}, Vector{Float}}
    function DiagGaussianSuffStats(s1::Vector{Float}, s2::Vector{Float})
        @assert length(s1)==length(s2) "Inconsistent dimensions"
        new((s1, s2))
    end
end

const FGaussSS = GaussianSuffStats
const DGaussSS = DiagGaussianSuffStats
const GaussSS  = Union{FGaussSS, DGaussSS}

suffstats(::Type{GaussNP}, x::Vector{Float})=GaussianSuffStats(x, 0.5x*x')
suffstats(::Type{GaussMP}, x::Vector{Float})=GaussianSuffStats(x, 0.5x*x')
suffstats(::Type{DGaussNP},x::Vector{Float})=DiagGaussianSuffStats(x, 0.5x.^2)
suffstats(::Type{DGaussMP},x::Vector{Float})=DiagGaussianSuffStats(x, 0.5x.^2)

Base.getindex(s::GaussSS, ind::Int) = s.ss[ind]

Base.vec(s::GaussSS)  = vcat(s[1], vec(s[2]))
Base.norm(s::GaussSS) = norm(vec(s))

# The operation that matters the most is the sum and the product for a weighted
# sum (monte carlo estimator)

+(sa::FGaussSS, sb::FGaussSS) =
        GaussianSuffStats(sa[1]+sb[1], sa[2]+sb[2])
+(sa::DGaussSS, sb::DGaussSS) =
        DiagGaussianSuffStats(sa[1]+sb[1], sa[2]+sb[2])

*(a::Real, s::FGaussSS) = GaussianSuffStats(a*s[1], a*s[2].data)
*(a::Real, s::DGaussSS) = DiagGaussianSuffStats(a*s[1], a*s[2])

*(s::GaussSS, a::Real) = a*s
/(s::GaussSS, a::Real) = (1.0/a)*s

# Minus may be useful for

-(sa::FGaussSS, sb::FGaussSS) =
        GaussianSuffStats(sa[1]-sb[1], sa[2]-sb[2])
-(sa::DGaussSS, sb::DGaussSS) =
        DiagGaussianSuffStats(sa[1]-sb[1], sa[2]-sb[2])


text:
using Polynomials
using TransportBasedInference: derivative, vander

@testset "Test physical Hermite polynomials"   begin

x = randn()

P0 = PhyPolyHermite(0)
@test P0(x) == 1.0
@test derivative(P0,0).coeffs == (1.0,)
@test derivative(P0,0).coeffs == (1.0,)
@test derivative(P0,1).coeffs == ()
@test derivative(P0,2).coeffs  == ()

@test (derivative(P0,1))(x) == 0.0
@test (derivative(P0,2))(x) == 0.0

P0 = PhyPolyHermite(0; scaled = true)
@test P0(x) == 1/sqrt(1.0)
@test Cphy(0) == sqrt(1.0)
@test derivative(P0,0).coeffs == (1/sqrt(1.0),)
@test derivative(P0,0).coeffs == (1/sqrt(1.0),)
@test derivative(P0,1).coeffs == ()
@test derivative(P0,2).coeffs  == ()

P1 = PhyPolyHermite(1)
@test P1(x) == 2*x
@test derivative(P1, 0).coeffs == (0.0, 2.0)
@test derivative(P1, 1).coeffs == (2.0,)
@test derivative(P1, 2).coeffs == ()

P1 = PhyPolyHermite(1; scaled = true)
@test abs(P1(x) - 2*x/sqrt(2*factorial(1)))<1e-10
@test derivative(P1, 1).coeffs == (2/sqrt(2*factorial(1)),)
@test derivative(P1, 2).coeffs == ()

# Verify recurrence relation
# Hn+1(x) = 2*x*Hn(x) - Hn′(x)
# Hn′(x) = 2*n*Hn-1(x)

nodes, weights = gausshermite( 100000 )

for i=1:11
    Pmm1 = PhyPolyHermite(i-1)
    Pm = PhyPolyHermite(i)
    Pmp1 = PhyPolyHermite(i+1)
    z = 0.5

    @test abs(Pmp1(z) - (2*z*Pm(z) - (derivative(Pm,1))(z)))<1e-7

    @test abs(derivative(Pm, 0)(z) - Pm(z))<1e-7
    @test abs(derivative(Pm, 1)(z) - 2*i*Pmm1(z))<1e-7

    @test abs(derivative(Pmp1, 2)(z) - 4*(i+1)*(i)*Pmm1(z))<1e-7

    # Verify normalizing constant:
    @test abs(Cphy(i) - sqrt(2^i*factorial(i)))<1e-7
    @test abs(Cphy(Pm)- sqrt(2^i*factorial(i)))<1e-7

    if i<4
        # Verify integrals
        @test abs(dot(weights, Pm.P.(nodes).*Pm.P.(nodes))-sqrt(π)*2^i*factorial(i))<1e-7
        @test abs(dot(weights, Pm.P.(nodes).*Pmp1.P.(nodes)))<1e-7
        @test abs(dot(weights, Pm.P.(nodes).*Pmm1.P.(nodes)))<1e-7
        @test abs(dot(weights, Pmp1.P.(nodes).*Pmm1.P.(nodes)))<1e-7
    end
end

x = randn()

@test norm([PhyPolyHermite(10).P.coeffs...] - [-30240.0, 0.0, 302400, 0.0, -403200.0, 0.0, 161280, 0.0, -23040, 0.0, 1024])<1e-7
@test norm([derivative(PhyPolyHermite(10),1).coeffs...] - [Polynomials.derivative(PhyPolyHermite(10).P).coeffs...])<1e-7
@test norm([derivative(PhyPolyHermite(10),2).coeffs...] - [Polynomials.derivative(Polynomials.derivative(PhyPolyHermite(10).P)).coeffs...])<1e-7

P10 = PhyPolyHermite(10)

@test abs(P10(1.5) -  dot([-30240.0, 0.0, 302400, 0.0, -403200.0, 0.0, 161280, 0.0, -23040, 0.0, 1024], map(i->1.5^i,0:10)))<1e-10

# Compute inner product for normalized Physicist Hermite polynomials

for i=1:6
    Pmm1 = PhyPolyHermite(i-1; scaled = true)
    Pm = PhyPolyHermite(i; scaled = true)
    Pmp1 = PhyPolyHermite(i+1; scaled = true)

    @test abs(dot(weights, Pm.P.(nodes).*Pm.P.(nodes))-sqrt(π))<1e-8
    @test abs(dot(weights, Pm.P.(nodes).*Pmp1.P.(nodes)))<1e-8
    @test abs(dot(weights, Pm.P.(nodes).*Pmm1.P.(nodes)))<1e-8
    @test abs(dot(weights, Pmp1.P.(nodes).*Pmm1.P.(nodes)))<1e-8

    # Check derivatives
    z = 0.25
    @test abs(derivative(Pm, 0)(z) - Pm(z))<1e-7
    @test abs(derivative(Pm, 1)(z) - 2*i*(1/Cphy(i))*FamilyPhyPolyHermite[i](z))<1e-7

    @test abs(derivative(Pmp1, 2)(z) - 4*(i+1)*(i)*(1/Cphy(i+1))*FamilyPhyPolyHermite[i](z))<1e-7
end

P12 = PhyPolyHermite(12;  scaled=true)
@test norm([derivative(P12,1).coeffs...] - [Polynomials.derivative(P12.P).coeffs...])<1e-10
@test norm([derivative(P12,2).coeffs...] - [Polynomials.derivative(Polynomials.derivative(P12.P)).coeffs...])<1e-10

end

@testset "Vandermonde matrix test for Physicist Hermite polynomials" begin
    # k = 0: check simple polynomial evaluation
    N = 20
    m = 10
    k = 0
    x = 0.2*randn(N)

    V = vander(PhyPolyHermite(m), k, x)

    @test size(V)==(N, m+1)

    for i=0:m
        @test norm(V[:,i+1] - (FamilyPhyPolyHermite[i+1]).(x))<1e-8
    end

    # k = 0: check simple polynomial evaluation with scaled = true
    N = 20
    m = 10
    k = 0
    x = 0.2*randn(N)

    V = vander(PhyPolyHermite(m;scaled = true), k, x)

    @test size(V)==(N, m+1)

    for i=0:m
        factor = 2^k*exp(loggamma(i+1) - loggamma(i+1-k))

        @test norm(V[:,i+1] - (FamilyScaledPhyPolyHermite[i+1]).(x)*sqrt(factor))<1e-8
    end

    # k = 1: check first derivative
    N = 20
    m = 10
    k = 1
    x = 0.2*randn(N)

    V = vander(PhyPolyHermite(m), k, x)

    @test size(V)==(N, m+1)

    for i=1:m
        @test norm(V[:,i+1] - (FamilyPhyPolyHermite[i]).(x)*2*i)<1e-8
    end

    # k = 1: check first derivative scaled = true
    N = 20
    m = 10
    k = 1
    x = 0.2*randn(N)

    V = vander(PhyPolyHermite(m;scaled = true), k, x)

    @test size(V)==(N, m+1)

    for i=1:m
        factor = 2^k*exp(loggamma(i+1) - loggamma(i+1-k))

        @test norm(V[:,i+1] - (FamilyPhyPolyHermite[i]).(x)*sqrt(factor)*1/Cphy(i))<1e-8
    end

    # k = 2: check second derivative
    N = 20
    m = 10
    k = 2
    x = 0.2*randn(N)

    V = vander(PhyPolyHermite(m; scaled = false), k, x)

    @test size(V)==(N, m+1)

    for i=2:m
        @test norm(V[:,i+1] - (FamilyPhyPolyHermite[i-1]).(x)*2*i*2*(i-1))<1e-8
        @test norm(V[:,i+1] - (FamilyPhyPolyHermite[i-1]).(x)*2^k*factorial(i)/factorial(i-k))<1e-8

    end

    # k = 2: check second derivative scaled = true
    N = 20
    m = 10
    k = 2
    x = 0.2*randn(N)

    V = vander(PhyPolyHermite(m;scaled = true), k, x)

    @test size(V)==(N, m+1)

    for i=2:m
        factor = 2^k*exp(loggamma(i+1) - loggamma(i+1-k))

        @test norm(V[:,i+1] - (FamilyPhyPolyHermite[i-1]).(x)*sqrt(2*2*i*(i-1))*1/Cphy(i))<1e-8
        @test norm(V[:,i+1] - (FamilyPhyPolyHermite[i-1]).(x)*sqrt(2^k*factorial(i)/factorial(i-k))*1/Cphy(i))<1e-8

    end

    # # k = 3: check third derivative
    # N = 20
    # m = 10
    # k = 3
    # x = 0.2*randn(N)
    #
    # V = vander(PhyPolyHermite(m; scaled = false), k, x)
    #
    # @test size(V)==(N, m+1)
    #
    # for i=3:m
    #     @test norm(V[:,i+1] - (FamilyPhyPolyHermite[i-2]).(x)*2*i*2*(i-1)*2*(i-2))<1e-6
    #     @test norm(V[:,i+1] - (FamilyPhyPolyHermite[i-2]).(x)*2^k*factorial(i)/factorial(i-k))<1e-6
    #
    # end
    #
    # # k = 3: check third derivative scaled = true
    # N = 20
    # m = 10
    # k = 3
    # x = 0.2*randn(N)
    #
    # V = vander(PhyPolyHermite(m;scaled = true), k, x)
    #
    # @test size(V)==(N, m+1)
    #
    # for i=3:m
    #     factor = 2^k*exp(loggamma(i+1) - loggamma(i+1-k))
    #
    #     @test norm(V[:,i+1] - (FamilyPhyPolyHermite[i-2]).(x)*sqrt(2*2*2*i*(i-1)*(i-2))*1/Cphy(i))<1e-8
    #     @test norm(V[:,i+1] - (FamilyPhyPolyHermite[i-2]).(x)*sqrt(2^k*factorial(i)/factorial(i-k))*1/Cphy(i))<1e-8
    #
    # end

end


text:
struct HMAC_CTX{CTX<:SHA_CTX}
    context::CTX
    outer::Vector{UInt8}

    function HMAC_CTX(ctx::CTX, key::Vector{UInt8}, blocksize::Integer=blocklen(CTX)) where CTX
        if length(key) > blocksize
            _ctx = CTX()
            update!(_ctx, key)
            key = digest!(_ctx)
        end

        pad = blocksize - length(key)

        if pad > 0
            key = [key; fill(0x00, pad)]
        end

        update!(ctx, key .⊻ 0x36)
        new{CTX}(ctx, key .⊻ 0x5c)
    end
end

function update!(ctx::HMAC_CTX, data, datalen=length(data))
    update!(ctx.context, data, datalen)
end

function digest!(ctx::HMAC_CTX{CTX}) where CTX
    digest = digest!(ctx.context)
    _ctx = CTX()
    update!(_ctx, ctx.outer)
    update!(_ctx, digest)
    digest!(_ctx)
end

max_stars_repo_name: djsegal/julia-fork

max_issues_repo_name: djsegal/julia-fork

max_forks_repo_name: djsegal/julia-fork


text:
# Export DynamicLinks API
export DynamicLinks,
       getindex, endof, length, start, next, done, eltype,
       handle, header

# Export Dynamic Link API
export DynamicLink,
       DynamicLinks, handle, path

# Export RPath API
export RPath,
       handle, rpaths, canonical_rpaths, find_library

"""
    DynamicLinks

This type encapsulates the list of dynamic links within an object, holding a
collection of `DynamicLink` objects.  The list of available API operations is
given below, with methods that subclasses must implement marked in emphasis:

### Creation
  - *DynamicLinks()*

### Iteration
  - *getindex()*
  - *endof()*
  - length()
  - start()
  - next()
  - done()
  - eltype()

### Misc.
  - *handle()*
"""

abstract type DynamicLinks{H <: ObjectHandle} end

@mustimplement endof(dls::DynamicLinks)
start(dls::DynamicLinks) = 1
done(dls::DynamicLinks, idx) = idx > length(dls)
next(dls::DynamicLinks, idx) = (dls[idx], idx+1)
length(dls::DynamicLinks) = endof(dls)
eltype(::Type{D}) where {D <: DynamicLinks} = DynamicLink
@mustimplement getindex(dls::DynamicLinks, idx)

"""
    DynamicLink

This type encapsulates the linkage of one object file to another.  The list of
available API operations is given below, with methods that subclasses must
implement marked in emphasis:

### Creation:
  - *DynamicLink()*

### Accessors:
  - *DynamicLinks()*
  - *handle()*
  - *path()*
"""
abstract type DynamicLink{H <: ObjectHandle} end

@mustimplement path(dl::DynamicLink)

"""
    RPath

This type encapsulates the search path used by an object file when looking for
a shared library.  This class enables not only looking at the path, but
querying the path for matches for given library names.  The list of available
API operations is given below, with methods that subclasses must implement
marked in emphasis:

### Creation:
  - *RPath()*

### Utility
  - *handle()*

### RPath operations
  - *rpaths()*
  - canonical_rpaths()
  - find_library()
"""
abstract type RPath{H <: ObjectHandle} end

"""
    RPath(oh::ObjectHandle)

Construct an `RPath` object from the given `ObjectHandle`.
"""
@mustimplement RPath(oh::ObjectHandle)

"""
    handle(rpath::RPath)

Return the handle that this `RPath` object refers to.
"""
@mustimplement handle(rpath::RPath)

"""
    rpaths(rpath::RPath)

Return the list of paths that will be searched for shared libraries.
"""
@mustimplement rpaths(rpath::RPath)

endof(rpath::RPath) = endof(rpaths(rpath))
start(rpath::RPath) = 1
done(rpath::RPath, idx) = idx > length(rpath)
next(rpath::RPath, idx) = (rpath[idx], idx+1)
length(rpath::RPath) = endof(rpath)
eltype(::Type{D}) where {D <: RPath} = String
getindex(rpath::RPath, idx) = rpaths(rpath)[idx]

"""
    canonical_rpaths(rpath::RPath)

Return a canonicalized list of paths that will be searched.
"""
function canonical_rpaths(rpath::RPath)
    origin = dirname(path(handle(rpath)))
    paths = rpaths(rpath)
    for idx in 1:length(paths)
        # Substitute the path of the containing handle for `$ORIGIN` and
        # `@loader_path`.  Do the same for `@executable_path` even though
        # that's technically incorrect, because we don't have a good way to
        # track the web of dependencies right now.
        paths[idx] = replace(paths[idx], "\$ORIGIN", origin)
        paths[idx] = replace(paths[idx], "@loader_path", origin)
        paths[idx] = replace(paths[idx], "@executable_path", origin)
        paths[idx] = abspath(paths[idx])
    end
    return paths
end

"""
    find_library(rpath::RPath, soname::String)

Return the full path to a library, searching the given `RPath`, and then the
default library search paths.  This method takes the given `soname` and joins
it to the end of every path within the given `RPath`, returning the resultant
path if it exists, returning back the original `soname` if it doesn't.
"""
function find_library(rpath::RPath, soname::AbstractString)
    for path in canonical_rpaths(rpath)
        libpath = joinpath(path, soname)
        if isfile(libpath)
            return libpath
        end
    end
    return soname
end

### Printing
function show(io::IO, dl::DynamicLink{H}) where {H <: ObjectHandle}
    print(io, "$(format_string(H)) DynamicLink \"$(path(dl))\"")
end

show(io::IO, dls::DynamicLinks{H}) where {H <: ObjectHandle} = show_collection(io, dls, H)
show(io::IO, rp::RPath{H}) where {H <: ObjectHandle} = show_collection(io, rp, H)


text:
using Gadfly, DataFrames

set_default_plot_size(6inch, 3inch)

df = DataFrame(x=[0.236033, 0.346517, 0.312707, 0.00790928, 0.488613, 0.210968, 0.951916, 0.999905, 0.251662, 0.986666, 0.555751, 0.437108, 0.424718, 0.773223, 0.28119, 0.209472, 0.251379, 0.0203749, 0.287702, 0.859512],
               y=[0.0769509, 0.640396, 0.873544, 0.278582, 0.751313, 0.644883, 0.0778264, 0.848185, 0.0856352, 0.553206, 0.46335, 0.185821, 0.111981, 0.976312, 0.0516146, 0.53803, 0.455692, 0.279395, 0.178246, 0.548983],
               grouping=vcat(fill("A", 10), fill("B", 10)))
plot(df, x=:x, y=:y, color=:grouping, Geom.line, Stat.step)