text:
# This file is auto-generated by AWSMetadata.jl
using AWS
using AWS.AWSServices: medialive
using AWS.Compat
using AWS.UUIDs
"""
    AcceptInputDeviceTransfer()

Accept an incoming input device transfer. The ownership of the device will transfer to your AWS account.

# Required Parameters
- `inputDeviceId`: The unique ID of the input device to accept. For example, hd-123456789abcdef.

"""

accept_input_device_transfer(inputDeviceId; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/inputDevices/$(inputDeviceId)/accept"; aws_config=aws_config)
accept_input_device_transfer(inputDeviceId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/inputDevices/$(inputDeviceId)/accept", args; aws_config=aws_config)

"""
    BatchDelete()

Starts delete of resources.

# Optional Parameters
- `channelIds`: List of channel IDs
- `inputIds`: List of input IDs
- `inputSecurityGroupIds`: List of input security group IDs
- `multiplexIds`: List of multiplex IDs
"""

batch_delete(; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/batch/delete"; aws_config=aws_config)
batch_delete(args::AbstractDict{String, Any}; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/batch/delete", args; aws_config=aws_config)

"""
    BatchStart()

Starts existing resources

# Optional Parameters
- `channelIds`: List of channel IDs
- `multiplexIds`: List of multiplex IDs
"""

batch_start(; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/batch/start"; aws_config=aws_config)
batch_start(args::AbstractDict{String, Any}; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/batch/start", args; aws_config=aws_config)

"""
    BatchStop()

Stops running resources

# Optional Parameters
- `channelIds`: List of channel IDs
- `multiplexIds`: List of multiplex IDs
"""

batch_stop(; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/batch/stop"; aws_config=aws_config)
batch_stop(args::AbstractDict{String, Any}; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/batch/stop", args; aws_config=aws_config)

"""
    BatchUpdateSchedule()

Update a channel schedule

# Required Parameters
- `channelId`: Id of the channel whose schedule is being updated.

# Optional Parameters
- `creates`: Schedule actions to create in the schedule.
- `deletes`: Schedule actions to delete from the schedule.
"""

batch_update_schedule(channelId; aws_config::AWSConfig=global_aws_config()) = medialive("PUT", "/prod/channels/$(channelId)/schedule"; aws_config=aws_config)
batch_update_schedule(channelId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("PUT", "/prod/channels/$(channelId)/schedule", args; aws_config=aws_config)

"""
    CancelInputDeviceTransfer()

Cancel an input device transfer that you have requested.

# Required Parameters
- `inputDeviceId`: The unique ID of the input device to cancel. For example, hd-123456789abcdef.

"""

cancel_input_device_transfer(inputDeviceId; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/inputDevices/$(inputDeviceId)/cancel"; aws_config=aws_config)
cancel_input_device_transfer(inputDeviceId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/inputDevices/$(inputDeviceId)/cancel", args; aws_config=aws_config)

"""
    CreateChannel()

Creates a new channel

# Optional Parameters
- `cdiInputSpecification`: Specification of CDI inputs for this channel
- `channelClass`: The class for this channel. STANDARD for a channel with two pipelines or SINGLE_PIPELINE for a channel with one pipeline.
- `destinations`:
- `encoderSettings`:
- `inputAttachments`: List of input attachments for channel.
- `inputSpecification`: Specification of network and file inputs for this channel
- `logLevel`: The log level to write to CloudWatch Logs.
- `name`: Name of channel.
- `requestId`: Unique request ID to be specified. This is needed to prevent retries from
creating multiple resources.

- `reserved`: Deprecated field that's only usable by whitelisted customers.
- `roleArn`: An optional Amazon Resource Name (ARN) of the role to assume when running the Channel.
- `tags`: A collection of key-value pairs.
"""

create_channel(; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/channels", Dict{String, Any}("requestId"=>string(uuid4())); aws_config=aws_config)
create_channel(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/channels", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("requestId"=>string(uuid4())), args)); aws_config=aws_config)

"""
    CreateInput()

Create an input

# Optional Parameters
- `destinations`: Destination settings for PUSH type inputs.
- `inputDevices`: Settings for the devices.
- `inputSecurityGroups`: A list of security groups referenced by IDs to attach to the input.
- `mediaConnectFlows`: A list of the MediaConnect Flows that you want to use in this input. You can specify as few as one
Flow and presently, as many as two. The only requirement is when you have more than one is that each Flow is in a
separate Availability Zone as this ensures your EML input is redundant to AZ issues.

- `name`: Name of the input.
- `requestId`: Unique identifier of the request to ensure the request is handled
exactly once in case of retries.

- `roleArn`: The Amazon Resource Name (ARN) of the role this input assumes during and after creation.
- `sources`: The source URLs for a PULL-type input. Every PULL type input needs
exactly two source URLs for redundancy.
Only specify sources for PULL type Inputs. Leave Destinations empty.

- `tags`: A collection of key-value pairs.
- `type`:
- `vpc`:
"""

create_input(; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/inputs", Dict{String, Any}("requestId"=>string(uuid4())); aws_config=aws_config)
create_input(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/inputs", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("requestId"=>string(uuid4())), args)); aws_config=aws_config)

"""
    CreateInputSecurityGroup()

Creates a Input Security Group

# Optional Parameters
- `tags`: A collection of key-value pairs.
- `whitelistRules`: List of IPv4 CIDR addresses to whitelist
"""

create_input_security_group(; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/inputSecurityGroups"; aws_config=aws_config)
create_input_security_group(args::AbstractDict{String, Any}; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/inputSecurityGroups", args; aws_config=aws_config)

"""
    CreateMultiplex()

Create a new multiplex.

# Required Parameters
- `availabilityZones`: A list of availability zones for the multiplex. You must specify exactly two.
- `multiplexSettings`: Configuration for a multiplex event.
- `name`: Name of multiplex.
- `requestId`: Unique request ID. This prevents retries from creating multiple
resources.

# Optional Parameters
- `tags`: A collection of key-value pairs.
"""

create_multiplex(availabilityZones, multiplexSettings, name, requestId; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/multiplexes", Dict{String, Any}("availabilityZones"=>availabilityZones, "multiplexSettings"=>multiplexSettings, "name"=>name, "requestId"=>requestId); aws_config=aws_config)
create_multiplex(availabilityZones, multiplexSettings, name, requestId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/multiplexes", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("availabilityZones"=>availabilityZones, "multiplexSettings"=>multiplexSettings, "name"=>name, "requestId"=>requestId), args)); aws_config=aws_config)

"""
    CreateMultiplexProgram()

Create a new program in the multiplex.

# Required Parameters
- `multiplexId`: ID of the multiplex where the program is to be created.
- `multiplexProgramSettings`: The settings for this multiplex program.
- `programName`: Name of multiplex program.
- `requestId`: Unique request ID. This prevents retries from creating multiple
resources.

"""

create_multiplex_program(multiplexId, multiplexProgramSettings, programName, requestId; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/multiplexes/$(multiplexId)/programs", Dict{String, Any}("multiplexProgramSettings"=>multiplexProgramSettings, "programName"=>programName, "requestId"=>requestId); aws_config=aws_config)
create_multiplex_program(multiplexId, multiplexProgramSettings, programName, requestId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/multiplexes/$(multiplexId)/programs", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("multiplexProgramSettings"=>multiplexProgramSettings, "programName"=>programName, "requestId"=>requestId), args)); aws_config=aws_config)

"""
    CreateTags()

Create tags for a resource

# Required Parameters
- `resource-arn`:

# Optional Parameters
- `tags`:
"""

create_tags(resource_arn; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/tags/$(resource-arn)"; aws_config=aws_config)
create_tags(resource_arn, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/tags/$(resource-arn)", args; aws_config=aws_config)

"""
    DeleteChannel()

Starts deletion of channel. The associated outputs are also deleted.

# Required Parameters
- `channelId`: Unique ID of the channel.

"""

delete_channel(channelId; aws_config::AWSConfig=global_aws_config()) = medialive("DELETE", "/prod/channels/$(channelId)"; aws_config=aws_config)
delete_channel(channelId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("DELETE", "/prod/channels/$(channelId)", args; aws_config=aws_config)

"""
    DeleteInput()

Deletes the input end point

# Required Parameters
- `inputId`: Unique ID of the input

"""

delete_input(inputId; aws_config::AWSConfig=global_aws_config()) = medialive("DELETE", "/prod/inputs/$(inputId)"; aws_config=aws_config)
delete_input(inputId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("DELETE", "/prod/inputs/$(inputId)", args; aws_config=aws_config)

"""
    DeleteInputSecurityGroup()

Deletes an Input Security Group

# Required Parameters
- `inputSecurityGroupId`: The Input Security Group to delete

"""

delete_input_security_group(inputSecurityGroupId; aws_config::AWSConfig=global_aws_config()) = medialive("DELETE", "/prod/inputSecurityGroups/$(inputSecurityGroupId)"; aws_config=aws_config)
delete_input_security_group(inputSecurityGroupId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("DELETE", "/prod/inputSecurityGroups/$(inputSecurityGroupId)", args; aws_config=aws_config)

"""
    DeleteMultiplex()

Delete a multiplex. The multiplex must be idle.

# Required Parameters
- `multiplexId`: The ID of the multiplex.

"""

delete_multiplex(multiplexId; aws_config::AWSConfig=global_aws_config()) = medialive("DELETE", "/prod/multiplexes/$(multiplexId)"; aws_config=aws_config)
delete_multiplex(multiplexId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("DELETE", "/prod/multiplexes/$(multiplexId)", args; aws_config=aws_config)

"""
    DeleteMultiplexProgram()

Delete a program from a multiplex.

# Required Parameters
- `multiplexId`: The ID of the multiplex that the program belongs to.
- `programName`: The multiplex program name.

"""

delete_multiplex_program(multiplexId, programName; aws_config::AWSConfig=global_aws_config()) = medialive("DELETE", "/prod/multiplexes/$(multiplexId)/programs/$(programName)"; aws_config=aws_config)
delete_multiplex_program(multiplexId, programName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("DELETE", "/prod/multiplexes/$(multiplexId)/programs/$(programName)", args; aws_config=aws_config)

"""
    DeleteReservation()

Delete an expired reservation.

# Required Parameters
- `reservationId`: Unique reservation ID, e.g. '1234567'

"""

delete_reservation(reservationId; aws_config::AWSConfig=global_aws_config()) = medialive("DELETE", "/prod/reservations/$(reservationId)"; aws_config=aws_config)
delete_reservation(reservationId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("DELETE", "/prod/reservations/$(reservationId)", args; aws_config=aws_config)

"""
    DeleteSchedule()

Delete all schedule actions on a channel.

# Required Parameters
- `channelId`: Id of the channel whose schedule is being deleted.

"""

delete_schedule(channelId; aws_config::AWSConfig=global_aws_config()) = medialive("DELETE", "/prod/channels/$(channelId)/schedule"; aws_config=aws_config)
delete_schedule(channelId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("DELETE", "/prod/channels/$(channelId)/schedule", args; aws_config=aws_config)

"""
    DeleteTags()

Removes tags for a resource

# Required Parameters
- `resource-arn`:
- `tagKeys`: An array of tag keys to delete

"""

delete_tags(resource_arn, tagKeys; aws_config::AWSConfig=global_aws_config()) = medialive("DELETE", "/prod/tags/$(resource-arn)", Dict{String, Any}("tagKeys"=>tagKeys); aws_config=aws_config)
delete_tags(resource_arn, tagKeys, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("DELETE", "/prod/tags/$(resource-arn)", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("tagKeys"=>tagKeys), args)); aws_config=aws_config)

"""
    DescribeChannel()

Gets details about a channel

# Required Parameters
- `channelId`: channel ID

"""

describe_channel(channelId; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/channels/$(channelId)"; aws_config=aws_config)
describe_channel(channelId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/channels/$(channelId)", args; aws_config=aws_config)

"""
    DescribeInput()

Produces details about an input

# Required Parameters
- `inputId`: Unique ID of the input

"""

describe_input(inputId; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/inputs/$(inputId)"; aws_config=aws_config)
describe_input(inputId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/inputs/$(inputId)", args; aws_config=aws_config)

"""
    DescribeInputDevice()

Gets the details for the input device

# Required Parameters
- `inputDeviceId`: The unique ID of this input device. For example, hd-123456789abcdef.

"""

describe_input_device(inputDeviceId; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/inputDevices/$(inputDeviceId)"; aws_config=aws_config)
describe_input_device(inputDeviceId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/inputDevices/$(inputDeviceId)", args; aws_config=aws_config)

"""
    DescribeInputDeviceThumbnail()

Get the latest thumbnail data for the input device.

# Required Parameters
- `accept`: The HTTP Accept header. Indicates the requested type for the thumbnail.
- `inputDeviceId`: The unique ID of this input device. For example, hd-123456789abcdef.

"""

describe_input_device_thumbnail(accept, inputDeviceId; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/inputDevices/$(inputDeviceId)/thumbnailData", Dict{String, Any}("headers"=>Dict{String, Any}("accept"=>accept)); aws_config=aws_config)
describe_input_device_thumbnail(accept, inputDeviceId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/inputDevices/$(inputDeviceId)/thumbnailData", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("headers"=>Dict{String, Any}("accept"=>accept)), args)); aws_config=aws_config)

"""
    DescribeInputSecurityGroup()

Produces a summary of an Input Security Group

# Required Parameters
- `inputSecurityGroupId`: The id of the Input Security Group to describe

"""

describe_input_security_group(inputSecurityGroupId; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/inputSecurityGroups/$(inputSecurityGroupId)"; aws_config=aws_config)
describe_input_security_group(inputSecurityGroupId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/inputSecurityGroups/$(inputSecurityGroupId)", args; aws_config=aws_config)

"""
    DescribeMultiplex()

Gets details about a multiplex.

# Required Parameters
- `multiplexId`: The ID of the multiplex.

"""

describe_multiplex(multiplexId; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/multiplexes/$(multiplexId)"; aws_config=aws_config)
describe_multiplex(multiplexId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/multiplexes/$(multiplexId)", args; aws_config=aws_config)

"""
    DescribeMultiplexProgram()

Get the details for a program in a multiplex.

# Required Parameters
- `multiplexId`: The ID of the multiplex that the program belongs to.
- `programName`: The name of the program.

"""

describe_multiplex_program(multiplexId, programName; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/multiplexes/$(multiplexId)/programs/$(programName)"; aws_config=aws_config)
describe_multiplex_program(multiplexId, programName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/multiplexes/$(multiplexId)/programs/$(programName)", args; aws_config=aws_config)

"""
    DescribeOffering()

Get details for an offering.

# Required Parameters
- `offeringId`: Unique offering ID, e.g. '87654321'

"""

describe_offering(offeringId; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/offerings/$(offeringId)"; aws_config=aws_config)
describe_offering(offeringId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/offerings/$(offeringId)", args; aws_config=aws_config)

"""
    DescribeReservation()

Get details for a reservation.

# Required Parameters
- `reservationId`: Unique reservation ID, e.g. '1234567'

"""

describe_reservation(reservationId; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/reservations/$(reservationId)"; aws_config=aws_config)
describe_reservation(reservationId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/reservations/$(reservationId)", args; aws_config=aws_config)

"""
    DescribeSchedule()

Get a channel schedule

# Required Parameters
- `channelId`: Id of the channel whose schedule is being updated.

# Optional Parameters
- `maxResults`:
- `nextToken`:
"""

describe_schedule(channelId; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/channels/$(channelId)/schedule"; aws_config=aws_config)
describe_schedule(channelId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/channels/$(channelId)/schedule", args; aws_config=aws_config)

"""
    ListChannels()

Produces list of channels that have been created

# Optional Parameters
- `maxResults`:
- `nextToken`:
"""

list_channels(; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/channels"; aws_config=aws_config)
list_channels(args::AbstractDict{String, Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/channels", args; aws_config=aws_config)

"""
    ListInputDeviceTransfers()

List input devices that are currently being transferred. List input devices that you are transferring from your AWS account or input devices that another AWS account is transferring to you.

# Required Parameters
- `transferType`:

# Optional Parameters
- `maxResults`:
- `nextToken`:
"""

list_input_device_transfers(transferType; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/inputDeviceTransfers", Dict{String, Any}("transferType"=>transferType); aws_config=aws_config)
list_input_device_transfers(transferType, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/inputDeviceTransfers", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("transferType"=>transferType), args)); aws_config=aws_config)

"""
    ListInputDevices()

List input devices

# Optional Parameters
- `maxResults`:
- `nextToken`:
"""

list_input_devices(; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/inputDevices"; aws_config=aws_config)
list_input_devices(args::AbstractDict{String, Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/inputDevices", args; aws_config=aws_config)

"""
    ListInputSecurityGroups()

Produces a list of Input Security Groups for an account

# Optional Parameters
- `maxResults`:
- `nextToken`:
"""

list_input_security_groups(; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/inputSecurityGroups"; aws_config=aws_config)
list_input_security_groups(args::AbstractDict{String, Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/inputSecurityGroups", args; aws_config=aws_config)

"""
    ListInputs()

Produces list of inputs that have been created

# Optional Parameters
- `maxResults`:
- `nextToken`:
"""

list_inputs(; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/inputs"; aws_config=aws_config)
list_inputs(args::AbstractDict{String, Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/inputs", args; aws_config=aws_config)

"""
    ListMultiplexPrograms()

List the programs that currently exist for a specific multiplex.

# Required Parameters
- `multiplexId`: The ID of the multiplex that the programs belong to.

# Optional Parameters
- `maxResults`: The maximum number of items to return.
- `nextToken`: The token to retrieve the next page of results.
"""

list_multiplex_programs(multiplexId; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/multiplexes/$(multiplexId)/programs"; aws_config=aws_config)
list_multiplex_programs(multiplexId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/multiplexes/$(multiplexId)/programs", args; aws_config=aws_config)

"""
    ListMultiplexes()

Retrieve a list of the existing multiplexes.

# Optional Parameters
- `maxResults`: The maximum number of items to return.
- `nextToken`: The token to retrieve the next page of results.
"""

list_multiplexes(; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/multiplexes"; aws_config=aws_config)
list_multiplexes(args::AbstractDict{String, Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/multiplexes", args; aws_config=aws_config)

"""
    ListOfferings()

List offerings available for purchase.

# Optional Parameters
- `channelClass`: Filter by channel class, 'STANDARD' or 'SINGLE_PIPELINE'

- `channelConfiguration`: Filter to offerings that match the configuration of an existing channel, e.g. '2345678' (a channel ID)

- `codec`: Filter by codec, 'AVC', 'HEVC', 'MPEG2', 'AUDIO', or 'LINK'
- `duration`: Filter by offering duration, e.g. '12'
- `maxResults`:
- `maximumBitrate`: Filter by bitrate, 'MAX_10_MBPS', 'MAX_20_MBPS', or 'MAX_50_MBPS'

- `maximumFramerate`: Filter by framerate, 'MAX_30_FPS' or 'MAX_60_FPS'
- `nextToken`:
- `resolution`: Filter by resolution, 'SD', 'HD', 'FHD', or 'UHD'
- `resourceType`: Filter by resource type, 'INPUT', 'OUTPUT', 'MULTIPLEX', or 'CHANNEL'
- `specialFeature`: Filter by special feature, 'ADVANCED_AUDIO' or 'AUDIO_NORMALIZATION'

- `videoQuality`: Filter by video quality, 'STANDARD', 'ENHANCED', or 'PREMIUM'

"""

list_offerings(; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/offerings"; aws_config=aws_config)
list_offerings(args::AbstractDict{String, Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/offerings", args; aws_config=aws_config)

"""
    ListReservations()

List purchased reservations.

# Optional Parameters
- `channelClass`: Filter by channel class, 'STANDARD' or 'SINGLE_PIPELINE'

- `codec`: Filter by codec, 'AVC', 'HEVC', 'MPEG2', 'AUDIO', or 'LINK'
- `maxResults`:
- `maximumBitrate`: Filter by bitrate, 'MAX_10_MBPS', 'MAX_20_MBPS', or 'MAX_50_MBPS'

- `maximumFramerate`: Filter by framerate, 'MAX_30_FPS' or 'MAX_60_FPS'
- `nextToken`:
- `resolution`: Filter by resolution, 'SD', 'HD', 'FHD', or 'UHD'
- `resourceType`: Filter by resource type, 'INPUT', 'OUTPUT', 'MULTIPLEX', or 'CHANNEL'
- `specialFeature`: Filter by special feature, 'ADVANCED_AUDIO' or 'AUDIO_NORMALIZATION'

- `videoQuality`: Filter by video quality, 'STANDARD', 'ENHANCED', or 'PREMIUM'

"""

list_reservations(; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/reservations"; aws_config=aws_config)
list_reservations(args::AbstractDict{String, Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/reservations", args; aws_config=aws_config)

"""
    ListTagsForResource()

Produces list of tags that have been created for a resource

# Required Parameters
- `resource-arn`:

"""

list_tags_for_resource(resource_arn; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/tags/$(resource-arn)"; aws_config=aws_config)
list_tags_for_resource(resource_arn, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("GET", "/prod/tags/$(resource-arn)", args; aws_config=aws_config)

"""
    PurchaseOffering()

Purchase an offering and create a reservation.

# Required Parameters
- `count`: Number of resources
- `offeringId`: Offering to purchase, e.g. '87654321'

# Optional Parameters
- `name`: Name for the new reservation
- `requestId`: Unique request ID to be specified. This is needed to prevent retries from creating multiple resources.
- `start`: Requested reservation start time (UTC) in ISO-8601 format. The specified time must be between the first day of the current month and one year from now. If no value is given, the default is now.
- `tags`: A collection of key-value pairs
"""

purchase_offering(count, offeringId; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/offerings/$(offeringId)/purchase", Dict{String, Any}("count"=>count, "requestId"=>string(uuid4())); aws_config=aws_config)
purchase_offering(count, offeringId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/offerings/$(offeringId)/purchase", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("count"=>count, "requestId"=>string(uuid4())), args)); aws_config=aws_config)

"""
    RejectInputDeviceTransfer()

Reject the transfer of the specified input device to your AWS account.

# Required Parameters
- `inputDeviceId`: The unique ID of the input device to reject. For example, hd-123456789abcdef.

"""

reject_input_device_transfer(inputDeviceId; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/inputDevices/$(inputDeviceId)/reject"; aws_config=aws_config)
reject_input_device_transfer(inputDeviceId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/inputDevices/$(inputDeviceId)/reject", args; aws_config=aws_config)

"""
    StartChannel()

Starts an existing channel

# Required Parameters
- `channelId`: A request to start a channel

"""

start_channel(channelId; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/channels/$(channelId)/start"; aws_config=aws_config)
start_channel(channelId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/channels/$(channelId)/start", args; aws_config=aws_config)

"""
    StartMultiplex()

Start (run) the multiplex. Starting the multiplex does not start the channels. You must explicitly start each channel.

# Required Parameters
- `multiplexId`: The ID of the multiplex.

"""

start_multiplex(multiplexId; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/multiplexes/$(multiplexId)/start"; aws_config=aws_config)
start_multiplex(multiplexId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/multiplexes/$(multiplexId)/start", args; aws_config=aws_config)

"""
    StopChannel()

Stops a running channel

# Required Parameters
- `channelId`: A request to stop a running channel

"""

stop_channel(channelId; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/channels/$(channelId)/stop"; aws_config=aws_config)
stop_channel(channelId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/channels/$(channelId)/stop", args; aws_config=aws_config)

"""
    StopMultiplex()

Stops a running multiplex. If the multiplex isn't running, this action has no effect.

# Required Parameters
- `multiplexId`: The ID of the multiplex.

"""

stop_multiplex(multiplexId; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/multiplexes/$(multiplexId)/stop"; aws_config=aws_config)
stop_multiplex(multiplexId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/multiplexes/$(multiplexId)/stop", args; aws_config=aws_config)

"""
    TransferInputDevice()

Start an input device transfer to another AWS account. After you make the request, the other account must accept or reject the transfer.

# Required Parameters
- `inputDeviceId`: The unique ID of this input device. For example, hd-123456789abcdef.

# Optional Parameters
- `targetCustomerId`: The AWS account ID (12 digits) for the recipient of the device transfer.
- `transferMessage`: An optional message for the recipient. Maximum 280 characters.
"""

transfer_input_device(inputDeviceId; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/inputDevices/$(inputDeviceId)/transfer"; aws_config=aws_config)
transfer_input_device(inputDeviceId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("POST", "/prod/inputDevices/$(inputDeviceId)/transfer", args; aws_config=aws_config)

"""
    UpdateChannel()

Updates a channel.

# Required Parameters
- `channelId`: channel ID

# Optional Parameters
- `cdiInputSpecification`: Specification of CDI inputs for this channel
- `destinations`: A list of output destinations for this channel.
- `encoderSettings`: The encoder settings for this channel.
- `inputAttachments`:
- `inputSpecification`: Specification of network and file inputs for this channel
- `logLevel`: The log level to write to CloudWatch Logs.
- `name`: The name of the channel.
- `roleArn`: An optional Amazon Resource Name (ARN) of the role to assume when running the Channel. If you do not specify this on an update call but the role was previously set that role will be removed.
"""

update_channel(channelId; aws_config::AWSConfig=global_aws_config()) = medialive("PUT", "/prod/channels/$(channelId)"; aws_config=aws_config)
update_channel(channelId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("PUT", "/prod/channels/$(channelId)", args; aws_config=aws_config)

"""
    UpdateChannelClass()

Changes the class of the channel.

# Required Parameters
- `channelClass`: The channel class that you wish to update this channel to use.
- `channelId`: Channel Id of the channel whose class should be updated.

# Optional Parameters
- `destinations`: A list of output destinations for this channel.
"""

update_channel_class(channelClass, channelId; aws_config::AWSConfig=global_aws_config()) = medialive("PUT", "/prod/channels/$(channelId)/channelClass", Dict{String, Any}("channelClass"=>channelClass); aws_config=aws_config)
update_channel_class(channelClass, channelId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("PUT", "/prod/channels/$(channelId)/channelClass", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("channelClass"=>channelClass), args)); aws_config=aws_config)

"""
    UpdateInput()

Updates an input.

# Required Parameters
- `inputId`: Unique ID of the input.

# Optional Parameters
- `destinations`: Destination settings for PUSH type inputs.
- `inputDevices`: Settings for the devices.
- `inputSecurityGroups`: A list of security groups referenced by IDs to attach to the input.
- `mediaConnectFlows`: A list of the MediaConnect Flow ARNs that you want to use as the source of the input. You can specify as few as one
Flow and presently, as many as two. The only requirement is when you have more than one is that each Flow is in a
separate Availability Zone as this ensures your EML input is redundant to AZ issues.

- `name`: Name of the input.
- `roleArn`: The Amazon Resource Name (ARN) of the role this input assumes during and after creation.
- `sources`: The source URLs for a PULL-type input. Every PULL type input needs
exactly two source URLs for redundancy.
Only specify sources for PULL type Inputs. Leave Destinations empty.

"""

update_input(inputId; aws_config::AWSConfig=global_aws_config()) = medialive("PUT", "/prod/inputs/$(inputId)"; aws_config=aws_config)
update_input(inputId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("PUT", "/prod/inputs/$(inputId)", args; aws_config=aws_config)

"""
    UpdateInputDevice()

Updates the parameters for the input device.

# Required Parameters
- `inputDeviceId`: The unique ID of the input device. For example, hd-123456789abcdef.

# Optional Parameters
- `hdDeviceSettings`: The settings that you want to apply to the input device.
- `name`: The name that you assigned to this input device (not the unique ID).
"""

update_input_device(inputDeviceId; aws_config::AWSConfig=global_aws_config()) = medialive("PUT", "/prod/inputDevices/$(inputDeviceId)"; aws_config=aws_config)
update_input_device(inputDeviceId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("PUT", "/prod/inputDevices/$(inputDeviceId)", args; aws_config=aws_config)

"""
    UpdateInputSecurityGroup()

Update an Input Security Group's Whilelists.

# Required Parameters
- `inputSecurityGroupId`: The id of the Input Security Group to update.

# Optional Parameters
- `tags`: A collection of key-value pairs.
- `whitelistRules`: List of IPv4 CIDR addresses to whitelist
"""

update_input_security_group(inputSecurityGroupId; aws_config::AWSConfig=global_aws_config()) = medialive("PUT", "/prod/inputSecurityGroups/$(inputSecurityGroupId)"; aws_config=aws_config)
update_input_security_group(inputSecurityGroupId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("PUT", "/prod/inputSecurityGroups/$(inputSecurityGroupId)", args; aws_config=aws_config)

"""
    UpdateMultiplex()

Updates a multiplex.

# Required Parameters
- `multiplexId`: ID of the multiplex to update.

# Optional Parameters
- `multiplexSettings`: The new settings for a multiplex.
- `name`: Name of the multiplex.
"""

update_multiplex(multiplexId; aws_config::AWSConfig=global_aws_config()) = medialive("PUT", "/prod/multiplexes/$(multiplexId)"; aws_config=aws_config)
update_multiplex(multiplexId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("PUT", "/prod/multiplexes/$(multiplexId)", args; aws_config=aws_config)

"""
    UpdateMultiplexProgram()

Update a program in a multiplex.

# Required Parameters
- `multiplexId`: The ID of the multiplex of the program to update.
- `programName`: The name of the program to update.

# Optional Parameters
- `multiplexProgramSettings`: The new settings for a multiplex program.
"""

update_multiplex_program(multiplexId, programName; aws_config::AWSConfig=global_aws_config()) = medialive("PUT", "/prod/multiplexes/$(multiplexId)/programs/$(programName)"; aws_config=aws_config)
update_multiplex_program(multiplexId, programName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("PUT", "/prod/multiplexes/$(multiplexId)/programs/$(programName)", args; aws_config=aws_config)

"""
    UpdateReservation()

Update reservation.

# Required Parameters
- `reservationId`: Unique reservation ID, e.g. '1234567'

# Optional Parameters
- `name`: Name of the reservation
"""

update_reservation(reservationId; aws_config::AWSConfig=global_aws_config()) = medialive("PUT", "/prod/reservations/$(reservationId)"; aws_config=aws_config)
update_reservation(reservationId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = medialive("PUT", "/prod/reservations/$(reservationId)", args; aws_config=aws_config)


text:
export compile

#####################
## CompiledSystem  ##
#####################
const TSYSTEM_TABLE = Dict{
    UInt,
    Vector{Tuple{Vector{Expression},Vector{Variable},Vector{Variable}}},
}()

struct CompiledSystem{H,I}
    nexpressions::Int
    variables::Vector{Symbol}
    parameters::Vector{Symbol}
end

function CompiledSystem(
    exprs::Vector{Expression},
    var_order::Vector{Variable},
    param_order::Vector{Variable} = Variable[],
)
    val = (exprs, var_order, param_order)
    h = hash(val)

    n = length(exprs)
    vars = Symbol.(var_order)
    params = Symbol.(param_order)

    if haskey(TSYSTEM_TABLE, h)
        # check that it is identical
        for (i, vi) in enumerate(TSYSTEM_TABLE[h])
            if vi == val
                return CompiledSystem{h,i}(n, vars, params)
            end
        end
        push!(TSYSTEM_TABLE[h], val)
        return CompiledSystem{h,length(TSYSTEM_TABLE[h])}(n, vars, params)
    else
        TSYSTEM_TABLE[h] = [val]
        return CompiledSystem{h,1}(n, vars, params)
    end
end

function Base.show(io::IO, TS::CompiledSystem)
    print(io, "Compiled: ")
    show(io, interpret(TS))
end

interpret(TS::CompiledSystem) = interpret(typeof(TS))
interpret(::Type{CompiledSystem{H,I}}) where {H,I} =
    System(TSYSTEM_TABLE[H][I]...)

Base.size(CS::CompiledSystem) = (CS.nexpressions, length(CS.variables))
Base.size(CS::CompiledSystem, i::Integer) = size(CS)[i]
Base.length(CS::CompiledSystem) = CS.nexpressions

######################
## CompiledHomotopy ##
######################

const THOMOTOPY_TABLE = Dict{
    UInt,
    Vector{
        Tuple{Vector{Expression},Vector{Variable},Variable,Vector{Variable}},
    },
}()

struct CompiledHomotopy{H,I}
    nexpressions::Int
    variables::Vector{Symbol}
    parameters::Vector{Symbol}
end

function CompiledHomotopy(
    exprs::Vector{<:Expression},
    var_order::AbstractVector{<:Variable},
    t::Variable,
    param_order::AbstractVector{<:Variable} = Variable[],
)
    val = (exprs, var_order, t, param_order)
    h = hash(val)

    n = length(exprs)
    vars = Symbol.(var_order)
    params = Symbol.(param_order)

    if haskey(THOMOTOPY_TABLE, h)
    # check that it is identical
        for (i, vi) in enumerate(THOMOTOPY_TABLE[h])
            if vi == val
                return CompiledHomotopy{h,i}(n, vars, params)
            end
        end
        push!(THOMOTOPY_TABLE[h], val)
        return CompiledHomotopy{h,length(TSYSTEM_TABLE[h])}(n, vars, params)
    else
        THOMOTOPY_TABLE[h] = [val]
        return CompiledHomotopy{h,1}(n, vars, params)
    end
end

Base.size(CH::CompiledHomotopy) = (CH.nexpressions, length(CH.variables))
Base.size(CS::CompiledHomotopy, i::Integer) = size(CS)[i]
Base.length(CH::CompiledHomotopy) = CH.nexpressions

function Base.show(io::IO, TH::CompiledHomotopy)
    print(io, "Compiled: ")
    show(io, interpret(TH))
end

interpret(TH::CompiledHomotopy) = interpret(typeof(TH))
interpret(::Type{CompiledHomotopy{H,I}}) where {H,I} =
    Homotopy(THOMOTOPY_TABLE[H][I]...)

"""
    compile(F::System)

Compile the given system. Returns a `CompiledSystem`.
    compile(H::Homotopy)

Compile the given homotopy. Returns a `CompiledHomotopy`.
"""
compile(F::System) = CompiledSystem(F.expressions, F.variables, F.parameters)
compile(H::Homotopy) =
    CompiledHomotopy(H.expressions, H.variables, H.t, H.parameters)

#############
## CODEGEN ##
#############

boundscheck_var_map(F::System; kwargs...) =
    boundscheck_var_map(F.expressions, F.variables, F.parameters; kwargs...)
boundscheck_var_map(H::Homotopy; kwargs...) = boundscheck_var_map(
    H.expressions,
    H.variables,
    H.parameters,
    H.t;
    kwargs...,
)

function boundscheck_var_map(
    exprs,
    vars,
    params,
    t = nothing;
    jacobian::Bool = false,
)
    n = length(exprs)
    m = length(vars)
    l = length(params)
    var_map = Dict{Symbol,Union{Symbol,Expr}}()
    for i = 1:m
        var_map[Symbol(vars[i])] = :(x[$i])
    end
    for i = 1:l
        var_map[Symbol(params[i])] = :(p[$i])
    end
    if t !== nothing
        var_map[Symbol(t)] = :(t)
    end

    checks = Expr[]
    if jacobian
        push!(checks, :(@boundscheck checkbounds(U, 1:$n, 1:$m)))
    else
        push!(checks, :(@boundscheck checkbounds(u, 1:$n)))
    end
    push!(checks, :(@boundscheck checkbounds(x, 1:$m)))
    push!(checks, :(@boundscheck p === nothing || checkbounds(p, 1:$l)))

    Expr(:block, checks...), var_map
end

function _evaluate!_impl(
    ::Type{T},
) where {T<:Union{CompiledSystem,CompiledHomotopy}}
    I = interpret(T)
    checks, var_map = boundscheck_var_map(I)
    slp = let
        list, ids = instruction_list(I.expressions)
        assignements = Dict{Symbol,Expr}()
        for (i, id) in enumerate(ids)
            push!(assignements, id => :(u[$i] = $id))
        end
        to_expr(list, var_map, assignements)
    end

    quote
        $checks
        @inbounds $slp
        u
    end
end

function _jacobian!_impl(
    ::Type{T},
) where {T<:Union{CompiledSystem,CompiledHomotopy}}
    I = interpret(T)
    checks, var_map = boundscheck_var_map(I; jacobian = true)

    slp = let
        list, ids = instruction_list(I.expressions)
        vars = Symbol.(I.variables)
        dlist, J = diff(list, vars, ids)

        assignements = Dict{Symbol,Expr}()

        U_constants = Expr[]
        for j = 1:size(J, 2), i = 1:size(J, 1)
            if J[i, j] isa Symbol
                push!(assignements, J[i, j] => :(U[$i, $j] = $(J[i, j])))
            elseif J[i, j] isa Number
                push!(U_constants, :(U[$i, $j] = $(J[i, j])))
            end
        end
        expr = to_expr(dlist, var_map, assignements)
        append!(expr.args, U_constants)
        expr
    end
    quote
        $checks
        U .= zero(eltype(x))
        @inbounds $slp
        U
    end
end

function _evaluate_and_jacobian!_impl(
    ::Type{T},
) where {T<:Union{CompiledSystem,CompiledHomotopy}}
    I = interpret(T)
    checks, var_map = boundscheck_var_map(I; jacobian = true)

    slp = let
        list, ids = instruction_list(I.expressions)
        vars = Symbol.(I.variables)
        dlist, J = diff(list, vars, ids)

        assignements = Dict{Symbol,Expr}()
        for (i, id) in enumerate(ids)
            push!(assignements, id => :(u[$i] = $id))
        end

        U_constants = Expr[]
        for j = 1:size(J, 2), i = 1:size(J, 1)
            if J[i, j] isa Symbol
                push!(assignements, J[i, j] => :(U[$i, $j] = $(J[i, j])))
            elseif J[i, j] isa Number
                push!(U_constants, :(U[$i, $j] = $(J[i, j])))
            end
        end
        expr = to_expr(dlist, var_map, assignements)
        append!(expr.args, U_constants)
        expr
    end
    quote
        $checks
        U .= zero(eltype(x))
        @inbounds $slp
        nothing
    end
end

function _diff_t!_impl(T::Type{<:CompiledHomotopy}, d, DP)
    H = interpret(T)
    checks, var_map = boundscheck_var_map(H)

    list, ids = instruction_list(H.expressions)

    vars = Symbol.(H.variables)
    params = Symbol.(H.parameters)
    t = Symbol(H.t)

    diff_map = Dict{Tuple{Symbol,Int},Any}()
    for (i, v) in enumerate(vars)
        for k = 1:(d-1)
            diff_map[(v, k)] = :(dx[$k][$i])
        end
    end

    for (i, v) in enumerate(params)
        for k = 1:DP
            diff_map[(v, k)] = :(dp[$k][$i])
        end
    end
    diff_map[(t, 1)] = 1

    dlist = univariate_diff!(list, d, diff_map)

    assignements = Dict{Symbol,Expr}()
    u_constants = Expr[]
    for (i, id) in enumerate(ids)
        d_id = get(diff_map, (id, d), nothing)
        if d_id isa Symbol
            push!(assignements, d_id => :(u[$i] = $d_id))
        elseif d_id isa Nothing
            push!(u_constants, :(u[$i] = zero(eltype(x))))
        else
            push!(u_constants, :(u[$i] = $d_id))
        end
    end
    slp = to_expr(dlist, var_map, assignements)
    append!(slp.args, u_constants)

    quote
        $checks
        @inbounds $slp
        u
    end
end

################
## EVALUATION ##
################

# inplace (generated)
"""
    evaluate!(u, T::CompiledSystem, x, p = nothing)

Evaluate `T` for variables `x` and parameters `p` and store result in `u`.
"""
@generated function evaluate!(u, T::CompiledSystem, x, p = nothing)
    _evaluate!_impl(T)
end

"""
    evaluate!(u, T::CompiledHomotopy, x, t, p = nothing)

Evaluate `T` for variables `x`, `t` and parameters `p` and store result in `u`.
"""
@generated function evaluate!(u, T::CompiledHomotopy, x, t, p = nothing)
    _evaluate!_impl(T)
end

"""
    jacobian!(U, T::CompiledHomotopy, x, p = nothing)

Evaluate the Jacobian of `T` for variables `x`, `t` and parameters `p`
and store result in `u`.
"""
@generated function jacobian!(U, T::CompiledSystem, x, p = nothing)
    _jacobian!_impl(T)
end

"""
    jacobian!(U, T::CompiledHomotopy, x, t, p = nothing)

Evaluate the Jacobian of `T` for variables `x`, `t` and parameters `p` and
store result in `u`.
"""
@generated function jacobian!(U, T::CompiledHomotopy, x, t, p = nothing)
    _jacobian!_impl(T)
end

"""
    evaluate_and_jacobian!(u, U, T::CompiledHomotopy, x, p = nothing)

Evaluate `T` and its Jacobian for variables `x` and parameters `p` and
store result in `u`.
"""
@generated function evaluate_and_jacobian!(
    u,
    U,
    T::CompiledSystem,
    x,
    p = nothing,
)
    _evaluate_and_jacobian!_impl(T)
end

"""
    evaluate_and_jacobian!(u, U, T::CompiledHomotopy, x, t, p = nothing)

Evaluate `T` and its Jacobian for variables `x`, `t` and parameters `p` and
store result in `u`.
"""
@generated function evaluate_and_jacobian!(
    u,
    U,
    T::CompiledHomotopy,
    x,
    t,
    p = nothing,
)
    _evaluate_and_jacobian!_impl(T)
end

"""
    diff_t!(u, H::CompiledHomotopy, x, t, (x₁,…,xᵣ₋₁) = (), p = nothing, (p₁,…,pⱼ) = ())

Evaluate the expression
```math
(1 / r!) dʳ/dλʳ \\, H(x + ∑_{k=1}^{r-1} xᵢλⁱ,t + λ)
```
at ``λ = 0``.
If ``j < r-1`` then ``pₐ = 0`` for ``a > j``.
"""
@generated function diff_t!(
    u,
    T::CompiledHomotopy,
    x::AbstractVector,
    t,
    dx::NTuple{D,<:AbstractVector} = Tuple{}(),
    p::Union{Nothing,AbstractVector} = nothing,
    dp::NTuple{DP,<:AbstractVector} = Tuple{}(),
) where {D,DP}
    _diff_t!_impl(T, D, DP)
end

# non-inplace

"""
    to_smallest_eltype(A::AbstractArray)

Convert an array to the smallest eltype such that all elements still fit.

## Example
```julia
typeof(to_smallest_elype(Any[2,3])) == Vector{Int}
```
"""
function to_smallest_eltype(A::AbstractArray)
    T = typeof(first(A))
    for a in A
        T = promote_type(T, typeof(a))
    end
    convert.(T, A)
end

function evaluate(T::CompiledSystem, x, p = nothing)
    to_smallest_eltype(evaluate!(Vector{Any}(undef, size(T, 1)), T, x, p))
end
function evaluate(T::CompiledHomotopy, x, t, p = nothing)
    to_smallest_eltype(evaluate!(Vector{Any}(undef, size(T, 1)), T, x, t, p))
end

(T::CompiledSystem)(x, p = nothing) = evaluate(x, p)
(T::CompiledHomotopy)(x, t, p = nothing) = evaluate(x, t, p)

function jacobian(T::CompiledSystem, x, p = nothing)
    n, m = size(T)
    U = Matrix{Any}(undef, n, m)
    to_smallest_eltype(jacobian!(U, T, x, p))
end
function jacobian(T::CompiledHomotopy, x, t, p = nothing)
    n, m = size(T)
    U = Vector{Any}(undef, n, m)
    to_smallest_eltype(jacobian!(U, T, x, t, p))
end

function evaluate_and_jacobian(T::CompiledSystem, x, p = nothing)
    n, m = size(T)
    u = Vector{Any}(undef, n)
    U = Matrix{Any}(undef, n, m)
    evaluate_and_jacobian!(u, U, T, x, p)
    to_smallest_eltype(u), to_smallest_eltype(U)
end
function evaluate_and_jacobian(T::CompiledHomotopy, x, t, p = nothing)
    n, m = size(T)
    u = Vector{Any}(undef, n)
    U = Matrix{Any}(undef, n, m)
    evaluate_and_jacobian!(u, U, T, x, t, p)
    to_smallest_eltype(u), to_smallest_eltype(U)
end

function diff_t(H::CompiledHomotopy, x::AbstractVector, t, args...)
    u = Vector{Any}(undef, size(H, 1))
    to_smallest_eltype(diff_t!(u, H, x, t, args...))
end

ext: jl


text:
# Simple SIR Model for COVID-19 Modeling
# Michele Fornino
# 3/23/2020
#
# Based on Atkeson (2020)

# Housekeeping
using Plots
using DifferentialEquations

# Define System of Differential Equations
function SIRE!(du, u, p, t)
  # Order of variables in vectors u and du:
  # u[1] S(usceptible)
  # u[2] E(xposed)
  # u[3] I(nfected)
  # u[4] R(recovered/dead)
  #
  # Order of parameters in vector p:
  # p[1] γ
  # p[2] σ

  # Define auxiliary variable
  S, E, I, R = u
  γ, σ, R0 = p
  N = sum(u)
  β = R0 * γ
  du[1] = - β * S / N * I
  du[2] = β * S / N * I - σ * E
  du[3] = σ * E - γ * I
  du[4] = γ * I
end

# Parameters
γ = 1.0/18.0
σ = 1.0/5.2
R0 = 2.5
p = [γ, σ, R0]

I0 = 1.0e-7
E0 = 4.0 * I0
S0 = 1.0 - E0 - I0
R0 = 0.0

u0 = [S0, E0, I0, R0]

T = 18.0 * 30.0
tspan = (0.0, T)

# Define and solve problem
prob = ODEProblem(SIRE!, u0, tspan, p)
sol = solve(prob)

max_stars_repo_name: mfornino/showcase

max_issues_repo_name: mfornino/showcase

max_forks_repo_name: mfornino/showcase


text:
#!/usr/bin/env julia

__precompile__(true)

"""
# EightQueensPuzzle

Ported to **Julia** from examples in several languages from
here: https://hbfs.wordpress.com/2009/11/10/is-python-slow
"""
module EightQueensPuzzle

export main

type Board
    cols::Int
    nodes::Int
    diag45::Int
    diag135::Int
    solutions::Int

    Board() = new(0, 0, 0, 0, 0)
end

"Marks occupancy."
function mark!(b::Board, k::Int, j::Int)
    b.cols    $= (1 << j)
    b.diag135 $= (1 << (j+k))
    b.diag45  $= (1 << (32+j-k))
end

"Tests if a square is menaced."
function test(b::Board, k::Int, j::Int)
    b.cols    & (1 << j)        +
    b.diag135 & (1 << (j+k))    +
    b.diag45  & (1 << (32+j-k)) == 0
end

"Backtracking solver."
function solve!(b::Board, niv::Int, dx::Int)
    if niv > 0
        for i in 0:dx-1
            if test(b, niv, i) == true
                mark!(b, niv, i)
                solve!(b, niv-1, dx)
                mark!(b, niv, i)
            end
        end
    else
        for i in 0:dx-1
            if test(b, 0, i) == true
                b.solutions += 1
            end
        end
    end
    b.nodes += 1
    b.solutions
end

"C/C++-style `main` function."
function main()
    for n = 1:17
        gc()
        b = Board()
        @show n
        print("elapsed:")
        solutions = @time solve!(b, n-1, n)
        @show solutions
        println()
    end
end

end

using  EightQueensPuzzle

main()

max_stars_repo_name: ethansaxenian/RosettaDecode

max_issues_repo_name: ethansaxenian/RosettaDecode

max_forks_repo_name: ethansaxenian/RosettaDecode


text:
# Use baremodule to shave off a few KB from the serialized `.ji` file
baremodule Gnuplot_jll
using Base
using Base: UUID
import JLLWrappers

JLLWrappers.@generate_main_file_header("Gnuplot")
JLLWrappers.@generate_main_file("Gnuplot", UUID("e5af9688-3aeb-5ed5-8c7e-253e55323d3e"))
end  # module Gnuplot_jll


text:
using Revise
using AdFem
using PyPlot
using SparseArrays

cmesh = CrackMesh(50,50,1/50,24)
mmesh = cmesh.mesh
β = 1/4; γ = 1/2
a = b = 0.1

NT = 500
Δt = 2/NT

Ca = spzeros(cmesh.nslip, 2mmesh.ndof)
ls = zeros(cmesh.nslip)
for i = 1:cmesh.nslip
    u = cmesh.upper[i+1]
    l = cmesh.lower[i+1]
    Ca[i, u] = 1.0
    Ca[i, l] = -1.0
    ls[i] = cmesh.h/5
end
Ca = constant(Ca)

bdedge = cmesh.bdedge

ρ = ones(get_ngauss(mmesh))

M = compute_fem_mass_matrix1(ρ, mmesh)
Z = spzero(mmesh.ndof, mmesh.ndof)
M = [M Z;Z M]

ν = 0.1ones(get_ngauss(mmesh))
E = ones(get_ngauss(mmesh))

D = compute_plane_strain_matrix(E, ν)
K = compute_fem_stiffness_matrix(D, mmesh)

Nbd = size(bdedge, 1)
ρe = ones(4Nbd)
mu = 1/(2*(1+0.3))
lambda = 0.3/(1+0.3)/(1-2*0.3)
cs = ones(4Nbd) * sqrt(mu)
cp = ones(4Nbd) * sqrt(lambda + 2mu)
C = compute_absorbing_boundary_condition_matrix(ρe, cs, cp, bdedge, mmesh)

function ricker(;dt = 0.05, f0 = 5.0)
    nw = 2/(f0*dt)
    nc = floor(Int, nw/2)
    t = dt*collect(-nc:1:nc)
    b = (π*f0*t).^2
    w = @. (1 - 2b)*exp(-b)
end

F = zeros(NT, 2mmesh.ndof+cmesh.nslip)
r = ricker()
xy = gauss_nodes(mmesh)
S = @. exp(-20*((xy[:,1]-0.5)^2+(xy[:,2]-0.5)^2))

for i = 1:min(length(r), NT)
    f1 = S * r[i]
    F[i,:] = [compute_fem_source_term(zero(f1), zero(f1), mmesh);ls]
end

F = constant(F)

en = ExplicitNewmark(M, C, K, Δt, factorize_A = false)
en.A = factorize([en.A Ca'
        Ca spzero(cmesh.nslip)])
en.C = [en.C spzero(2mmesh.ndof, cmesh.nslip)
        spzero(cmesh.nslip, 2mmesh.ndof) spzero(cmesh.nslip)]
en.B = [en.B spzero(2mmesh.ndof, cmesh.nslip)
    spzero(cmesh.nslip, 2mmesh.ndof) spzero(cmesh.nslip)]

u = TensorArray(NT+1)
u = write(u, 1, zeros(2mmesh.ndof+cmesh.nslip))
u = write(u, 2, zeros(2mmesh.ndof+cmesh.nslip))

function condition(i, arr...)
    i <= NT+1
end
function body(i, arr...)
    u = arr[1]
    u0 = read(u, i-2)
    u1 = read(u, i-1)
    u = write(u, i, step(en, u0, u1, F[i-1]))
    i+1, u
end
i = constant(3, dtype = Int32)
_, out = while_loop(condition, body, [i, u])
U = stack(out)

sess = Session(); init(sess)
uarr = run(sess, U)

m = mean(uarr[:, 1:mmesh.ndof])
s = std(uarr[:, 1:mmesh.ndof])
vmin = -5s
vmax = 5s
function update(i)
    clf()
    visualize_scalar_on_fem_points(uarr[i,1:mmesh.ndof], mmesh, vmin = vmin, vmax = vmax)
    title("i = $i")
end
p = animate(update, 1:(NT÷20):NT)
saveanim(p, "udir.gif")

m = mean(uarr[:, mmesh.ndof+1:2mmesh.ndof])
s = std(uarr[:, mmesh.ndof+1:2mmesh.ndof])
vmin = m - 2s
vmax = m + 2s
function update(i)
    clf()
    visualize_scalar_on_fem_points(uarr[i,mmesh.ndof+1:2mmesh.ndof], mmesh, vmin = vmin, vmax = vmax)
    title("i = $i")
end
p = animate(update, 1:(NT÷20):NT)
saveanim(p, "vdir.gif")


text:
## Definition of Link types and methods for link, invlink and μη, the derivative of μ w.r.t. η

abstract Link

immutable IdentityLink <: Link end
immutable InverseLink <: Link end
immutable LogLink <: Link end
immutable LogitLink <: Link end

link(::IdentityLink,μ) = μ
invlink(::IdentityLink,η) = η
μη(::IdentityLink,η) = one(η)

link(::LogitLink,μ) = log(μ/(one(μ)-μ))
invlink(::LogitLink,η) = inv(one(η) + exp(-η))
μη(::LogitLink,η) = (ee = exp(-η); ee/abs2(one(η)+ee))

link(::LogLink,μ) = log(μ)
invlink(::LogLink,η) = exp(η)
μη(::LogLink,η) = exp(η)

link(::InverseLink,μ) = inv(μ)
invlink(::InverseLink,η) = inv(η)
μη(::InverseLink,η) = -inv(abs2(η))


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

using Test, Libdl, LibUnwind_jll

@testset "LibUnwind_jll" begin
    if !Sys.isapple() && !Sys.iswindows()
        @test dlsym(LibUnwind_jll.libunwind_handle, :unw_backtrace; throw_error=false) !== nothing
    end
end

max_stars_repo_name: jonas-schulze/julia

max_issues_repo_name: jonas-schulze/julia

max_forks_repo_name: jonas-schulze/julia


text:
using ..Continuations: set_if_not

aliasof(x) = nameof(typeof(x))

tkindstr(x) = tkindstr(timekind(x))
tkindstr(::Discrete) = "Discrete"
tkindstr(::Continuous) = "Continuous"

function print_header(io::IO, point::Union{SpecialPoint,
                                           SpecialPointInterval})
    print(io, aliasof(point), " <",
          tkindstr(point), " ",
          point.point_type,
          ">")
end

function print_header(io::IO, ctx::Union{BifurcationSweep,
                                         BifurcationSolution,
                                         BifurcationSolver})
    print(io, aliasof(ctx), " <", tkindstr(ctx), ">")
end

function Base.show(io::IO, point::SpecialPoint)
    print_header(io, point)
    println(io)
    if ! get(io, :compact, false)
        io = set_if_not(io, :compact, true)  # reduce number of digits shown
        println(io, "u = ", point.u)
    end
end

function Base.show(io::IO, point::SpecialPointInterval)
    print_header(io, point)
    println(io)
    if ! get(io, :compact, false)
        io = set_if_not(io, :compact, true)  # reduce number of digits shown
        println(io, "happened between:")
        println(io, "  u0 = ", point.u0)
        println(io, "  u1 = ", point.u1)
    end
end

function show_special_points_counts(io, ctx)
    for (point_type, n) in sort(collect(count_special_points(ctx)),
                                by = first)
        print(io, "# ")
        print(io, rpad(string(point_type), 19))
        print(io, ": ")
        println(io, n)
    end
end

function Base.show(io::IO, sweep::BifurcationSweep)
    super = as(sweep, ContinuationSweep)
    print_header(io, sweep)

    n_all = length(sweep)
    n_sb = length(super.simple_bifurcation)
    n_sp = length(sweep.special_intervals)
    if get(io, :compact, false)
        println(io, " ", n_sb + n_sp, "/", n_all, " special/points")
    else
        println(io)
        println(io, "# points             : ", n_all)
        println(io, "# branches           : ", n_sb)
        show_special_points_counts(io, sweep)
    end
end

function show_solution_info(io::IO, sol::BifurcationSolution)
    super = as(sol, ContinuationSolution)
    if isempty(sol.sweeps)
        println(io, " no sweeps")
        return
    end
    n_all = sum(length, super.sweeps)
    n_sb = sum(length(s.simple_bifurcation) for s in super.sweeps)
    n_sp = sum(length(s.special_intervals) for s in sol.sweeps)
    if get(io, :compact, false)
        println(io, " ", n_sb + n_sp, "/", n_all, " special/points")
    else
        println(io)
        println(io, "# sweeps             : ", length(sol.sweeps))
        println(io, "# points             : ", n_all)
        println(io, "# branches           : ", n_sb)
        show_special_points_counts(io, sol)
    end
end

function Base.show(io::IO, sol::BifurcationSolution)
    print_header(io, sol)
    show_solution_info(io, sol)
end

function Base.show(io::IO, solver::BifurcationSolver)
    print_header(io, solver)
    show_solution_info(io, solver.sol)
end


text:
struct FlightAccumulator
    count::Int
    totalTime::Dates.Minute
    picTime::Dates.Minute
    dualTime::Dates.Minute
    instrTime::Dates.Minute
end

FlightAccumulator() = FlightAccumulator(0, Dates.Minute(0), Dates.Minute(0), Dates.Minute(0), Dates.Minute(0))
FlightAccumulator(flights::Vector{<:Flighty}) = sum([FlightAccumulator(); flights])

function toPrettyTableRow(acc::FlightAccumulator, comment)
	return [
		"",
		"", "", "", "", "", "", "", "", "", "",
		asString(acc.totalTime),
		"",
		asString(acc.picTime), asString(acc.dualTime), asString(acc.instrTime),
		acc.count,
		comment
	]
end

function Base.:+(acc::FlightAccumulator, f::Flighty)
    c = acc.count + numberOfLandings(f)
    totalTime = acc.totalTime + minutes(f)
    dualTime = acc.dualTime
    picTime = acc.picTime
    instrTime = acc.instrTime

    if !dual(f)
        picTime = acc.picTime + minutes(f)
    else
        dualTime = acc.dualTime + minutes(f)
    end

    if instr(f)
        instrTime = acc.instrTime + minutes(f)
    end

    FlightAccumulator(c, totalTime, picTime, dualTime, instrTime)
end

function Base.:+(f1::Flighty, f2::Flighty)::FlightAccumulator
    acc = FlightAccumulator()
    acc + f1 + f2
end

max_stars_repo_name: julianschick/flugbuch

max_issues_repo_name: julianschick/flugbuch

max_forks_repo_name: julianschick/flugbuch


text:
using OrdinaryDiffEq

function LotkaVolterraTest_not_inplace(u,a,t)
    b,c,d = 1.0,3.0,1.0
    x,y = u[1],u[2]
    du = zeros(eltype(u),2)
    du[1] = a*x - b*x*y
    du[2] = -c*y + d*x*y
    du
end

# forward
u0 = [1.0;1.0]
tspan = (0.0,10.0)
prob = ODEProblem(LotkaVolterraTest_not_inplace,u0,tspan,1.5)

sol = solve(prob,Tsit5())
t = collect(range(0, stop=10, length=200))
using RecursiveArrayTools # for VectorOfArray
randomized = VectorOfArray([(sol(t[i]) + .01randn(2)) for i in 1:length(t)])
data = convert(Array,randomized)

# inverse
soll = solve(prob,Tsit5())

cost_function = build_loss_objective(prob,Tsit5(),L2Loss(t,data),
                                     maxiters=10000,verbose=false)
import Optim
result = Optim.optimize(cost_function, 0.0, 10.0)


text:
# workspace()
using JuLearn
using MatlabPlot
@Eval lr=1e-2 batchsize=100
L=4;T=10

# prepare data
t=0:0.5:10000;x=cos(t);y=x[[2:end,1]]
# mplot([x[1:100] y[1:100]],".")
# x=x[:,[2:end,1]]
nData=1000;inputBase=zeros(1,nData,T);outputBase=zeros(1,nData,T);state=1
for data=1:nData,t=1:T
  inputBase[:,data,t]=x[state];outputBase[:,data,t]=y[state]; state+=1
end

# create JuLearn
orderGraph=rnnOrderGraph(L,T)
@Eval order=topologicalSort(Main.orderGraph)
connectGraph=rnnConnectGraph(L,T)

layersNames=repmat([:d,:h,:h,:l],T,1)
layersDims=repmat([1 1;1 10;10 1;1 1],T,1)
layersDims=correctLayerDims(orderGraph,layersDims)

net=initNet(layersNames,layersDims,:regression)
connectNet(net,connectGraph,layersDims)
for i=1:1:length(net)
  if i%L==0
    net[i-1].A=linear;net[i-1].∂A=∂linear
    net[i].Cost=leastsq;net[i].∂Cost=∂leastsq
    println(i)
  end
end

sharedParams=Array{Any}(L-2,2)
for l=2:L-1
  sharedParams[l-1,1]=collect(l+(1:T-1)*L)
  sharedParams[l-1,2]=[:W,:b]
end
@Eval shareParams=Main.shareParams

# backprop
err=backprop(net,inputBase,outputBase,nIter=3000)
figure();mplot(err)

# prediction
Ttrain=2
input=x[state+(0:T-1)]
target=y[state+(0:T-1)]
prediction=zeros(T)
for t=0:Ttrain net[1+t*L].rₒ[1,1]=x[state+t] end
forward!(net)
for t=0:Ttrain prediction[t+1]=net[t*L+L-1].rₒ[1,1] end

for t=Ttrain+1:T-1
net[1+t*L].rₒ[1,1]=prediction[t]
forward!(net)
prediction[t+1]=net[t*L+L-1].rₒ[1,1]
end
figure();mplot([input target prediction]);legend("input","target","prediction")


text:
# even though we don't subtype the GeoInterface abstract types
# we can still extend some of their methods to make interoperation easier

GeoInterface.geotype(::Feature) = :Feature
GeoInterface.geotype(::FeatureCollection) = :FeatureCollection

function GeoInterface.properties(f::Feature)
    props = properties(f)
    Dict{String, Any}(String(k) => v for (k, v) in props)
end

# TODO implement for FeatureCollection, currently only features are captured
function GeoInterface.bbox(f::Feature)
    bbox = get(json(f), :bbox, nothing)
    if bbox === nothing
        return nothing
    else
        return copy(bbox)
    end
end

GeoInterface.coordinates(f::Feature) = copy(geometry(f).coordinates)

function _geometry(g::JSON3.Object)
    if g.type == "Point"
        GeoInterface.Point(g.coordinates)
    elseif g.type == "LineString"
        GeoInterface.LineString(g.coordinates)
    elseif g.type == "Polygon"
        GeoInterface.Polygon(g.coordinates)
    elseif g.type == "MultiPoint"
        GeoInterface.MultiPoint(g.coordinates)
    elseif g.type == "MultiLineString"
        GeoInterface.MultiLineString(g.coordinates)
    elseif g.type == "MultiPolygon"
        GeoInterface.MultiPolygon(g.coordinates)
    elseif g.type == "GeometryCollection"
        _geometry.(g.geometries)
    else
        throw(ArgumentError("Unknown geometry type"))
    end
end

function GeoInterface.geometry(f::Feature)
    _geometry(geometry(f))
end

function GeoInterface.Feature(f::Feature)
    GeoInterface.Feature(GeoInterface.geometry(f), GeoInterface.properties(f))
end

function GeoInterface.FeatureCollection(fc::FeatureCollection)
    GeoInterface.FeatureCollection(GeoInterface.Feature.(fc), nothing, nothing)
end


text:
valsdomain_type_promote(::Type{T},::Type{T}) where {T<:Complex}=T,T
valsdomain_type_promote(::Type{T},::Type{T}) where {T<:Real}=T,T
valsdomain_type_promote(::Type{Int},::Type{Int})=Float64,Int
valsdomain_type_promote(::Type{T},::Type{Complex{V}}) where {T<:Real,V<:Real}=promote_type(T,V),Complex{promote_type(T,V)}
valsdomain_type_promote(::Type{Complex{T}},::Type{V}) where {T<:Real,V<:Real}=Complex{promote_type(T,V)},promote_type(T,V)
valsdomain_type_promote(::Type{T},::Type{Int}) where {T<:Integer}=Float64,Int
valsdomain_type_promote(::Type{T},::Type{Int}) where {T<:Real}=T,Int
valsdomain_type_promote(::Type{T},::Type{Int}) where {T<:Complex}=T,Int
valsdomain_type_promote(::Type{T},::Type{V}) where {T<:Integer,V<:Real}=valsdomain_type_promote(Float64,V)
valsdomain_type_promote(::Type{T},::Type{V}) where {T<:Integer,V<:Complex}=valsdomain_type_promote(Float64,V)
valsdomain_type_promote(::Type{T},::Type{Vector{T}}) where {T<:Real}=T,Vector{T}
valsdomain_type_promote(::Type{T},::Type{V}) where {T,V}=promote_type(T,V),promote_type(T,V)

function choosefuncfstype(ftype,Td)
    if !( ftype<: Number || ( ((ftype <: AbstractArray) || (ftype <: Vec)) &&
                              (eltype(ftype) <: Number) ) )
        @warn "Function outputs type $(ftype), which is not a Number"
    end

    Tprom = ftype

    if ftype <: Number #TODO should also work for array-valued functions
        Tprom,Tpromd=valsdomain_type_promote(ftype,Td)

        if Tpromd != Td
                @warn "Space domain number type $(Td) is not compatible with coefficient type $(Tprom)"
                #TODO should construct a new Space that contains a domain where the numbers have been promoted
                #and call constructor with this Space.
        end
    end

    Tprom
end

# default_Fun is the default constructor, based on evaluation and transforms
# last argument is whether to splat or not
default_Fun(::Type{T},f,d::Space{ReComp},pts::AbstractVector,::Type{Val{true}}) where {T,ReComp} =
    Fun(d,transform(d,T[f(x...) for x in pts]))

default_Fun(::Type{T},f,d::Space{ReComp},pts::AbstractVector,::Type{Val{false}}) where {T,ReComp} =
    Fun(d,transform(d,broadcast!(f, similar(pts, T), pts)))

function default_Fun(f,d::Space{ReComp},n::Integer,::Type{Val{false}}) where ReComp
    pts=points(d, n)
    f1=f(pts[1])
    if isa(f1,AbstractArray) && size(d) ≠ size(f1)
        return Fun(f,Space(fill(d,size(f1))),n)
    end

    # we need 3 eltype calls for the case Interval(Point([1.,1.]))
    Tprom=choosefuncfstype(typeof(f1),prectype(domain(d)))
    default_Fun(Tprom,f,d,pts,Val{false})
end

function default_Fun(f,d::Space{ReComp},n::Integer,::Type{Val{true}}) where ReComp
    pts=points(d, n)
    f1=f(pts[1]...)
    if isa(f1,AbstractArray) && size(d) ≠ size(f1)
        return Fun(f,Space(fill(d,size(f1))),n)
    end

    # we need 3 eltype calls for the case Interval(Point([1.,1.]))
    Tprom=choosefuncfstype(typeof(f1),prectype(domain(d)))
    default_Fun(Tprom,f,d,pts,Val{true})
end

default_Fun(f,d::Space{ReComp},n::Integer) where {ReComp} = default_Fun(f,d,n,Val{!hasnumargs(f,1)})

Fun(f::Function,d::Space{ReComp},n::Integer) where {ReComp} = default_Fun(dynamic(f),d,n)

# the following is to avoid ambiguity
# Fun(f::Fun,d) should be equivalent to Fun(x->f(x),d)
Fun(f::Fun,d::Space) = Fun(d,coefficients(f,d))
Fun(f::Fun,::Type{T}) where {T<:Space} = Fun(f,T(domain(f)))

Fun(f,T::Type) = Fun(dynamic(f),T())
Fun(f::Function,T::Type,n::Integer) = Fun(dynamic(f),T(),n)

Fun(f::AbstractVector,d::Domain) = Fun(f,Space(d))
Fun(d::Domain,f::AbstractVector{T}) where {T<:Number} = Fun(Space(d),f)
Fun(d::Domain,f::AbstractVector) = Fun(Space(d),f)

Fun(f::Function,d::Domain,n) = Fun(dynamic(f),Space(d),n)

# We do zero special since zero exists even when one doesn't
Fun(c::Number,::Type{T}) where {T<:Space} = c==0 ? zeros(T(AnyDomain())) : c*ones(T(AnyDomain()))
Fun(c::Number,d::Domain) = c==0 ? c*zeros(d) : c*ones(d)
Fun(c::Number,d::Space) = c==0 ? c*zeros(prectype(d),d) : c*ones(prectype(d),d)

## Adaptive constructors
function default_Fun(f, d::Space)
    hasnumargs(f,1) || return Fun(xy->f(xy...),d)
    isinf(dimension(d)) || return Fun(f,d,dimension(d))  # use exactly dimension number of sample points

    #TODO: reuse function values?
    T = real(prectype(domain(d)))

    r=checkpoints(d)
    f0=f(first(r))

    isa(f0,AbstractArray) && size(d) ≠ size(f0) && return Fun(f,Space(fill(d,size(f0))))

    tol =T==Any ? 20eps() : 20eps(T)

    fr=map(f,r)
    maxabsfr=norm(fr,Inf)

    for logn = 4:20
        #cf = Fun(f, d, 2^logn + 1)
        cf = default_Fun(f, d, 2^logn)
        maxabsc = maximum(abs,cf.coefficients)
        if maxabsc == 0 && maxabsfr == 0
            return(zeros(d))
        end

        b = block(d,length(cf.coefficients))
        bs = blockstart(d,max(b.n[1]-2,1))

        # we allow for transformed coefficients being a different size
        ##TODO: how to do scaling for unnormalized bases like Jacobi?
        if ncoefficients(cf) > 8 && maximum(abs,cf.coefficients[bs:end]) < 10tol*maxabsc &&
                all(k->norm(cf(r[k])-fr[k],1)<tol*length(cf.coefficients)*maxabsfr*1000,1:length(r))
            return chop!(cf,tol)
        end
    end

    @warn "Maximum number of coefficients "*string(2^20+1)*" reached in constructing Fun."

    Fun(f,d,2^21)
end

Fun(f::Type, d::Space) = error("Not implemented")

# special case constructors
zeros(S::Space) = Fun(S,zeros(1))
zeros(::Type{T}, S::Space) where {T<:Number} = Fun(S,zeros(T,1))

# catch all
ones(S::Space) = Fun(x->1.0,S)
ones(::Type{T}, S::Space) where {T<:Number} = Fun(x->one(T),S)

function Fun(::typeof(identity), d::Domain)
    cd=canonicaldomain(d)
    if typeof(d) == typeof(cd)
        Fun(dynamic(x->x),d) # fall back to constructor, can't use `identity` as that creates a loop
    else
        # this allows support for singularities, that the constructor doesn't
        sf=fromcanonical(d,Fun(identity,cd))
        Fun(setdomain(space(sf),d),coefficients(sf))
    end
end

Fun(::typeof(identity), S::Space) = Fun(identity,domain(S))

Fun(f::typeof(zero), d::Space) = zeros(eltype(domain(d)),d)
Fun(f::typeof(one), d::Space) = ones(eltype(domain(d)),d)

Fun(f::Type, d::Domain) = Fun(f,Space(d))
Fun(f::Function, d::Domain) = Fun(f,Space(d))

# this is the main constructor
Fun(f::Function, d::Space) = default_Fun(dynamic(f), d)

# this supports expanding a Fun to a larger or smaller domain.
# we take the union and then intersection to get at any singularities
# TODO: singularities in space(f)
Fun(f::Fun, d::Domain) = Fun(f,Space((d ∪ domain(f)) ∩ d))

## Aliases

Fun(T::Type,n::Integer) = Fun(T(),n)
Fun(f,n::Integer) = Fun(f,ChebyshevInterval(),n)
Fun(T::Type,d::AbstractVector) = Fun(T(),d)

Fun(f::Fun{SequenceSpace},s::Space) = Fun(s,f.coefficients)


text:
using Test
using TOMLConfig
using Dates, Random

struct NoException <: Exception end

macro test_nothrow(ex)
    esc(:(@test_throws NoException ($(ex); throw(NoException()))))
end

function check_keys(toml::Dict{String}, has, doesnt)
    for key in has
        @test haskey(toml, key)
    end
    for key in doesnt
        @test !haskey(toml, key)
    end
end

function typed_isequal(toml1::Dict{String}, toml2::Dict{String})
    @test toml1 == toml2
    for k in keys(toml1)
        v1, v2 = toml1[k], toml2[k]
        if v1 isa AbstractDict && v2 isa AbstractDict
            @test typeof(v1) == typeof(v2)
            typed_isequal(v1, v2)
        else
            @test typeof(v1) == typeof(v2)
        end
    end
end

@testset "basic parsing" begin
    template = TOML.parse(
    """
    a = 0
    b = 0.0
    [sec1]
        c = [1, 2]
        [sec1.sub1]
            d = [1.0, 2.0]
            e = true
        [sec1.sub2]
            f = 2010-05-17
            g = 2013-01-01T00:00:00
            h = 01:00:00
    """)

    function check_parsed_types(toml::Dict{String})
        @test typeof(toml["a"]) == Int
        @test typeof(toml["b"]) == Float64
        @test typeof(toml["sec1"]["c"]) == Vector{Int}
        @test typeof(toml["sec1"]["sub1"]["d"]) == Vector{Float64}
        @test typeof(toml["sec1"]["sub1"]["e"]) == Bool
        @test typeof(toml["sec1"]["sub2"]["f"]) == Date
        @test typeof(toml["sec1"]["sub2"]["g"]) == DateTime
        @test typeof(toml["sec1"]["sub2"]["h"]) == Time
    end

    @testset "no args passed" begin
        parsed_args = parse_args(String[], Config(deepcopy(template)); as_dict = true)
        expected_parsed = deepcopy(template)
        check_parsed_types(parsed_args)
        check_parsed_types(expected_parsed)
        typed_isequal(parsed_args, expected_parsed)
    end

    @testset "args passed" begin
        args_list = [
            "--a", "1",
            "--sec1.c", "3", "4", "5",
            "--sec1.sub1.d", "5.5",
            "--sec1.sub2.f", "2021-06-01",
            "--sec1.sub2.g", "2021-06-01T12:34:56",
            "--sec1.sub2.h", "01:23:45",
        ]
        parsed_args = parse_args(args_list, Config(deepcopy(template)); as_dict = true)

        expected_parsed = deepcopy(template)
        expected_parsed["a"] = 1
        expected_parsed["sec1"]["c"] = [3,4,5]
        expected_parsed["sec1"]["sub1"]["d"] = [5.5]
        expected_parsed["sec1"]["sub2"]["f"] = Date("2021-06-01")
        expected_parsed["sec1"]["sub2"]["g"] = DateTime("2021-06-01T12:34:56")
        expected_parsed["sec1"]["sub2"]["h"] = Time("01:23:45")

        check_parsed_types(parsed_args)
        check_parsed_types(expected_parsed)
        typed_isequal(parsed_args, expected_parsed)
    end

    @testset "mistyped args" begin
        for args_list in [
            ["--a", "1.5"],
            ["--b", "e"],
            ["--sec1.c", "3.5", "4"],
            ["--sec1.sub1.d", "f", "g", "h"],
            ["--sec1.sub2.f", "01:00:00"],
            ["--sec1.sub2.g", "01:00:00"],
            ["--sec1.sub2.h", "2013-01-01"],
        ]
            settings = ArgParseSettings(exc_handler = ArgParse.debug_handler)
            @test_throws ArgParseError parse_args(args_list, settings, Config(deepcopy(template)))
        end
    end
end

@testset "nested field inheritance" begin
    template = TOML.parse(
    """
    a = 0
    b = 0.0
    c = "c"
    [sec1]
        _INHERIT_ = "_PARENT_"
        a = 1
        [sec1.sub1]
            _INHERIT_ = "_PARENT_"
            c = "d"
        [sec1.sub2]
            _INHERIT_ = "_PARENT_"
            b = "_PARENT_"
            c = "d"
    """)

    function check_parsed_keys(toml::Dict{String})
        check_keys(toml, ["a", "b", "c"], ["_INHERIT_"])
        check_keys(toml["sec1"], ["a", "b", "c"], ["_INHERIT_"])
        check_keys(toml["sec1"]["sub1"], ["a", "c"], ["_INHERIT_", "b"])
        check_keys(toml["sec1"]["sub2"], ["a", "b", "c"], ["_INHERIT_"])
    end

    @testset "no args passed" begin
        parsed_args = parse_args(String[], Config(deepcopy(template)); as_dict = true)
        expected_parsed = TOML.parse(
        """
        a = 0
        b = 0.0
        c = "c"
        [sec1]
            a = 1
            b = 0.0
            c = "c"
            [sec1.sub1]
                a = 1
                c = "d"
            [sec1.sub2]
                a = 1
                b = 0.0
                c = "d"
        """)
        check_parsed_keys(parsed_args)
        typed_isequal(parsed_args, expected_parsed)
    end

    @testset "args passed" begin
        args_list = ["--b=1.0", "--sec1.a=2", "--sec1.sub2.c=e"]
        parsed_args = parse_args(args_list, Config(deepcopy(template)); as_dict = true)
        expected_parsed = TOML.parse(
        """
        a = 0
        b = 1.0
        c = "c"
        [sec1]
            a = 2
            b = 1.0
            c = "c"
            [sec1.sub1]
                a = 2
                c = "d"
            [sec1.sub2]
                a = 2
                b = 1.0
                c = "e"
        """)
        check_parsed_keys(parsed_args)
        typed_isequal(parsed_args, expected_parsed)
    end
end

@testset "customizing arg table" begin
    template = TOML.parse(
    """
    a = [0]
    b = 0.0
    c = "c"
    [sec1]
        _INHERIT_ = "_PARENT_"
        a = [1]
        [sec1.sub1]
            _INHERIT_ = "_PARENT_"
            c = "d"
        [sec1.sub2]
            _INHERIT_ = "_PARENT_"
            b = "_PARENT_"
            c = "d"
    """)

    function randomly_insert_arg_dicts!(toml)
        seed = 0
        for node in TOMLConfig.StatelessBFS(Config(toml))
            for (k,v) in TOMLConfig.contents(node)
                k == TOMLConfig.inherit_all_key() && continue # can't replace _INHERIT_ with arg dict
                !TOMLConfig.is_arg(v) && continue # only replace args, not child dicts
                rand(MersenneTwister(seed += 1)) > 0.5 && continue # flip coin
                TOMLConfig.contents(node)[k] = !TOMLConfig.is_dict_arg(v) ?
                    Dict{String, Any}(TOMLConfig.arg_key() => TOMLConfig.arg_value(v)) :
                    TOMLConfig.arg_value(v)
            end
        end
        return toml
    end

    @testset "arg dict equivalence" begin
        for args_list in [
            String[],
            ["--a", "1", "2", "--c", "cat"],
            ["--b", "2.0", "--sec1.b", "3.0", "--sec1.sub1.a", "5"],
        ]
            template′ = randomly_insert_arg_dicts!(deepcopy(template))
            parsed_args = parse_args(args_list, Config(deepcopy(template)); as_dict = true)
            parsed_args′ = parse_args(args_list, Config(deepcopy(template′)); as_dict = true)
            typed_isequal(parsed_args, parsed_args′)
        end
    end

    template = TOML.parse(
    """
    [a]
        _ARG_ = "_REQUIRED_"
        nargs = 2
        arg_type = "Int"
        required = true
        help = "help string"
    [b]
        _ARG_ = [1.0, 2.0]
        nargs = "+"
        help = "help string"
    """)
    @testset "arg dict properties" begin
        debug_parse_args = (args_list) -> parse_args(args_list, ArgParseSettings(exc_handler = ArgParse.debug_handler), Config(deepcopy(template)))
        @test_throws ArgParseError debug_parse_args(String[]) # --a is required
        @test_throws ArgParseError debug_parse_args(["--a", "3.0", "4.0"]) # --a must be Int
        @test_throws ArgParseError debug_parse_args(["--a", "3"]) # --a requires two args
        @test_throws ArgParseError debug_parse_args(["--a", "1", "2", "--b"]) # --b requires at least one arg
        @test_nothrow debug_parse_args(["--a", "1", "2", "--b", "5.0"])
        @test_nothrow debug_parse_args(["--a", "1", "2", "--b", "5", "10"]) # --b should allow conversion Int -> Float64
    end
end

max_stars_repo_name: jondeuce/TOMLConfig

max_issues_repo_name: jondeuce/TOMLConfig

max_forks_repo_name: jondeuce/TOMLConfig


text:
# Find a Median String
using IterTools

const NUCLEOTIDES = ('A', 'C', 'G', 'T')

calc_hamming_distance(s1, s2) = count(((c1, c2),) -> c1 != c2, zip(s1, s2))

function distance_between_pattern_and_text(text, pattern, k)
    mindist = k
    for ix in 1:(length(text)-k+1)
        kmer = text[ix:ix+k-1]
        distance = calc_hamming_distance(pattern, kmer)
        if distance < mindist
            mindist = distance
        end
    end
    mindist
end

distance_between_pattern_and_collection_of_texts(texts, pattern, k) =
    foldl((distance, text) -> distance + distance_between_pattern_and_text(text, pattern, k), texts; init=0)

function calc_median_string(texts, k)
    nr_texts = length(texts)
    minimum_distance = nr_texts * k
    median_string = ""
    for pattern in imap(join, Iterators.product(ntuple(_ -> NUCLEOTIDES, k)...))
        distance = distance_between_pattern_and_collection_of_texts(texts, pattern, k)
        if distance < minimum_distance
            minimum_distance = distance
            median_string = pattern
        end
    end
    median_string
end

function main()
    k = parse(Int64, readline())
    texts = readlines()
    result = calc_median_string(texts, k)
    println(result)
end

main()


text:
function readSP3(gpsWeek, day)

    # Construct string
    #sp3File = datadir("igs") * "\\igs" * string(gpsWeek) * string(day) * ".sp3"
    sp3File = datadir("igs", "igs" * string(gpsWeek) * string(day) * ".sp3")

    if !isfile(sp3File)
        throw(ErrorException("The file " * sp3File * " does not exist and must be downloaded from CDDIS.\n" *
        "The file can be found at 'https://cddis.nasa.gov/archive/gnss/products/'"))
    end

    # Instantiate Data Frame
    df = DataFrame(
        MJD     = Float64[],
        Year    = Int[],
        Month   = Int[],
        Day     = Int[],
        Hour    = Int[],
        Min     = Int[],
        Sec     = Float64[],
        Sat     = Symbol[],
        X       = Float64[],
        Y       = Float64[],
        Z       = Float64[],
        Clk     = Float64[],
        Xstd    = Float64[],
        Ystd    = Float64[],
        Zstd    = Float64[],
        Clkstd  = Float64[]
        )

    # Open file
    f = open(sp3File)

    # Base std errors
    basePos = 0.0
    baseClk = 0.0

    # Date and time
    MJD     = 0.0
    Year    = 0
    Month   = 0
    Day     = 0
    Hour    = 0
    Min     = 0
    Sec     = 0.0

    # Begin looping through lines in file
    lineNum = 0
    for line in readlines(f)
        lineNum += 1
        if lineNum > 22
            if line[1] == '*' # Line designates time
                Year    = parse(Int, line[4:7])
                Month   = parse(Int, line[9:10])
                Day     = parse(Int, line[12:13])
                Hour    = parse(Int, line[15:16])
                Min     = parse(Int, line[18:19])
                Sec     = parse(Float64, line[21:31])
            elseif line[1] == 'P'
                Sat         = Symbol(line[2:4])
                X           = parse(Float64, line[5:18])
                Y           = parse(Float64, line[19:32])
                Z           = parse(Float64, line[33:46])
                Clk         = parse(Float64, line[47:60])
                if length(line) > 60
                    XstdExp     = tryparse(Int, line[62:63])
                    XstdExp === nothing ? XstdExp = NaN : ()
                    YstdExp     = tryparse(Int, line[65:66])
                    YstdExp === nothing ? YstdExp = NaN : ()
                    ZstdExp     = tryparse(Int, line[68:69])
                    ZstdExp === nothing ? ZstdExp = NaN : ()
                    ClkstdExp   = tryparse(Int, line[71:73])
                    ClkstdExp === nothing ? ClkstdExp = NaN : ()
                else
                    XstdExp     = NaN
                    YstdExp     = NaN
                    ZstdExp     = NaN
                    ClkstdExp   = NaN
                end

                # Compute MJD
                dayWithFrac = day + ((Sec/60.0 + Min)/60.0 + Hour)/24.0
                MJD = gps2MJD(gpsWeek, dayWithFrac)

                # Push to Data Frame
                push!(df, Dict(
                    "MJD"       => MJD,
                    "Year"      => Year,
                    "Month"     => Month,
                    "Day"       => Day,
                    "Hour"      => Hour,
                    "Min"       => Min,
                    "Sec"       => Sec,
                    "Sat"       => Sat,
                    "X"         => X,
                    "Y"         => Y,
                    "Z"         => Z,
                    "Clk"       => Clk,
                    "Xstd"      => basePos^XstdExp,
                    "Ystd"      => basePos^YstdExp,
                    "Zstd"      => basePos^ZstdExp,
                    "Clkstd"    => baseClk^ClkstdExp
                ))
            end
        else
            if lineNum == 15
                str = split(line, " "; keepempty = false)[2:3]
                basePos = parse(Float64, str[1])
                baseClk = parse(Float64, str[2])
            end
        end
    end

    close(f)
    return df
end

function readSP3s(gpsWeekStart, weekDayStart, gpsWeekEnd, weekDayEnd)
    # Handle gps weeks and week days
    gpsWeeks        = gpsWeekStart:gpsWeekEnd
    startWeekDays   = weekDayStart:6
    endWeekDays     = 0:weekDayEnd

    # Instantiate Data Frame
    df = DataFrame(
        MJD     = Float64[],
        Year    = Int[],
        Month   = Int[],
        Day     = Int[],
        Hour    = Int[],
        Min     = Int[],
        Sec     = Float64[],
        Sat     = Symbol[],
        X       = Float64[],
        Y       = Float64[],
        Z       = Float64[],
        Clk     = Float64[],
        Xstd    = Float64[],
        Ystd    = Float64[],
        Zstd    = Float64[],
        Clkstd  = Float64[]
        )

    @showprogress "Reading in sp3 files..." for week in gpsWeeks
        if week == gpsWeekStart
            for day in startWeekDays
                df = vcat(df, readSP3(week, day))
            end
        elseif week == gpsWeekEnd
            for day in endWeekDays
                df = vcat(df, readSP3(week, day))
            end
        else
            for day in 1:6
                df = vcat(df, readSP3(week, day))
            end
        end
    end

    return df
end

max_stars_repo_name: GrantHecht/OptimalEstimationProject


text:
using PyPlot, MPIReco, OpenMPIData

include("visualization.jl")

filenameCalib = joinpath(OpenMPIData.basedir(),"data","calibrations","2.mdf")
#filenameCalib = joinpath(OpenMPIData.basedir(),"data","calibrations","5.mdf")

for (i,phantom) in enumerate(["shapePhantom", "resolutionPhantom", "concentrationPhantom"])

  filenameMeas = joinpath(OpenMPIData.basedir(),"data","measurements",phantom,"2.mdf")

  # reconstruct data
  c = reconstruction(filenameCalib, filenameMeas, iterations=10, lambd=0.01,
                    minFreq=80e3, SNRThresh=1.5, recChannels=1:3,
		    bgCorrectionInternal=true, spectralLeakageCorrection=false)[:,:,:,10:28,:]

  mkpath( joinpath(OpenMPIData.basedir(),"data/reconstructions/$(phantom)"))
  s = size(c)[2:4]

  # visualization
  if phantom =="shapePhantom"
    filenameImage = joinpath(OpenMPIData.basedir(),"data","reconstructions","$phantom","reconstruction2D.png")
    showMIPs(c[1,:,:,:,1],filename=filenameImage, fignum=i)
  elseif phantom =="resolutionPhantom"
    slice=[div(s[1]+1,2),div(s[2]+1,2),div(s[3]+1,2)]
    filenameImage = joinpath(OpenMPIData.basedir(),"data","reconstructions","$phantom","reconstruction2D.png")
    showSlices(c[1,:,:,:,1],slice,filename=filenameImage, fignum=i)
  elseif phantom =="concentrationPhantom"
    slice1=[div(s[1],3)+1,div(s[2],3)+1,div(s[3],3)+1]
    slice2=[2*div(s[1],3)+1,2*div(s[2],3)+1,div(s[3],3)+1]
    filenameImage = joinpath(OpenMPIData.basedir(),"data","reconstructions","$phantom","reconstruction2D_1.png")
    showSlices(c[1,:,:,:,1],slice1,filename=filenameImage,fignum=i)
    filenameImage = joinpath(OpenMPIData.basedir(),"data","reconstructions","$phantom","reconstruction2D_2.png")
    showSlices(c[1,:,:,:,1],slice2,filename=filenameImage,fignum=i+1)
  end
end


text:
export Id, monoSymp, beamSplitter, circulator
export randomSymmetric, randomSymp, randomGenericSymp
export randomPassiveLocalSymp, randomLocalSymp, randomizeSymp

# From Number of Modes to Identity Symplectic Matrix
Id(n::Int)::Symp = Matrix(1I, 2*n, 2*n)

monoPassiveSymp(θ::Real)::Symp =  exp(θ*Ω(1))
monoSymp(θ1::Real, l::Real, θ2::Real)::Symp =  monoPassiveSymp(θ1) * Symp([l 0 ; 0  1/l ]) * monoPassiveSymp(θ2)

# Generte a Two-Mode BeamSplitter
beamSplitter(angle::Real)::Symp = monoPassiveSymp(angle) ⊗ Id(1)
# Generate a BeamSplitter between two modes in a multi-mode System
function beamSplitter(angle::Real, mode1, mode2, nModes)::Symp
    mode1, mode2 = sort([mode1, mode2])
    lst = [ [[2 * (i + 2) - 1, 2 * (i + 2)] for i in 1:mode1-1]... ; [1, 2] ; [[2 * (i + mode1 + 1) - 1, 2 * (i + mode1 + 1)] for i in 1: mode2 - mode1 - 1]...; [3, 4] ; [[2 * (i + mode2 ) - 1, 2 * (i + mode2 )]  for i in 1:nModes-mode2]...  ];
    return dsum( beamSplitter(angle), Id(nModes - 2) )[lst, lst]
end

# Generate a Circulator-Like Symplectic Matrix according to the given permutation
circulator(perm::Vector)::Symp = hvcat(length(perm), [i == perm[j] ? Id(1).S : zeros(2, 2)   for i in 1:length(perm), j in 1:length(perm) ]...)

# From Number of Modes to Random Symmetric Matrix
function randomSymmetric(n::Int, range::Real = 3)::Matrix{BigFloat}
    if range <= 0
        return error("range must be positive")
    end
    return Symmetric( range*(rand(2*n, 2*n) - I ) )
end

# From Number of Modes to Random Symplectic Matrix
function randomSymp(n::Int, range::Real = 3)::Symp
    S1 = Id(n) - (Ω(n) * randomSymmetric(n, range) + Id(n) / 2  )^-1
    S2 = Id(n) - (Ω(n) * randomSymmetric(n, range) + Id(n) / 2  )^-1
    return  S1 * S2
end
function randomGenericSymp(n::Int, range::Real = 3)::Symp
        m = randomSymp(n, range)
        return isGeneric(m) ? m : randomGenericSymp(n, range)
end
randomPassiveLocalSymp(n::NofModes)::Symp = n == 1 ? monoPassiveSymp(2π*rand()) : ⊕([monoPassiveSymp(2π*rand()) for i in 1:n]...)

randomLocalSymp(n::NofModes, range::Real = 0.2)::Symp = n == 1 ? monoSymp(2π*rand(), range*( rand() -1/2) + 1.0 , 2π*rand()) : ⊕([ monoSymp(2π*rand(), range*( rand() -1/2) + 1.0 , 2π*rand()) for i in 1:n]...)

function randomizeSympPassive(S::Symp, l::Int)::Symp
    n = nModes(S)
    if l == 1
        return randomPassiveLocalSymp(n) * S  * randomPassiveLocalSymp(n)
        # return randomLocalSymp(n) * S  * randomLocalSymp(n)
    else
        return *([randomizeSympPassive(S, 1) for i in 1:l]...)
    end
end

function randomizeSymp(S::Symp, l::Int)::Symp
    n = nModes(S)
    if l == 1
        return randomLocalSymp(n) * S  * randomLocalSymp(n)
        # return randomLocalSymp(n) * S  * randomLocalSymp(n)
    else
        return *([randomizeSymp(S, 1) for i in 1:l]...)
    end
end


text:
using CategoricalArrays, DataFrames, LinearAlgebra, MixedModels, RData, Test

const dat = Dict(Symbol(k) => v for (k,v) in load(joinpath(dirname(@__FILE__), "dat.rda")))

include("UniformBlockDiagonal.jl")
include("linalg.jl")
include("matrixterm.jl")
include("FactorReTerm.jl")
include("pls.jl")
include("pirls.jl")
include("gausshermite.jl")


text:
"""
    TraceHandler

Saves the messages from each sample site in a dictionary with the keys as the
name of the sample site. All the messages are saved in `trace[:msgs]`.
"""
struct TraceHandler <: AbstractHandler end

function enter!(trace::Dict, h::TraceHandler)
    trace[:msgs] = Dict()
end

function postprocess_message!(trace::Dict, h::TraceHandler, msg::Dict)
    trace[:msgs][msg[:name]] = copy(msg)
end

"""
    LogJointHandler

Computes the sum of the log densities of all sample sites. The result is saved
in trace[:logjoint].
"""
struct LogJointHandler <: AbstractHandler end

function enter!(trace::Dict, h::LogJointHandler)
    trace[:logjoint] = 0.0
end

function postprocess_message!(trace::Dict, h::LogJointHandler, msg::Dict)
    dist = msg[:args][1]
    if msg[:value] != nothing
        trace[:logjoint] = trace[:logjoint] + logpdf(dist, msg[:value])
    else
        # TODO: Warning might be annoying when running the queue handler.
        @warn "Encountered site with value nothing." msg[:name]
    end
end

"""
    ConditionHandler

Conditions the model on the given data. This means that the sample sites
included in `data` will be recorded as observed and the model will always
generate traces which agree with the data.

# Fields
- `data::Dict`: data to condition on saved as `{site_name => value}`
"""
struct ConditionHandler <: AbstractHandler
    data::Dict
end

function process_message!(trace::Dict, h::ConditionHandler, msg::Dict)
    if haskey(h.data, msg[:name])
        msg[:value] = h.data[msg[:name]]
        msg[:stop] = true
        msg[:is_observed] = true
    end
end

"""
    ReplayHandler

Makes sure the model generates the same value as given in `trace`. Only the sites
that do not appear in `trace` will be randomly sampled.

# Fields
- `trace::Dict`: trace with values used for replay
"""
struct ReplayHandler <: AbstractHandler
    trace::Dict
end

function process_message!(trace::Dict, h::ReplayHandler, msg::Dict)
    if haskey(h.trace[:msgs], msg[:name])
        msg[:value] = h.trace[:msgs][msg[:name]][:value]
    end
end

"""
    EscapeHandler

Interrupts the execution of model when `escape_fn` evaluates to `true`. Specifically,
an `EscapeException` is thrown to interrupt the execution.

# Fields
- `escape_fn::Function`: function that takes a message as an argument and returns
    `true` at the sample site to escape from
"""
struct EscapeHandler <: AbstractHandler
    escape_fn::Function
end

"""
    EscapeException

Raised by `EscapeHandler`.

# Fields
- `trace::Dict`: trace of the model execution that has been interrupted
- `name::Any`: name of the sample site that caused interruption
"""
struct EscapeException <: Exception
    trace::Dict
    name::Any
end

function process_message!(trace::Dict, h::EscapeHandler, msg::Dict)
    if h.escape_fn(msg)
        msg[:done] = true
        cont(t, m) = throw(EscapeException(t, m[:name]))
        msg[:continuation] = cont
    end
end

"""
    handle!(model::MinijyroModel, handler::AbstractHandler)

Pushes the `handler` on top of the stack of `model`.

# Arguments
- `model::MinijyroModel`
- `handler::AbstractHandler`
"""
function handle!(model::MinijyroModel, handler::AbstractHandler)
    push!(model.handlers_stack, handler)
end

"""
    handle(model::MinijyroModel, handler::AbstractHandler)

Same as `handle!` but does not mutate the `model` and instead returns a new
model with the added `handler`.

# Arguments
- `model::MinijyroModel`
- `handler::AbstractHandler`

# Returns
- `MinijyroModel`
"""
function handle(model::MinijyroModel, handler::AbstractHandler)
    # Same has handle! but do not alter original model.
    m = copy(model)
    push!(m.handlers_stack, handler)
    return m
end

# Generated convenience functions
handlers = [
    :TraceHandler,
    :LogJointHandler,
    :ConditionHandler,
    :ReplayHandler,
    :EscapeHandler
]

function get_function_name(type_name::Symbol)
    # Takes handler type and returns an adequate function name
    # Example: LogJointHandler -> log_joint
    s = String(type_name)
    prefix = split(s, "Handler")[1]
    regex = r"([a-z])([A-Z]+)"
    subsititution = s"\1_\2"
    fn_name = lowercase(replace(prefix, regex => subsititution))
    return Symbol(fn_name)
end

for h in handlers
    # TODO: Can we do kwargs as well?
    h_fn_name = get_function_name(h)
    # Function name for when we do mutation.
    h_fn_name_mut = Symbol(h_fn_name, "!")
    @eval begin
        export $(h_fn_name_mut), $(h_fn_name)

        function $(h_fn_name_mut)(model, args...)
            handle!(model, $(h)(args...))
        end

        function $(h_fn_name)(model, args...)
            return handle(model, $(h)(args...))
        end
    end
end

"""
    queue(model::MinijyroModel, queue::Array{Dict{Any,Any},1})

Will replay the model with the first trace in `queue`. Once we encounter a
discrete sample site which was not in the trace the function execution is
interrupted and for each value in the support of the new sample site we create
a new trace from the old one and add it to the queue.

This effect handler can be used to perform breadth-first enumeration of all
possible traces.

# Arguments
- `model::MinijyroModel`: model
- `queue::Array{Dict{Any,Any},1}`: array of traces

# Returns
- `MinijyroModel`
"""
function queue(model::MinijyroModel, queue::Array{Dict{Any,Any},1})
    # NOTE: This type of effect handler is actually more powerful because we can
    #       change the model_fn.
    max_tries = Int(1e6) # Make sure we do not have infinite loops.
    function _fn(handlers_stack, args...)
        # TODO: This cannot deal with the fact that model_fn might have been
        # been changed. Alternative is to pass model to the model_fn.
        m = MinijyroModel(handlers_stack, model.model_fn)
        for i in 1:max_tries
            top_trace = popfirst!(queue)
            try
                queue_m = handle(m, ReplayHandler(top_trace))
                # Escape when we see a new variable that is not in the trace.
                discr_esc(msg) = !haskey(top_trace[:msgs], msg[:name])
                queue_m = handle(queue_m, EscapeHandler(discr_esc))
                queue_m = handle(queue_m, TraceHandler())

                full_trace = queue_m(args...)
                # We only get to the return call if there has been no escape i.e.
                # if the top_trace has been a full trace.
                return full_trace
            catch e
                if isa(e, EscapeException)
                    for val in support(e.trace[:msgs][e.name][:args][1])
                        new_trace = deepcopy(e.trace)
                        new_trace[:msgs][e.name][:value] = val

                        # Make sure that we do not escape again when using this
                        # trace for replay.
                        new_trace[:msgs][e.name][:done] = false
                        new_trace[:msgs][e.name][:continuation] = nothing
                        push!(queue, new_trace)
                    end
                else
                    throw(e)
                end
            end
        end
    end

    return MinijyroModel(model.handlers_stack, _fn)
end