text:
#==============================================================================#
# AlexaForBusiness.jl
#
# This file is generated from:
# https://github.com/aws/aws-sdk-js/blob/master/apis/alexaforbusiness-2017-11-09.normal.json
#==============================================================================#

__precompile__()

module AlexaForBusiness

using AWSCore

"""
    using AWSSDK.AlexaForBusiness.associate_contact_with_address_book
    associate_contact_with_address_book([::AWSConfig], arguments::Dict)
    associate_contact_with_address_book([::AWSConfig]; ContactArn=, AddressBookArn=)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "AssociateContactWithAddressBook", arguments::Dict)
    alexaforbusiness([::AWSConfig], "AssociateContactWithAddressBook", ContactArn=, AddressBookArn=)

# AssociateContactWithAddressBook Operation

Associates a contact with a given address book.

# Arguments

## `ContactArn = ::String` -- *Required*
The ARN of the contact to associate with an address book.

## `AddressBookArn = ::String` -- *Required*
The ARN of the address book with which to associate the contact.

# Returns

`AssociateContactWithAddressBookResponse`

# Exceptions

`LimitExceededException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/AssociateContactWithAddressBook)
"""
@inline associate_contact_with_address_book(aws::AWSConfig=default_aws_config(); args...) = associate_contact_with_address_book(aws, args)

@inline associate_contact_with_address_book(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "AssociateContactWithAddressBook", args)

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

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

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

# AssociateDeviceWithRoom Operation

Associates a device with a given room. This applies all the settings from the room profile to the device, and all the skills in any skill groups added to that room. This operation requires the device to be online, or else a manual sync is required.

# Arguments

## `DeviceArn = ::String`
The ARN of the device to associate to a room. Required.

## `RoomArn = ::String`
The ARN of the room with which to associate the device. Required.

# Returns

`AssociateDeviceWithRoomResponse`

# Exceptions

`LimitExceededException` or `DeviceNotRegisteredException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/AssociateDeviceWithRoom)
"""
@inline associate_device_with_room(aws::AWSConfig=default_aws_config(); args...) = associate_device_with_room(aws, args)

@inline associate_device_with_room(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "AssociateDeviceWithRoom", args)

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

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

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

# AssociateSkillGroupWithRoom Operation

Associates a skill group with a given room. This enables all skills in the associated skill group on all devices in the room.

# Arguments

## `SkillGroupArn = ::String`
The ARN of the skill group to associate with a room. Required.

## `RoomArn = ::String`
The ARN of the room with which to associate the skill group. Required.

# Returns

`AssociateSkillGroupWithRoomResponse`

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/AssociateSkillGroupWithRoom)
"""
@inline associate_skill_group_with_room(aws::AWSConfig=default_aws_config(); args...) = associate_skill_group_with_room(aws, args)

@inline associate_skill_group_with_room(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "AssociateSkillGroupWithRoom", args)

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

"""
    using AWSSDK.AlexaForBusiness.create_address_book
    create_address_book([::AWSConfig], arguments::Dict)
    create_address_book([::AWSConfig]; Name=, <keyword arguments>)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "CreateAddressBook", arguments::Dict)
    alexaforbusiness([::AWSConfig], "CreateAddressBook", Name=, <keyword arguments>)

# CreateAddressBook Operation

Creates an address book with the specified details.

# Arguments

## `Name = ::String` -- *Required*
The name of the address book.

## `Description = ::String`
The description of the address book.

## `ClientRequestToken = ::String`
A unique, user-specified identifier for the request that ensures idempotency.

# Returns

`CreateAddressBookResponse`

# Exceptions

`AlreadyExistsException` or `LimitExceededException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/CreateAddressBook)
"""
@inline create_address_book(aws::AWSConfig=default_aws_config(); args...) = create_address_book(aws, args)

@inline create_address_book(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "CreateAddressBook", args)

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

"""
    using AWSSDK.AlexaForBusiness.create_contact
    create_contact([::AWSConfig], arguments::Dict)
    create_contact([::AWSConfig]; FirstName=, PhoneNumber=, <keyword arguments>)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "CreateContact", arguments::Dict)
    alexaforbusiness([::AWSConfig], "CreateContact", FirstName=, PhoneNumber=, <keyword arguments>)

# CreateContact Operation

Creates a contact with the specified details.

# Arguments

## `DisplayName = ::String`
The name of the contact to display on the console.

## `FirstName = ::String` -- *Required*
The first name of the contact that is used to call the contact on the device.

## `LastName = ::String`
The last name of the contact that is used to call the contact on the device.

## `PhoneNumber = ::String` -- *Required*
The phone number of the contact in E.164 format.

## `ClientRequestToken = ::String`
A unique, user-specified identifier for this request that ensures idempotency.

# Returns

`CreateContactResponse`

# Exceptions

`AlreadyExistsException` or `LimitExceededException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/CreateContact)
"""
@inline create_contact(aws::AWSConfig=default_aws_config(); args...) = create_contact(aws, args)

@inline create_contact(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "CreateContact", args)

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

"""
    using AWSSDK.AlexaForBusiness.create_profile
    create_profile([::AWSConfig], arguments::Dict)
    create_profile([::AWSConfig]; ProfileName=, Timezone=, Address=, DistanceUnit=, TemperatureUnit=, WakeWord=, <keyword arguments>)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "CreateProfile", arguments::Dict)
    alexaforbusiness([::AWSConfig], "CreateProfile", ProfileName=, Timezone=, Address=, DistanceUnit=, TemperatureUnit=, WakeWord=, <keyword arguments>)

# CreateProfile Operation

Creates a new room profile with the specified details.

# Arguments

## `ProfileName = ::String` -- *Required*
The name of a room profile.

## `Timezone = ::String` -- *Required*
The time zone used by a room profile.

## `Address = ::String` -- *Required*
The valid address for the room.

## `DistanceUnit = "METRIC" or "IMPERIAL"` -- *Required*
The distance unit to be used by devices in the profile.

## `TemperatureUnit = "FAHRENHEIT" or "CELSIUS"` -- *Required*
The temperature unit to be used by devices in the profile.

## `WakeWord = "ALEXA", "AMAZON", "ECHO" or "COMPUTER"` -- *Required*
A wake word for Alexa, Echo, Amazon, or a computer.

## `ClientRequestToken = ::String`
The user-specified token that is used during the creation of a profile.

## `SetupModeDisabled = ::Bool`
Whether room profile setup is enabled.

## `MaxVolumeLimit = ::Int`
The maximum volume limit for a room profile.

## `PSTNEnabled = ::Bool`
Whether PSTN calling is enabled.

# Returns

`CreateProfileResponse`

# Exceptions

`LimitExceededException` or `AlreadyExistsException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/CreateProfile)
"""
@inline create_profile(aws::AWSConfig=default_aws_config(); args...) = create_profile(aws, args)

@inline create_profile(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "CreateProfile", args)

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

"""
    using AWSSDK.AlexaForBusiness.create_room
    create_room([::AWSConfig], arguments::Dict)
    create_room([::AWSConfig]; RoomName=, <keyword arguments>)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "CreateRoom", arguments::Dict)
    alexaforbusiness([::AWSConfig], "CreateRoom", RoomName=, <keyword arguments>)

# CreateRoom Operation

Creates a room with the specified details.

# Arguments

## `RoomName = ::String` -- *Required*
The name for the room.

## `Description = ::String`
The description for the room.

## `ProfileArn = ::String`
The profile ARN for the room.

## `ProviderCalendarId = ::String`
The calendar ARN for the room.

## `ClientRequestToken = ::String`
A unique, user-specified identifier for this request that ensures idempotency.

## `Tags = [[ ... ], ...]`
The tags for the room.
```
 Tags = [[
        "Key" =>  ::String,
        "Value" =>  ::String
    ], ...]
```

# Returns

`CreateRoomResponse`

# Exceptions

`AlreadyExistsException` or `LimitExceededException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/CreateRoom)
"""
@inline create_room(aws::AWSConfig=default_aws_config(); args...) = create_room(aws, args)

@inline create_room(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "CreateRoom", args)

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

"""
    using AWSSDK.AlexaForBusiness.create_skill_group
    create_skill_group([::AWSConfig], arguments::Dict)
    create_skill_group([::AWSConfig]; SkillGroupName=, <keyword arguments>)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "CreateSkillGroup", arguments::Dict)
    alexaforbusiness([::AWSConfig], "CreateSkillGroup", SkillGroupName=, <keyword arguments>)

# CreateSkillGroup Operation

Creates a skill group with a specified name and description.

# Arguments

## `SkillGroupName = ::String` -- *Required*
The name for the skill group.

## `Description = ::String`
The description for the skill group.

## `ClientRequestToken = ::String`
A unique, user-specified identifier for this request that ensures idempotency.

# Returns

`CreateSkillGroupResponse`

# Exceptions

`AlreadyExistsException` or `LimitExceededException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/CreateSkillGroup)
"""
@inline create_skill_group(aws::AWSConfig=default_aws_config(); args...) = create_skill_group(aws, args)

@inline create_skill_group(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "CreateSkillGroup", args)

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

"""
    using AWSSDK.AlexaForBusiness.create_user
    create_user([::AWSConfig], arguments::Dict)
    create_user([::AWSConfig]; UserId=, <keyword arguments>)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "CreateUser", arguments::Dict)
    alexaforbusiness([::AWSConfig], "CreateUser", UserId=, <keyword arguments>)

# CreateUser Operation

Creates a user.

# Arguments

## `UserId = ::String` -- *Required*
The ARN for the user.

## `FirstName = ::String`
The first name for the user.

## `LastName = ::String`
The last name for the user.

## `Email = ::String`
The email address for the user.

## `ClientRequestToken = ::String`
A unique, user-specified identifier for this request that ensures idempotency.

## `Tags = [[ ... ], ...]`
The tags for the user.
```
 Tags = [[
        "Key" =>  ::String,
        "Value" =>  ::String
    ], ...]
```

# Returns

`CreateUserResponse`

# Exceptions

`ResourceInUseException` or `LimitExceededException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/CreateUser)
"""
@inline create_user(aws::AWSConfig=default_aws_config(); args...) = create_user(aws, args)

@inline create_user(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "CreateUser", args)

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

"""
    using AWSSDK.AlexaForBusiness.delete_address_book
    delete_address_book([::AWSConfig], arguments::Dict)
    delete_address_book([::AWSConfig]; AddressBookArn=)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "DeleteAddressBook", arguments::Dict)
    alexaforbusiness([::AWSConfig], "DeleteAddressBook", AddressBookArn=)

# DeleteAddressBook Operation

Deletes an address book by the address book ARN.

# Arguments

## `AddressBookArn = ::String` -- *Required*
The ARN of the address book to delete.

# Returns

`DeleteAddressBookResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/DeleteAddressBook)
"""
@inline delete_address_book(aws::AWSConfig=default_aws_config(); args...) = delete_address_book(aws, args)

@inline delete_address_book(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "DeleteAddressBook", args)

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

"""
    using AWSSDK.AlexaForBusiness.delete_contact
    delete_contact([::AWSConfig], arguments::Dict)
    delete_contact([::AWSConfig]; ContactArn=)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "DeleteContact", arguments::Dict)
    alexaforbusiness([::AWSConfig], "DeleteContact", ContactArn=)

# DeleteContact Operation

Deletes a contact by the contact ARN.

# Arguments

## `ContactArn = ::String` -- *Required*
The ARN of the contact to delete.

# Returns

`DeleteContactResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/DeleteContact)
"""
@inline delete_contact(aws::AWSConfig=default_aws_config(); args...) = delete_contact(aws, args)

@inline delete_contact(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "DeleteContact", args)

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

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

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

# DeleteProfile Operation

Deletes a room profile by the profile ARN.

# Arguments

## `ProfileArn = ::String`
The ARN of the room profile to delete. Required.

# Returns

`DeleteProfileResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/DeleteProfile)
"""
@inline delete_profile(aws::AWSConfig=default_aws_config(); args...) = delete_profile(aws, args)

@inline delete_profile(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "DeleteProfile", args)

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

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

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

# DeleteRoom Operation

Deletes a room by the room ARN.

# Arguments

## `RoomArn = ::String`
The ARN of the room to delete. Required.

# Returns

`DeleteRoomResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/DeleteRoom)
"""
@inline delete_room(aws::AWSConfig=default_aws_config(); args...) = delete_room(aws, args)

@inline delete_room(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "DeleteRoom", args)

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

"""
    using AWSSDK.AlexaForBusiness.delete_room_skill_parameter
    delete_room_skill_parameter([::AWSConfig], arguments::Dict)
    delete_room_skill_parameter([::AWSConfig]; SkillId=, ParameterKey=, <keyword arguments>)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "DeleteRoomSkillParameter", arguments::Dict)
    alexaforbusiness([::AWSConfig], "DeleteRoomSkillParameter", SkillId=, ParameterKey=, <keyword arguments>)

# DeleteRoomSkillParameter Operation

Deletes room skill parameter details by room, skill, and parameter key ID.

# Arguments

## `RoomArn = ::String`
The ARN of the room from which to remove the room skill parameter details.

## `SkillId = ::String` -- *Required*
The ID of the skill from which to remove the room skill parameter details.

## `ParameterKey = ::String` -- *Required*
The room skill parameter key for which to remove details.

# Returns

`DeleteRoomSkillParameterResponse`

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/DeleteRoomSkillParameter)
"""
@inline delete_room_skill_parameter(aws::AWSConfig=default_aws_config(); args...) = delete_room_skill_parameter(aws, args)

@inline delete_room_skill_parameter(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "DeleteRoomSkillParameter", args)

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

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

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

# DeleteSkillGroup Operation

Deletes a skill group by skill group ARN.

# Arguments

## `SkillGroupArn = ::String`
The ARN of the skill group to delete. Required.

# Returns

`DeleteSkillGroupResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/DeleteSkillGroup)
"""
@inline delete_skill_group(aws::AWSConfig=default_aws_config(); args...) = delete_skill_group(aws, args)

@inline delete_skill_group(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "DeleteSkillGroup", args)

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

"""
    using AWSSDK.AlexaForBusiness.delete_user
    delete_user([::AWSConfig], arguments::Dict)
    delete_user([::AWSConfig]; EnrollmentId=, <keyword arguments>)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "DeleteUser", arguments::Dict)
    alexaforbusiness([::AWSConfig], "DeleteUser", EnrollmentId=, <keyword arguments>)

# DeleteUser Operation

Deletes a specified user by user ARN and enrollment ARN.

# Arguments

## `UserArn = ::String`
The ARN of the user to delete in the organization. Required.

## `EnrollmentId = ::String` -- *Required*
The ARN of the user's enrollment in the organization. Required.

# Returns

`DeleteUserResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/DeleteUser)
"""
@inline delete_user(aws::AWSConfig=default_aws_config(); args...) = delete_user(aws, args)

@inline delete_user(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "DeleteUser", args)

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

"""
    using AWSSDK.AlexaForBusiness.disassociate_contact_from_address_book
    disassociate_contact_from_address_book([::AWSConfig], arguments::Dict)
    disassociate_contact_from_address_book([::AWSConfig]; ContactArn=, AddressBookArn=)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "DisassociateContactFromAddressBook", arguments::Dict)
    alexaforbusiness([::AWSConfig], "DisassociateContactFromAddressBook", ContactArn=, AddressBookArn=)

# DisassociateContactFromAddressBook Operation

Disassociates a contact from a given address book.

# Arguments

## `ContactArn = ::String` -- *Required*
The ARN of the contact to disassociate from an address book.

## `AddressBookArn = ::String` -- *Required*
The ARN of the address from which to disassociate the contact.

# Returns

`DisassociateContactFromAddressBookResponse`

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/DisassociateContactFromAddressBook)
"""
@inline disassociate_contact_from_address_book(aws::AWSConfig=default_aws_config(); args...) = disassociate_contact_from_address_book(aws, args)

@inline disassociate_contact_from_address_book(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "DisassociateContactFromAddressBook", args)

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

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

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

# DisassociateDeviceFromRoom Operation

Disassociates a device from its current room. The device continues to be connected to the Wi-Fi network and is still registered to the account. The device settings and skills are removed from the room.

# Arguments

## `DeviceArn = ::String`
The ARN of the device to disassociate from a room. Required.

# Returns

`DisassociateDeviceFromRoomResponse`

# Exceptions

`DeviceNotRegisteredException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/DisassociateDeviceFromRoom)
"""
@inline disassociate_device_from_room(aws::AWSConfig=default_aws_config(); args...) = disassociate_device_from_room(aws, args)

@inline disassociate_device_from_room(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "DisassociateDeviceFromRoom", args)

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

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

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

# DisassociateSkillGroupFromRoom Operation

Disassociates a skill group from a specified room. This disables all skills in the skill group on all devices in the room.

# Arguments

## `SkillGroupArn = ::String`
The ARN of the skill group to disassociate from a room. Required.

## `RoomArn = ::String`
The ARN of the room from which the skill group is to be disassociated. Required.

# Returns

`DisassociateSkillGroupFromRoomResponse`

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/DisassociateSkillGroupFromRoom)
"""
@inline disassociate_skill_group_from_room(aws::AWSConfig=default_aws_config(); args...) = disassociate_skill_group_from_room(aws, args)

@inline disassociate_skill_group_from_room(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "DisassociateSkillGroupFromRoom", args)

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

"""
    using AWSSDK.AlexaForBusiness.get_address_book
    get_address_book([::AWSConfig], arguments::Dict)
    get_address_book([::AWSConfig]; AddressBookArn=)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "GetAddressBook", arguments::Dict)
    alexaforbusiness([::AWSConfig], "GetAddressBook", AddressBookArn=)

# GetAddressBook Operation

Gets address the book details by the address book ARN.

# Arguments

## `AddressBookArn = ::String` -- *Required*
The ARN of the address book for which to request details.

# Returns

`GetAddressBookResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/GetAddressBook)
"""
@inline get_address_book(aws::AWSConfig=default_aws_config(); args...) = get_address_book(aws, args)

@inline get_address_book(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "GetAddressBook", args)

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

"""
    using AWSSDK.AlexaForBusiness.get_contact
    get_contact([::AWSConfig], arguments::Dict)
    get_contact([::AWSConfig]; ContactArn=)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "GetContact", arguments::Dict)
    alexaforbusiness([::AWSConfig], "GetContact", ContactArn=)

# GetContact Operation

Gets the contact details by the contact ARN.

# Arguments

## `ContactArn = ::String` -- *Required*
The ARN of the contact for which to request details.

# Returns

`GetContactResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/GetContact)
"""
@inline get_contact(aws::AWSConfig=default_aws_config(); args...) = get_contact(aws, args)

@inline get_contact(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "GetContact", args)

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

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

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

# GetDevice Operation

Gets the details of a device by device ARN.

# Arguments

## `DeviceArn = ::String`
The ARN of the device for which to request details. Required.

# Returns

`GetDeviceResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/GetDevice)
"""
@inline get_device(aws::AWSConfig=default_aws_config(); args...) = get_device(aws, args)

@inline get_device(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "GetDevice", args)

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

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

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

# GetProfile Operation

Gets the details of a room profile by profile ARN.

# Arguments

## `ProfileArn = ::String`
The ARN of the room profile for which to request details. Required.

# Returns

`GetProfileResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/GetProfile)
"""
@inline get_profile(aws::AWSConfig=default_aws_config(); args...) = get_profile(aws, args)

@inline get_profile(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "GetProfile", args)

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

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

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

# GetRoom Operation

Gets room details by room ARN.

# Arguments

## `RoomArn = ::String`
The ARN of the room for which to request details. Required.

# Returns

`GetRoomResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/GetRoom)
"""
@inline get_room(aws::AWSConfig=default_aws_config(); args...) = get_room(aws, args)

@inline get_room(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "GetRoom", args)

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

"""
    using AWSSDK.AlexaForBusiness.get_room_skill_parameter
    get_room_skill_parameter([::AWSConfig], arguments::Dict)
    get_room_skill_parameter([::AWSConfig]; SkillId=, ParameterKey=, <keyword arguments>)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "GetRoomSkillParameter", arguments::Dict)
    alexaforbusiness([::AWSConfig], "GetRoomSkillParameter", SkillId=, ParameterKey=, <keyword arguments>)

# GetRoomSkillParameter Operation

Gets room skill parameter details by room, skill, and parameter key ARN.

# Arguments

## `RoomArn = ::String`
The ARN of the room from which to get the room skill parameter details.

## `SkillId = ::String` -- *Required*
The ARN of the skill from which to get the room skill parameter details. Required.

## `ParameterKey = ::String` -- *Required*
The room skill parameter key for which to get details. Required.

# Returns

`GetRoomSkillParameterResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/GetRoomSkillParameter)
"""
@inline get_room_skill_parameter(aws::AWSConfig=default_aws_config(); args...) = get_room_skill_parameter(aws, args)

@inline get_room_skill_parameter(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "GetRoomSkillParameter", args)

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

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

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

# GetSkillGroup Operation

Gets skill group details by skill group ARN.

# Arguments

## `SkillGroupArn = ::String`
The ARN of the skill group for which to get details. Required.

# Returns

`GetSkillGroupResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/GetSkillGroup)
"""
@inline get_skill_group(aws::AWSConfig=default_aws_config(); args...) = get_skill_group(aws, args)

@inline get_skill_group(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "GetSkillGroup", args)

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

"""
    using AWSSDK.AlexaForBusiness.list_device_events
    list_device_events([::AWSConfig], arguments::Dict)
    list_device_events([::AWSConfig]; DeviceArn=, <keyword arguments>)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "ListDeviceEvents", arguments::Dict)
    alexaforbusiness([::AWSConfig], "ListDeviceEvents", DeviceArn=, <keyword arguments>)

# ListDeviceEvents Operation

Lists the Device Event history for up to 30 days. If EventType isn't specified in the request, this returns a list of all device events in reverse chronological order. If EventType is specified, this returns a list of device events for that EventType in reverse chronological order.

# Arguments

## `DeviceArn = ::String` -- *Required*
The ARN of a device.

## `EventType = "CONNECTION_STATUS" or "DEVICE_STATUS"`
The event type to filter device events.

## `NextToken = ::String`
An optional token returned from a prior request. Use this token for pagination of results from this action. If this parameter is specified, the response only includes results beyond the token, up to the value specified by MaxResults.

## `MaxResults = ::Int`
The maximum number of results to include in the response. If more results exist than the specified MaxResults value, a token is included in the response so that the remaining results can be retrieved. Required.

# Returns

`ListDeviceEventsResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/ListDeviceEvents)
"""
@inline list_device_events(aws::AWSConfig=default_aws_config(); args...) = list_device_events(aws, args)

@inline list_device_events(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "ListDeviceEvents", args)

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

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

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

# ListSkills Operation

Lists all enabled skills in a specific skill group.

# Arguments

## `SkillGroupArn = ::String`
The ARN of the skill group for which to list enabled skills. Required.

## `NextToken = ::String`
An optional token returned from a prior request. Use this token for pagination of results from this action. If this parameter is specified, the response includes only results beyond the token, up to the value specified by `MaxResults`. Required.

## `MaxResults = ::Int`
The maximum number of results to include in the response. If more results exist than the specified `MaxResults` value, a token is included in the response so that the remaining results can be retrieved. Required.

# Returns

`ListSkillsResponse`

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/ListSkills)
"""
@inline list_skills(aws::AWSConfig=default_aws_config(); args...) = list_skills(aws, args)

@inline list_skills(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "ListSkills", args)

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

"""
    using AWSSDK.AlexaForBusiness.list_tags
    list_tags([::AWSConfig], arguments::Dict)
    list_tags([::AWSConfig]; Arn=, <keyword arguments>)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "ListTags", arguments::Dict)
    alexaforbusiness([::AWSConfig], "ListTags", Arn=, <keyword arguments>)

# ListTags Operation

Lists all tags for a specific resource.

# Arguments

## `Arn = ::String` -- *Required*
The ARN of the specific resource for which to list tags. Required.

## `NextToken = ::String`
An optional token returned from a prior request. Use this token for pagination of results from this action. If this parameter is specified, the response includes only results beyond the token, up to the value specified by `MaxResults`.

## `MaxResults = ::Int`
The maximum number of results to include in the response. If more results exist than the specified `MaxResults` value, a token is included in the response so that the remaining results can be retrieved.

# Returns

`ListTagsResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/ListTags)
"""
@inline list_tags(aws::AWSConfig=default_aws_config(); args...) = list_tags(aws, args)

@inline list_tags(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "ListTags", args)

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

"""
    using AWSSDK.AlexaForBusiness.put_room_skill_parameter
    put_room_skill_parameter([::AWSConfig], arguments::Dict)
    put_room_skill_parameter([::AWSConfig]; SkillId=, RoomSkillParameter=, <keyword arguments>)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "PutRoomSkillParameter", arguments::Dict)
    alexaforbusiness([::AWSConfig], "PutRoomSkillParameter", SkillId=, RoomSkillParameter=, <keyword arguments>)

# PutRoomSkillParameter Operation

Updates room skill parameter details by room, skill, and parameter key ID. Not all skills have a room skill parameter.

# Arguments

## `RoomArn = ::String`
The ARN of the room associated with the room skill parameter. Required.

## `SkillId = ::String` -- *Required*
The ARN of the skill associated with the room skill parameter. Required.

## `RoomSkillParameter = [ ... ]` -- *Required*
The updated room skill parameter. Required.
```
 RoomSkillParameter = [
        "ParameterKey" => <required> ::String,
        "ParameterValue" => <required> ::String
    ]
```

# Returns

`PutRoomSkillParameterResponse`

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/PutRoomSkillParameter)
"""
@inline put_room_skill_parameter(aws::AWSConfig=default_aws_config(); args...) = put_room_skill_parameter(aws, args)

@inline put_room_skill_parameter(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "PutRoomSkillParameter", args)

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

"""
    using AWSSDK.AlexaForBusiness.resolve_room
    resolve_room([::AWSConfig], arguments::Dict)
    resolve_room([::AWSConfig]; UserId=, SkillId=)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "ResolveRoom", arguments::Dict)
    alexaforbusiness([::AWSConfig], "ResolveRoom", UserId=, SkillId=)

# ResolveRoom Operation

Determines the details for the room from which a skill request was invoked. This operation is used by skill developers.

# Arguments

## `UserId = ::String` -- *Required*
The ARN of the user. Required.

## `SkillId = ::String` -- *Required*
The ARN of the skill that was requested. Required.

# Returns

`ResolveRoomResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/ResolveRoom)
"""
@inline resolve_room(aws::AWSConfig=default_aws_config(); args...) = resolve_room(aws, args)

@inline resolve_room(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "ResolveRoom", args)

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

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

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

# RevokeInvitation Operation

Revokes an invitation and invalidates the enrollment URL.

# Arguments

## `UserArn = ::String`
The ARN of the user for whom to revoke an enrollment invitation. Required.

## `EnrollmentId = ::String`
The ARN of the enrollment invitation to revoke. Required.

# Returns

`RevokeInvitationResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/RevokeInvitation)
"""
@inline revoke_invitation(aws::AWSConfig=default_aws_config(); args...) = revoke_invitation(aws, args)

@inline revoke_invitation(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "RevokeInvitation", args)

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

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

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

# SearchAddressBooks Operation

Searches address books and lists the ones that meet a set of filter and sort criteria.

# Arguments

## `Filters = [[ ... ], ...]`
The filters to use to list a specified set of address books. The supported filter key is AddressBookName.
```
 Filters = [[
        "Key" => <required> ::String,
        "Values" => <required> [::String, ...]
    ], ...]
```

## `SortCriteria = [[ ... ], ...]`
The sort order to use in listing the specified set of address books. The supported sort key is AddressBookName.
```
 SortCriteria = [[
        "Key" => <required> ::String,
        "Value" => <required> "ASC" or "DESC"
    ], ...]
```

## `NextToken = ::String`
An optional token returned from a prior request. Use this token for pagination of results from this action. If this parameter is specified, the response only includes results beyond the token, up to the value specified by MaxResults.

## `MaxResults = ::Int`
The maximum number of results to include in the response. If more results exist than the specified MaxResults value, a token is included in the response so that the remaining results can be retrieved.

# Returns

`SearchAddressBooksResponse`

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/SearchAddressBooks)
"""
@inline search_address_books(aws::AWSConfig=default_aws_config(); args...) = search_address_books(aws, args)

@inline search_address_books(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "SearchAddressBooks", args)

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

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

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

# SearchContacts Operation

Searches contacts and lists the ones that meet a set of filter and sort criteria.

# Arguments

## `Filters = [[ ... ], ...]`
The filters to use to list a specified set of address books. The supported filter keys are DisplayName, FirstName, LastName, and AddressBookArns.
```
 Filters = [[
        "Key" => <required> ::String,
        "Values" => <required> [::String, ...]
    ], ...]
```

## `SortCriteria = [[ ... ], ...]`
The sort order to use in listing the specified set of contacts. The supported sort keys are DisplayName, FirstName, and LastName.
```
 SortCriteria = [[
        "Key" => <required> ::String,
        "Value" => <required> "ASC" or "DESC"
    ], ...]
```

## `NextToken = ::String`
An optional token returned from a prior request. Use this token for pagination of results from this action. If this parameter is specified, the response only includes results beyond the token, up to the value specified by MaxResults.

## `MaxResults = ::Int`
The maximum number of results to include in the response. If more results exist than the specified MaxResults value, a token is included in the response so that the remaining results can be retrieved.

# Returns

`SearchContactsResponse`

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/SearchContacts)
"""
@inline search_contacts(aws::AWSConfig=default_aws_config(); args...) = search_contacts(aws, args)

@inline search_contacts(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "SearchContacts", args)

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

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

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

# SearchDevices Operation

Searches devices and lists the ones that meet a set of filter criteria.

# Arguments

## `NextToken = ::String`
An optional token returned from a prior request. Use this token for pagination of results from this action. If this parameter is specified, the response includes only results beyond the token, up to the value specified by `MaxResults`.

## `MaxResults = ::Int`
The maximum number of results to include in the response. If more results exist than the specified `MaxResults` value, a token is included in the response so that the remaining results can be retrieved.

## `Filters = [[ ... ], ...]`
The filters to use to list a specified set of devices. Supported filter keys are DeviceName, DeviceStatus, DeviceStatusDetailCode, RoomName, DeviceType, DeviceSerialNumber, UnassociatedOnly, and ConnectionStatus (ONLINE and OFFLINE).
```
 Filters = [[
        "Key" => <required> ::String,
        "Values" => <required> [::String, ...]
    ], ...]
```

## `SortCriteria = [[ ... ], ...]`
The sort order to use in listing the specified set of devices. Supported sort keys are DeviceName, DeviceStatus, RoomName, DeviceType, DeviceSerialNumber, and ConnectionStatus.
```
 SortCriteria = [[
        "Key" => <required> ::String,
        "Value" => <required> "ASC" or "DESC"
    ], ...]
```

# Returns

`SearchDevicesResponse`

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/SearchDevices)
"""
@inline search_devices(aws::AWSConfig=default_aws_config(); args...) = search_devices(aws, args)

@inline search_devices(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "SearchDevices", args)

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

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

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

# SearchProfiles Operation

Searches room profiles and lists the ones that meet a set of filter criteria.

# Arguments

## `NextToken = ::String`
An optional token returned from a prior request. Use this token for pagination of results from this action. If this parameter is specified, the response includes only results beyond the token, up to the value specified by `MaxResults`.

## `MaxResults = ::Int`
The maximum number of results to include in the response. If more results exist than the specified `MaxResults` value, a token is included in the response so that the remaining results can be retrieved.

## `Filters = [[ ... ], ...]`
The filters to use to list a specified set of room profiles. Supported filter keys are ProfileName and Address. Required.
```
 Filters = [[
        "Key" => <required> ::String,
        "Values" => <required> [::String, ...]
    ], ...]
```

## `SortCriteria = [[ ... ], ...]`
The sort order to use in listing the specified set of room profiles. Supported sort keys are ProfileName and Address.
```
 SortCriteria = [[
        "Key" => <required> ::String,
        "Value" => <required> "ASC" or "DESC"
    ], ...]
```

# Returns

`SearchProfilesResponse`

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/SearchProfiles)
"""
@inline search_profiles(aws::AWSConfig=default_aws_config(); args...) = search_profiles(aws, args)

@inline search_profiles(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "SearchProfiles", args)

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

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

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

# SearchRooms Operation

Searches rooms and lists the ones that meet a set of filter and sort criteria.

# Arguments

## `NextToken = ::String`
An optional token returned from a prior request. Use this token for pagination of results from this action. If this parameter is specified, the response includes only results beyond the token, up to the value specified by `MaxResults`.

## `MaxResults = ::Int`
The maximum number of results to include in the response. If more results exist than the specified `MaxResults` value, a token is included in the response so that the remaining results can be retrieved.

## `Filters = [[ ... ], ...]`
The filters to use to list a specified set of rooms. The supported filter keys are RoomName and ProfileName.
```
 Filters = [[
        "Key" => <required> ::String,
        "Values" => <required> [::String, ...]
    ], ...]
```

## `SortCriteria = [[ ... ], ...]`
The sort order to use in listing the specified set of rooms. The supported sort keys are RoomName and ProfileName.
```
 SortCriteria = [[
        "Key" => <required> ::String,
        "Value" => <required> "ASC" or "DESC"
    ], ...]
```

# Returns

`SearchRoomsResponse`

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/SearchRooms)
"""
@inline search_rooms(aws::AWSConfig=default_aws_config(); args...) = search_rooms(aws, args)

@inline search_rooms(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "SearchRooms", args)

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

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

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

# SearchSkillGroups Operation

Searches skill groups and lists the ones that meet a set of filter and sort criteria.

# Arguments

## `NextToken = ::String`
An optional token returned from a prior request. Use this token for pagination of results from this action. If this parameter is specified, the response includes only results beyond the token, up to the value specified by `MaxResults`. Required.

## `MaxResults = ::Int`
The maximum number of results to include in the response. If more results exist than the specified `MaxResults` value, a token is included in the response so that the remaining results can be retrieved.

## `Filters = [[ ... ], ...]`
The filters to use to list a specified set of skill groups. The supported filter key is SkillGroupName.
```
 Filters = [[
        "Key" => <required> ::String,
        "Values" => <required> [::String, ...]
    ], ...]
```

## `SortCriteria = [[ ... ], ...]`
The sort order to use in listing the specified set of skill groups. The supported sort key is SkillGroupName.
```
 SortCriteria = [[
        "Key" => <required> ::String,
        "Value" => <required> "ASC" or "DESC"
    ], ...]
```

# Returns

`SearchSkillGroupsResponse`

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/SearchSkillGroups)
"""
@inline search_skill_groups(aws::AWSConfig=default_aws_config(); args...) = search_skill_groups(aws, args)

@inline search_skill_groups(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "SearchSkillGroups", args)

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

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

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

# SearchUsers Operation

Searches users and lists the ones that meet a set of filter and sort criteria.

# Arguments

## `NextToken = ::String`
An optional token returned from a prior request. Use this token for pagination of results from this action. If this parameter is specified, the response includes only results beyond the token, up to the value specified by `MaxResults`. Required.

## `MaxResults = ::Int`
The maximum number of results to include in the response. If more results exist than the specified `MaxResults` value, a token is included in the response so that the remaining results can be retrieved. Required.

## `Filters = [[ ... ], ...]`
The filters to use for listing a specific set of users. Required. Supported filter keys are UserId, FirstName, LastName, Email, and EnrollmentStatus.
```
 Filters = [[
        "Key" => <required> ::String,
        "Values" => <required> [::String, ...]
    ], ...]
```

## `SortCriteria = [[ ... ], ...]`
The sort order to use in listing the filtered set of users. Required. Supported sort keys are UserId, FirstName, LastName, Email, and EnrollmentStatus.
```
 SortCriteria = [[
        "Key" => <required> ::String,
        "Value" => <required> "ASC" or "DESC"
    ], ...]
```

# Returns

`SearchUsersResponse`

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/SearchUsers)
"""
@inline search_users(aws::AWSConfig=default_aws_config(); args...) = search_users(aws, args)

@inline search_users(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "SearchUsers", args)

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

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

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

# SendInvitation Operation

Sends an enrollment invitation email with a URL to a user. The URL is valid for 72 hours or until you call this operation again, whichever comes first.

# Arguments

## `UserArn = ::String`
The ARN of the user to whom to send an invitation. Required.

# Returns

`SendInvitationResponse`

# Exceptions

`NotFoundException` or `InvalidUserStatusException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/SendInvitation)
"""
@inline send_invitation(aws::AWSConfig=default_aws_config(); args...) = send_invitation(aws, args)

@inline send_invitation(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "SendInvitation", args)

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

"""
    using AWSSDK.AlexaForBusiness.start_device_sync
    start_device_sync([::AWSConfig], arguments::Dict)
    start_device_sync([::AWSConfig]; Features=, <keyword arguments>)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "StartDeviceSync", arguments::Dict)
    alexaforbusiness([::AWSConfig], "StartDeviceSync", Features=, <keyword arguments>)

# StartDeviceSync Operation

Resets a device and its account to the known default settings, by clearing all information and settings set by previous users.

# Arguments

## `RoomArn = ::String`
The ARN of the room with which the device to sync is associated. Required.

## `DeviceArn = ::String`
The ARN of the device to sync. Required.

## `Features = ["BLUETOOTH", "VOLUME", "NOTIFICATIONS", "LISTS", "SKILLS" or "ALL", ...]` -- *Required*
Request structure to start the device sync. Required.

# Returns

`StartDeviceSyncResponse`

# Exceptions

`DeviceNotRegisteredException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/StartDeviceSync)
"""
@inline start_device_sync(aws::AWSConfig=default_aws_config(); args...) = start_device_sync(aws, args)

@inline start_device_sync(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "StartDeviceSync", args)

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

"""
    using AWSSDK.AlexaForBusiness.tag_resource
    tag_resource([::AWSConfig], arguments::Dict)
    tag_resource([::AWSConfig]; Arn=, Tags=)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "TagResource", arguments::Dict)
    alexaforbusiness([::AWSConfig], "TagResource", Arn=, Tags=)

# TagResource Operation

Adds metadata tags to a specified resource.

# Arguments

## `Arn = ::String` -- *Required*
The ARN of the resource to which to add metadata tags. Required.

## `Tags = [[ ... ], ...]` -- *Required*
The tags to be added to the specified resource. Do not provide system tags. Required.
```
 Tags = [[
        "Key" =>  ::String,
        "Value" =>  ::String
    ], ...]
```

# Returns

`TagResourceResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/TagResource)
"""
@inline tag_resource(aws::AWSConfig=default_aws_config(); args...) = tag_resource(aws, args)

@inline tag_resource(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "TagResource", args)

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

"""
    using AWSSDK.AlexaForBusiness.untag_resource
    untag_resource([::AWSConfig], arguments::Dict)
    untag_resource([::AWSConfig]; Arn=, TagKeys=)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "UntagResource", arguments::Dict)
    alexaforbusiness([::AWSConfig], "UntagResource", Arn=, TagKeys=)

# UntagResource Operation

Removes metadata tags from a specified resource.

# Arguments

## `Arn = ::String` -- *Required*
The ARN of the resource from which to remove metadata tags. Required.

## `TagKeys = [::String, ...]` -- *Required*
The tags to be removed from the specified resource. Do not provide system tags. Required.

# Returns

`UntagResourceResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/UntagResource)
"""
@inline untag_resource(aws::AWSConfig=default_aws_config(); args...) = untag_resource(aws, args)

@inline untag_resource(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "UntagResource", args)

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

"""
    using AWSSDK.AlexaForBusiness.update_address_book
    update_address_book([::AWSConfig], arguments::Dict)
    update_address_book([::AWSConfig]; AddressBookArn=, <keyword arguments>)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "UpdateAddressBook", arguments::Dict)
    alexaforbusiness([::AWSConfig], "UpdateAddressBook", AddressBookArn=, <keyword arguments>)

# UpdateAddressBook Operation

Updates address book details by the address book ARN.

# Arguments

## `AddressBookArn = ::String` -- *Required*
The ARN of the room to update.

## `Name = ::String`
The updated name of the room.

## `Description = ::String`
The updated description of the room.

# Returns

`UpdateAddressBookResponse`

# Exceptions

`NotFoundException` or `NameInUseException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/UpdateAddressBook)
"""
@inline update_address_book(aws::AWSConfig=default_aws_config(); args...) = update_address_book(aws, args)

@inline update_address_book(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "UpdateAddressBook", args)

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

"""
    using AWSSDK.AlexaForBusiness.update_contact
    update_contact([::AWSConfig], arguments::Dict)
    update_contact([::AWSConfig]; ContactArn=, <keyword arguments>)

    using AWSCore.Services.alexaforbusiness
    alexaforbusiness([::AWSConfig], "UpdateContact", arguments::Dict)
    alexaforbusiness([::AWSConfig], "UpdateContact", ContactArn=, <keyword arguments>)

# UpdateContact Operation

Updates the contact details by the contact ARN.

# Arguments

## `ContactArn = ::String` -- *Required*
The ARN of the contact to update.

## `DisplayName = ::String`
The updated display name of the contact.

## `FirstName = ::String`
The updated first name of the contact.

## `LastName = ::String`
The updated last name of the contact.

## `PhoneNumber = ::String`
The updated phone number of the contact.

# Returns

`UpdateContactResponse`

# Exceptions

`NotFoundException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/UpdateContact)
"""
@inline update_contact(aws::AWSConfig=default_aws_config(); args...) = update_contact(aws, args)

@inline update_contact(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "UpdateContact", args)

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

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

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

# UpdateDevice Operation

Updates the device name by device ARN.

# Arguments

## `DeviceArn = ::String`
The ARN of the device to update. Required.

## `DeviceName = ::String`
The updated device name. Required.

# Returns

`UpdateDeviceResponse`

# Exceptions

`NotFoundException` or `DeviceNotRegisteredException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/UpdateDevice)
"""
@inline update_device(aws::AWSConfig=default_aws_config(); args...) = update_device(aws, args)

@inline update_device(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "UpdateDevice", args)

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

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

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

# UpdateProfile Operation

Updates an existing room profile by room profile ARN.

# Arguments

## `ProfileArn = ::String`
The ARN of the room profile to update. Required.

## `ProfileName = ::String`
The updated name for the room profile.

## `Timezone = ::String`
The updated timezone for the room profile.

## `Address = ::String`
The updated address for the room profile.

## `DistanceUnit = "METRIC" or "IMPERIAL"`
The updated distance unit for the room profile.

## `TemperatureUnit = "FAHRENHEIT" or "CELSIUS"`
The updated temperature unit for the room profile.

## `WakeWord = "ALEXA", "AMAZON", "ECHO" or "COMPUTER"`
The updated wake word for the room profile.

## `SetupModeDisabled = ::Bool`
Whether the setup mode of the profile is enabled.

## `MaxVolumeLimit = ::Int`
The updated maximum volume limit for the room profile.

## `PSTNEnabled = ::Bool`
Whether the PSTN setting of the room profile is enabled.

# Returns

`UpdateProfileResponse`

# Exceptions

`NotFoundException` or `NameInUseException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/UpdateProfile)
"""
@inline update_profile(aws::AWSConfig=default_aws_config(); args...) = update_profile(aws, args)

@inline update_profile(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "UpdateProfile", args)

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

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

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

# UpdateRoom Operation

Updates room details by room ARN.

# Arguments

## `RoomArn = ::String`
The ARN of the room to update.

## `RoomName = ::String`
The updated name for the room.

## `Description = ::String`
The updated description for the room.

## `ProviderCalendarId = ::String`
The updated provider calendar ARN for the room.

## `ProfileArn = ::String`
The updated profile ARN for the room.

# Returns

`UpdateRoomResponse`

# Exceptions

`NotFoundException` or `NameInUseException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/UpdateRoom)
"""
@inline update_room(aws::AWSConfig=default_aws_config(); args...) = update_room(aws, args)

@inline update_room(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "UpdateRoom", args)

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

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

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

# UpdateSkillGroup Operation

Updates skill group details by skill group ARN.

# Arguments

## `SkillGroupArn = ::String`
The ARN of the skill group to update.

## `SkillGroupName = ::String`
The updated name for the skill group.

## `Description = ::String`
The updated description for the skill group.

# Returns

`UpdateSkillGroupResponse`

# Exceptions

`NotFoundException` or `NameInUseException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/alexaforbusiness-2017-11-09/UpdateSkillGroup)
"""
@inline update_skill_group(aws::AWSConfig=default_aws_config(); args...) = update_skill_group(aws, args)

@inline update_skill_group(aws::AWSConfig, args) = AWSCore.Services.alexaforbusiness(aws, "UpdateSkillGroup", args)

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

end # module AlexaForBusiness

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


text:
using Test
using Symbolics, StructArrays
using DifferentiableStateSpaceModels: order_vector_by_symbols, make_substitutions

const ∞ = Inf
@variables α, β, ρ, δ, σ
@variables t::Integer, k(..), z(..), c(..), q(..)
x = [k, z]
y = [c, q]
p = [α, β, ρ, δ, σ]
subs_x = StructArray(make_substitutions.(t, x))
subs_y = StructArray(make_substitutions.(t, y))
subs = vcat(subs_x, subs_y)
p_symbols = Symbol.(p)

p_val = (α = 0.1, β = 0.5, ρ = 0.1, δ = 1.9, σ= 1.9)
p_val_2 = (ρ = 0.1, α = 0.1, σ= 1.9, β = 0.5, δ = 1.9)
p_vec = order_vector_by_symbols(p_val, p_symbols)
p_vec_2 = order_vector_by_symbols(p_val_2, p_symbols)
@test p_vec ≈ p_vec_2

ext: jl


text:
# This file was generated, do not modify it. # hide
x = randn(N)
λ = 1.0

max_stars_repo_name: cscherrer/InformativePrior

max_issues_repo_name: cscherrer/InformativePrior

max_forks_repo_name: cscherrer/InformativePrior


text:
###############################
##  Markov chain simulation  ##
###############################

function tr_prioH(θ, N_H, N_E, p_H, p_E)
    if rand() < θ #incoming H
        if rand() > (1 - p_H^2)^N_H #can match to another H
            N_H -= 1
        elseif rand() > (1 - p_E*p_H)^N_E #can match to an E
            N_E -= 1
        else
            N_H += 1
        end
    else #incoming E
         if rand() > (1 - p_E*p_H)^N_H #can match to another H
            N_H -= 1
        elseif rand() > (1 - p_E^2)^N_E #can match to an E
            N_E -= 1
        else
            N_E += 1
        end
    end
    return (N_H, N_E)
end

function tr_random_prio(θ, N_H, N_E, p_H, p_E)
    if rand() < θ #incoming H
      n_E = N_E
      n_H = N_H
      while n_E > 0 || n_H > 0
        if rand() < n_E / (n_E + n_H) # probability that we pick an E next
          if rand() < p_E*p_H # can match to the E
            N_E -= 1
            break
          else
            n_E -= 1 # decrease pool of available matches
          end
        else
          if rand() < p_H^2
            N_H -= 1
            break
          else
            n_H -= 1 # decrease pool of available matches.
          end
        end
      end
      if n_E == 0 && n_H == 0
        N_H += 1
      end
    else #incoming E
      n_E = N_E
      n_H = N_H
      while n_E > 0 || n_H > 0
        if rand() < n_E / (n_E + n_H) # probability that we pick an E next
          if rand() < p_E^2 # can match to the E
            N_E -= 1
            break
          else
            n_E -= 1 # decrease pool of available matches
          end
        else
          if rand() < p_H * p_E
            N_H -= 1
            break
          else
            n_H -= 1 # decrease pool of available matches.
          end
        end
      end
      if n_E == 0 && n_H == 0
        N_E += 1
      end
    end
    return (N_H, N_E)
end

function tr_prioE(θ, N_H, N_E, p_H, p_E)
    if rand() < θ #incoming H
        if rand() > (1 - p_E*p_H)^N_E #can match to an E
            N_E -= 1
        elseif rand() > (1 - p_H^2)^N_H #can match to another H
            N_H -= 1
        else
            N_H += 1
        end
    else #incoming E
        if rand() > (1 - p_E^2)^N_E #can match to an E
            N_E -= 1
        elseif rand() > (1 - p_E*p_H)^N_H #can match to another H
            N_H -= 1
        else
            N_E += 1
        end
    end
    return (N_H, N_E)
end

function tr_chains(θ, N_H, N_E, p_H, p_E, d)
    continue_chain = false
    if rand() < θ #incoming H
        if rand() < 1 - (1 - p_H)^d #can match to another H
            continue_chain = true
        else
            N_H += 1
        end
    else #incoming E
         if rand() < 1 - (1 - p_E)^d
            continue_chain = true
        else
            N_E += 1
        end
    end
    while continue_chain
        if rand() < 1 - (1 - p_H)^N_H
            N_H -= 1
        elseif rand() < 1 - (1 - p_E)^N_E
            N_E -= 1
        else
            continue_chain = false
        end
    end
    return (N_H, N_E)
end

function tr_chains_prioE(θ, N_H, N_E, p_H, p_E, d)
    continue_chain = false
    if rand() < θ #incoming H
        if rand() < 1 - (1 - p_H)^d #can match to another H
            continue_chain = true
        else
            N_H += 1
        end
    else #incoming E
         if rand() < 1 - (1 - p_E)^d
            continue_chain = true
        else
            N_E += 1
        end
    end
    while continue_chain
        if rand() < 1 - (1 - p_E)^N_E
            N_E -= 1
        elseif rand() < 1 - (1 - p_H)^N_H
            N_H -= 1
        else
            continue_chain = false
        end
    end
    return (N_H, N_E)
end


text:
################################################################################
#                             SUPPORT SUM METHODS
################################################################################
# Define coefficient function for summing over supports
_support_sum_coeffs(x::Array) = ones(size(x)[end])

"""
    support_sum(expr::JuMP.AbstractJuMPScalar,
                params::Union{GeneralVariableRef, AbstractArray{GeneralVariableRef}};
                label = All
                )::GeneralVariableRef

Creates a measure that represents the sum of the expression over a parameter(s)
using all of its supports corresponding to `label`. Also, note that it is
preferred to call [`@support_sum`](@ref) when `expr` is not just a
single variable reference.

**Example**
```julia-repl
julia> @infinite_parameter(model, x in [0, 1], supports = [0.3, 0.7])
x

julia> @variable(model, f, Infinite(x))
f(x)

julia> meas = support_sum(f, x)
support_sum{x}[f(x)]

julia> expand(meas)
f(0.3) + f(0.7)
```
"""
function support_sum(
    expr::JuMP.AbstractJuMPScalar,
    prefs::Union{InfiniteOpt.GeneralVariableRef, AbstractArray{InfiniteOpt.GeneralVariableRef}};
    label = InfiniteOpt.All
    )::InfiniteOpt.GeneralVariableRef
    # make the data
    vect_prefs = InfiniteOpt.Collections.vectorize(prefs)
    length(prefs) == 1 ? bounds = NaN : bounds = map(e -> NaN, vect_prefs)
    data = InfiniteOpt.FunctionalDiscreteMeasureData(vect_prefs, _support_sum_coeffs,
                                                     0, label,
                                                     InfiniteOpt.NoGenerativeSupports(),
                                                     InfiniteOpt.default_weight,
                                                     bounds, bounds, false)
    # make the measure
    return InfiniteOpt.measure(expr, data, name = "support_sum")
end

"""
    @support_sum(expr::JuMP.AbstractJuMPScalar,
                 prefs::Union{GeneralVariableRef, AbstractArray{GeneralVariableRef}};
                 label = All
                 )::GeneralVariableRef

An efficient wrapper for [`support_sum`](@ref) please see its doc string for
more information.
"""
macro support_sum(expr, prefs, args...)
    _error(str...) = InfiniteOpt._macro_error(:support_sum, (expr, prefs, args...),
                                              str...)
    extra, kwargs, _, _ = InfiniteOpt._extract_kwargs(args)
    if length(extra) > 0
        _error("Unexpected positional arguments." *
               "Must be of form @support_sum(expr, prefs, kwargs...).")
    end
    expression = :( JuMP.@expression(InfiniteOpt._Model, $expr) )
    mref = :( support_sum($expression, $prefs; ($(kwargs...))) )
    return esc(mref)
end


text:
using Dataframes, StatsBase
aapl = readtable("AAPL-Short,csv");

naapl = size(aapl)[1]
m1 = int(mean((aapl[:Volume]))); # => 6306547

using Match
wts = zeros(naapl);
for i in 1:naapl
    dt = aapl[:Date][i]
    wts[i] = @match dt begin
         r"^2000" => 1.0
         r"^2001" => 2.0
         r"^2002" => 4.0
         _        => 0.0
    end
end;

wv = WeightVec(wts);
m2 = int(mean(aapl[:Volume], wv))
mean(aapl[:Close])
mean(aapl[:Close], wv)
trimmean(aapl[:Close], 0.1)

std(aapl[:Close])
skewness(aapl[:Close])
kurtosis(aapl[:Close])

max_stars_repo_path: Module 3/Chapter05/aapl-stats.jl

max_issues_repo_path: Module 3/Chapter05/aapl-stats.jl

max_forks_repo_path: Module 3/Chapter05/aapl-stats.jl


text:
@testset "moon98" begin
   pv = moon98(2400000.5, 43999.9)

   @test pv[1][1] ≈ -0.2601295959971044180e-2 atol=1e-11
   @test pv[1][2] ≈ 0.6139750944302742189e-3 atol=1e-11
   @test pv[1][3] ≈ 0.2640794528229828909e-3 atol=1e-11

   @test pv[2][1] ≈ -0.1244321506649895021e-3 atol=1e-11
   @test pv[2][2] ≈ -0.5219076942678119398e-3 atol=1e-11
   @test pv[2][3] ≈ -0.1716132214378462047e-3 atol=1e-11
end


text:
module ReverseGeocode

using ZipFile
using CSV
using NearestNeighbors
using Logging

export Geocoder, decode

include("geocoder.jl")

end


text:
# This file is a part of Julia. License is MIT: https://julialang.org/license

# Content in this file is extracted from BinaryProvider.jl, see LICENSE.method

module PlatformEngines

using SHA, Downloads, Tar
import ...Pkg: Pkg, TOML, pkg_server, depots1, can_fancyprint, stderr_f
using ..MiniProgressBars
using Base.BinaryPlatforms, p7zip_jll

export verify, unpack, package, download_verify_unpack

const EXE7Z_LOCK = ReentrantLock()
const EXE7Z = Ref{String}()

function exe7z()
    # If the JLL is available, use the wrapper function defined in there
    if p7zip_jll.is_available()
        return p7zip_jll.p7zip()
    end

    lock(EXE7Z_LOCK) do
        if !isassigned(EXE7Z)
            EXE7Z[] = find7z()
        end
        return Cmd([EXE7Z[]])
    end
end

function find7z()
    name = "7z"
    Sys.iswindows() && (name = "$name.exe")
    for dir in (joinpath("..", "libexec"), ".")
        path = normpath(Sys.BINDIR::String, dir, name)
        isfile(path) && return path
    end
    path = Sys.which(name)
    path !== nothing && return path
    error("7z binary not found")
end

is_secure_url(url::AbstractString) =
    occursin(r"^(https://|\w+://(127\.0\.0\.1|localhost)(:\d+)?($|/))"i, url)

function get_server_dir(
    url :: AbstractString,
    server :: Union{AbstractString, Nothing} = pkg_server(),
)
    server === nothing && return
    url == server || startswith(url, "$server/") || return
    m = match(r"^\w+://([^\\/]+)(?:$|/)", server)
    if m === nothing
        @warn "malformed Pkg server value" server
        return
    end
    isempty(Base.DEPOT_PATH) && return
    joinpath(depots1(), "servers", String(m.captures[1]))
end

const AUTH_ERROR_HANDLERS = Pair{Union{String, Regex},Any}[]

function handle_auth_error(url, err; verbose::Bool = false)
    handled, should_retry = false, false
    for (scheme, handler) in AUTH_ERROR_HANDLERS
        occursin(scheme, url) || continue
        handled, should_retry = handler(url, pkg_server(), err)
        handled && break
    end
    handled && should_retry && return get_auth_header(url; verbose = verbose)
    return nothing
end

"""
    register_auth_error_handler(urlscheme::Union{AbstractString, Regex}, f)

Registers `f` as the topmost handler for failures in package server authentication.

A handler is only invoked if `occursin(urlscheme, url)` is true (where `url` is the URL Pkg
is currently trying to download.)

`f` must be a function that takes three input arguments `(url, pkgserver, err)`, where `url` is the
URL currently being downloaded, `pkgserver = Pkg.pkg_server()` the current package server, and
`err` is one of `no-auth-file`, `insecure-connection`, `malformed-file`, `no-access-token`,
`no-refresh-key` or `insecure-refresh-url`.

The handler `f` needs to return a tuple of `Bool`s `(handled, should_retry)`. If `handled` is `false`,
the next handler in the stack will be called, otherwise handling terminates; `get_auth_header` is called again if `should_retry`
is `true`.

`register_auth_error_handler` returns a zero-arg function that can be called to deregister the handler.
"""
function register_auth_error_handler(urlscheme::Union{AbstractString, Regex}, @nospecialize(f))
    unique!(pushfirst!(AUTH_ERROR_HANDLERS, urlscheme => f))
    return () -> deregister_auth_error_handler(urlscheme, f)
end

"""
    deregister_auth_error_handler(urlscheme::Union{AbstractString, Regex}, f)

Removes `f` from the stack of authentication error handlers.
"""
function deregister_auth_error_handler(urlscheme::Union{String, Regex}, @nospecialize(f))
    filter!(handler -> !(handler.first == urlscheme && handler.second === f), AUTH_ERROR_HANDLERS)
    return nothing
end

function get_auth_header(url::AbstractString; verbose::Bool = false)
    server_dir = get_server_dir(url)
    server_dir === nothing && return
    auth_file = joinpath(server_dir, "auth.toml")
    isfile(auth_file) || return handle_auth_error(url, "no-auth-file"; verbose=verbose)
    # TODO: check for insecure auth file permissions
    if !is_secure_url(url)
        @warn "refusing to send auth info over insecure connection" url=url
        return handle_auth_error(url, "insecure-connection"; verbose=verbose)
    end
    # parse the auth file
    auth_info = try
        TOML.parsefile(auth_file)
    catch err
        @error "malformed auth file" file=auth_file err=err
        return handle_auth_error(url, "malformed-file"; verbose=verbose)
    end
    # check for an auth token
    if !haskey(auth_info, "access_token")
        @warn "auth file without access_token field" file=auth_file
        return handle_auth_error(url, "no-access-token"; verbose=verbose)
    end
    auth_token = auth_info["access_token"]::String
    auth_header = "Authorization" => "Bearer $auth_token"
    # handle token expiration and refresh
    expires_at = Inf
    if haskey(auth_info, "expires_at")
        expires_at = min(expires_at, Float64(auth_info["expires_at"])::Float64)
    end
    if haskey(auth_info, "expires_in")
        expires_at = min(expires_at, mtime(auth_file) + Float64(auth_info["expires_in"])::Float64)
    end
    # if token is good until ten minutes from now, use it
    time_now = time()
    if expires_at ≥ time_now + 10*60 # ten minutes
        return auth_header
    end
    if !haskey(auth_info, "refresh_url") || !haskey(auth_info, "refresh_token")
        if expires_at ≤ time_now
            @warn "expired auth without refresh keys" file=auth_file
        end
        # try it anyway since we can't refresh
        return something(handle_auth_error(url, "no-refresh-key"; verbose=verbose), auth_header)
    end
    refresh_url = auth_info["refresh_url"]::String
    if !is_secure_url(refresh_url)
        @warn "ignoring insecure auth refresh URL" url=refresh_url
        return something(handle_auth_error(url, "insecure-refresh-url"; verbose=verbose), auth_header)
    end
    verbose && @info "Refreshing expired auth token..." file=auth_file
    tmp = tempname()
    refresh_token = auth_info["refresh_token"]::String
    refresh_auth = "Authorization" => "Bearer $refresh_token"
    try download(refresh_url, tmp, auth_header=refresh_auth, verbose=verbose)
    catch err
        @warn "token refresh failure" file=auth_file url=refresh_url err=err
        rm(tmp, force=true)
        return handle_auth_error(url, "token-refresh-failed"; verbose=verbose)
    end
    auth_info = try TOML.parsefile(tmp)
    catch err
        @warn "discarding malformed auth file" url=refresh_url err=err
        rm(tmp, force=true)
        return something(handle_auth_error(url, "malformed-file"; verbose=verbose), auth_header)
    end
    if !haskey(auth_info, "access_token")
        if haskey(auth_info, "refresh_token")
            auth_info["refresh_token"] = "*"^64
        end
        @warn "discarding auth file without access token" auth=auth_info
        rm(tmp, force=true)
        return something(handle_auth_error(url, "no-access-token"; verbose=verbose), auth_header)
    end
    if haskey(auth_info, "expires_in")
        expires_in = auth_info["expires_in"]
        if expires_in isa Number
            expires_at = floor(time_now + Float64(expires_in)::Float64)
            # overwrite expires_at (avoids clock skew issues)
            auth_info["expires_at"] = expires_at
        end
    end
    let auth_info = auth_info
        open(tmp, write=true) do io
            TOML.print(io, auth_info, sorted=true)
        end
    end
    mv(tmp, auth_file, force=true)
    access_token = auth_info["access_token"]::String
    return "Authorization" => "Bearer $access_token"
end

# based on information in this post:
# https://github.community/t5/GitHub-Actions/Have-the-CI-environment-variable-set-by-default/m-p/32358/highlight/true#M1097
const CI_VARIABLES = [
    "APPVEYOR",
    "CI",
    "CI_SERVER",
    "CIRCLECI",
    "CONTINUOUS_INTEGRATION",
    "GITHUB_ACTIONS",
    "GITLAB_CI",
    "JULIA_CI",
    "JULIA_PKGEVAL",
    "JULIA_REGISTRYCI_AUTOMERGE",
    "TF_BUILD",
    "TRAVIS",
]

function get_metadata_headers(url::AbstractString)
    headers = Pair{String,String}[]
    server = pkg_server()
    server_dir = get_server_dir(url, server)
    server_dir === nothing && return headers
    push!(headers, "Julia-Pkg-Protocol" => "1.0")
    push!(headers, "Julia-Pkg-Server" => server)
    push!(headers, "Julia-Version" => string(VERSION))
    system = triplet(HostPlatform())
    push!(headers, "Julia-System" => system)
    ci_info = String[]
    for var in CI_VARIABLES
        val = get(ENV, var, nothing)
        state = val === nothing ? "n" :
            lowercase(val) in ("true", "t", "1", "yes", "y") ? "t" :
            lowercase(val) in ("false", "f", "0", "no", "n") ? "f" : "o"
        push!(ci_info, "$var=$state")
    end
    push!(headers, "Julia-CI-Variables" => join(ci_info, ';'))
    push!(headers, "Julia-Interactive" => string(isinteractive()))
    for (key, val) in ENV
        m = match(r"^JULIA_PKG_SERVER_([A-Z0-9_]+)$"i, key)
        m === nothing && continue
        val = strip(val)
        isempty(val) && continue
        words = split(m.captures[1], '_', keepempty=false)
        isempty(words) && continue
        hdr = "Julia-" * join(map(titlecase, words), '-')
        any(hdr == k for (k, v) in headers) && continue
        push!(headers, hdr => val)
    end
    return headers
end

function download(
    url::AbstractString,
    dest::AbstractString;
    verbose::Bool = false,
    headers::Vector{Pair{String,String}} = Pair{String,String}[],
    auth_header::Union{Pair{String,String}, Nothing} = nothing,
    io::IO=stderr_f()
)
    if auth_header === nothing
        auth_header = get_auth_header(url, verbose=verbose)
    end
    if auth_header !== nothing
        push!(headers, auth_header)
    end
    for header in get_metadata_headers(url)
        push!(headers, header)
    end

    do_fancy = verbose && can_fancyprint(io)
    progress = if do_fancy
        bar = MiniProgressBar(header="Downloading", color=Base.info_color())
        start_progress(io, bar)
        (total, now) -> begin
            bar.max = total
            bar.current = now
            show_progress(io, bar)
        end
    else
        (total, now) -> nothing
    end
    try
        Downloads.download(url, dest; headers, progress)
    finally
        do_fancy && end_progress(io, bar)
    end
end

"""
    download_verify(
        url::AbstractString,
        hash::Union{AbstractString, Nothing},
        dest::AbstractString;
        verbose::Bool = false,
        force::Bool = false,
        quiet_download::Bool = false,
    )

Download file located at `url`, verify it matches the given `hash`, and throw
an error if anything goes wrong.  If `dest` already exists, just verify it. If
`force` is set to `true`, overwrite the given file if it exists but does not
match the given `hash`.

This method returns `true` if the file was downloaded successfully, `false`
if an existing file was removed due to the use of `force`, and throws an error
if `force` is not set and the already-existent file fails verification, or if
`force` is set, verification fails, and then verification fails again after
redownloading the file.

If `quiet_download` is set to `false`, this method will print to
stdout when downloading a new file.  If it is set to `true` (default, and `verbose` is
set to `false`) the downloading process will be completely silent.  If
`verbose` is set to `true`, messages about integrity verification will be
printed in addition to messages regarding downloading.
"""
function download_verify(
    url::AbstractString,
    hash::Union{AbstractString, Nothing},
    dest::AbstractString;
    verbose::Bool = false,
    force::Bool = false,
    quiet_download::Bool = false,
)
    # Whether the file existed in the first place
    file_existed = false

    if isfile(dest)
        file_existed = true
        if verbose
            @info("Destination file $(dest) already exists, verifying...")
        end

        # verify download, if it passes, return happy.  If it fails, (and
        # `force` is `true`, re-download!)
        if hash !== nothing && verify(dest, hash; verbose=verbose)
            return true
        elseif !force
            error("Verification failed, not overwriting $(dest)")
        end
    end

    # Make sure the containing folder exists
    mkpath(dirname(dest))

    # Download the file, optionally continuing
    download(url, dest; verbose=verbose || !quiet_download)
    if hash !== nothing && !verify(dest, hash; verbose=verbose)
        # If the file already existed, it's possible the initially downloaded chunk
        # was bad.  If verification fails after downloading, auto-delete the file
        # and start over from scratch.
        if file_existed
            if verbose
                @info("Continued download didn't work, restarting from scratch")
            end
            Base.rm(dest; force=true)

            # Download and verify from scratch
            download(url, dest; verbose=verbose || !quiet_download)
            if hash !== nothing && !verify(dest, hash; verbose=verbose)
                error("Verification failed")
            end
        else
            # If it didn't verify properly and we didn't resume, something is
            # very wrong and we must complain mightily.
            error("Verification failed")
        end
    end

    # If the file previously existed, this means we removed it (due to `force`)
    # and redownloaded, so return `false`.  If it didn't exist, then this means
    # that we successfully downloaded it, so return `true`.
    return !file_existed
end

# TODO: can probably delete this, only affects tests
function copy_symlinks()
    var = get(ENV, "BINARYPROVIDER_COPYDEREF", "")
    lowercase(var) in ("true", "t", "yes", "y", "1") ? true :
    lowercase(var) in ("false", "f", "no", "n", "0") ? false : nothing
end

function unpack(
    tarball_path::AbstractString,
    dest::AbstractString;
    verbose::Bool = false,
)
    Tar.extract(`$(exe7z()) x $tarball_path -so`, dest, copy_symlinks = copy_symlinks())
end

"""
    package(src_dir::AbstractString, tarball_path::AbstractString)

Compress `src_dir` into a tarball located at `tarball_path`.
"""
function package(src_dir::AbstractString, tarball_path::AbstractString)
    rm(tarball_path, force=true)
    cmd = `$(exe7z()) a -si -tgzip -mx9 $tarball_path`
    open(pipeline(cmd, stdout=devnull), write=true) do io
        Tar.create(src_dir, io)
    end
end

"""
    download_verify_unpack(
        url::AbstractString,
        hash::Union{AbstractString, Nothing},
        dest::AbstractString;
        tarball_path = nothing,
        ignore_existence::Bool = false,
        force::Bool = false,
        verbose::Bool = false,
        quiet_download::Bool = false,
        io::IO=stderr,
    )

Helper method to download tarball located at `url`, verify it matches the
given `hash`, then unpack it into folder `dest`.  In general, the method
`install()` should be used to download and install tarballs into a `Prefix`;
this method should only be used if the extra functionality of `install()` is
undesired.

If `tarball_path` is specified, the given `url` will be downloaded to
`tarball_path`, and it will not be removed after downloading and verification
is complete.  If it is not specified, the tarball will be downloaded to a
temporary location, and removed after verification is complete.

If `force` is specified, a verification failure will cause `tarball_path` to be
deleted (if it exists), the `dest` folder to be removed (if it exists) and the
tarball to be redownloaded and reverified.  If the verification check is failed
a second time, an exception is raised.  If `force` is not specified, a
verification failure will result in an immediate raised exception.

If `ignore_existence` is set, the tarball is unpacked even if the destination
directory already exists.

Returns `true` if a tarball was actually unpacked, `false` if nothing was
changed in the destination prefix.
"""
function download_verify_unpack(
    url::AbstractString,
    hash::Union{AbstractString, Nothing},
    dest::AbstractString;
    tarball_path = nothing,
    ignore_existence::Bool = false,
    force::Bool = false,
    verbose::Bool = false,
    quiet_download::Bool = false,
    io::IO=stderr_f(),
)
    # First, determine whether we should keep this tarball around
    remove_tarball = false
    if tarball_path === nothing
        remove_tarball = true

        function url_ext(url)
            url = basename(url)

            # Chop off urlparams
            qidx = findfirst(isequal('?'), url)
            if qidx !== nothing
                url = url[1:qidx]
            end

            # Try to detect extension
            dot_idx = findlast(isequal('.'), url)
            if dot_idx === nothing
                return nothing
            end

            return url[dot_idx+1:end]
        end

        # If extension of url contains a recognized extension, use it, otherwise use ".gz"
        ext = url_ext(url)
        if !(ext in ["tar", "gz", "tgz", "bz2", "xz"])
            ext = "gz"
        end

        # Work around windows limitations regarding tempname()
        tarball_path = "$(tempname())-download.$(ext)"
        tries = 0
        while isfile(tarball_path) && tries < 100
            tarball_path = "$(tempname())-download.$(ext)"
            tries += 1
        end
        if tries >= 100
            error("Unable to generate unused tempname! Clean up your temporary folder $(dirname(tempname())) and try again.")
        end
    end

    # Download the tarball; if it already existed and we needed to remove it
    # then we should remove the unpacked path as well
    should_delete = !download_verify(url, hash, tarball_path;
                                     force=force, verbose=verbose, quiet_download=quiet_download)
    if should_delete
        if verbose
            @info("Removing dest directory $(dest) as source tarball changed")
        end
        Base.rm(dest; recursive=true, force=true)
    end

    # If the destination path already exists, don't bother to unpack
    if !ignore_existence && isdir(dest)
        if verbose
            @info("Destination directory $(dest) already exists, returning")
        end

        # Signify that we didn't do any unpacking
        return false
    end

    try
        if verbose
            @info("Unpacking $(tarball_path) into $(dest)...")
        end
        open(`$(exe7z()) x $tarball_path -so`) do io
            Tar.extract(io, dest, copy_symlinks = copy_symlinks())
        end
    finally
        if remove_tarball
            Base.rm(tarball_path)
            # Remove cached tarball hash, if it exists.
            Base.rm(string(tarball_path, ".sha256"); force=true)
        end
    end

    # Signify that we did some unpacking!
    return true
end

"""
    verify(path::AbstractString, hash::AbstractString;
           verbose::Bool = false, report_cache_status::Bool = false)

Given a file `path` and a `hash`, calculate the SHA256 of the file and compare
it to `hash`.  This method caches verification results in a `"\$(path).sha256"`
file to accelerate reverification of files that have been previously verified.
If no `".sha256"` file exists, a full verification will be done and the file
will be created, with the calculated hash being stored within the `".sha256"`
file.  If a `".sha256"` file does exist, its contents are checked to ensure
that the hash contained within matches the given `hash` parameter, and its
modification time shows that the file located at `path` has not been modified
since the last verification.

If `report_cache_status` is set to `true`, then the return value will be a
`Symbol` giving a granular status report on the state of the hash cache, in
addition to the `true`/`false` signifying whether verification completed
successfully.
"""
function verify(path::AbstractString, hash::AbstractString; verbose::Bool = false,
                report_cache_status::Bool = false, hash_path::AbstractString="$(path).sha256")

    # Check hash string format
    if !occursin(r"^[0-9a-f]{64}$"i, hash)
        msg = "Hash value must be 64 hexadecimal characters (256 bits), "
        if !isascii(hash)
            msg *= "given hash value is non-ASCII"
        elseif occursin(r"^[0-9a-f]*$"i, hash)
            msg *= "given hash value has the wrong length ($(length(hash)))"
        else
            msg *= "given hash value contains non-hexadecimal characters"
        end
        msg *= ": $(repr(hash))"
        error(msg)
    end
    hash = lowercase(hash)

    # Check to see if the hash cache is consistent
    status = :hash_consistent

    # First, it must exist
    if isfile(hash_path)
        # Next, it must contain the same hash as what we're verifying against
        if read(hash_path, String) == hash
            # Next, it must be no older than the actual path
            if stat(hash_path).mtime >= stat(path).mtime
                # If all of that is true, then we're good!
                if verbose
                    @info("Hash cache is consistent, returning true")
                end
                status = :hash_cache_consistent

                # If we're reporting our status, then report it!
                if report_cache_status
                    return true, status
                else
                    return true
                end
            else
                if verbose
                    @info("File has been modified, hash cache invalidated")
                end
                status = :file_modified
            end
        else
            if verbose
                @info("Verification hash mismatch, hash cache invalidated")
            end
            status = :hash_cache_mismatch
        end
    else
        if verbose
            @info("No hash cache found")
        end
        status = :hash_cache_missing
    end

    calc_hash = open(path) do file
        bytes2hex(sha256(file))
    end
    @assert occursin(r"^[0-9a-f]{64}$", calc_hash)

    if verbose
        @info("Calculated hash $calc_hash for file $path")
    end

    if calc_hash != hash
        msg  = "Hash Mismatch!\n"
        msg *= "  Expected sha256:   $hash\n"
        msg *= "  Calculated sha256: $calc_hash"
        @error(msg)
        if report_cache_status
            return false, :hash_mismatch
        else
            return false
        end
    end

    # Try to save a hash cache if everything worked out fine
    try
        open(hash_path, "w") do file
            write(file, hash)
        end
    catch e
        if isa(e, InterruptException)
            rethrow(e)
        end

        if verbose
            @warn("Unable to create hash cache file $(hash_path)")
        end
    end

    if report_cache_status
        return true, status
    else
        return true
    end
end

end # module PlatformEngines