text:
# This file is auto-generated by AWSMetadata.jl
using AWS
using AWS.AWSServices: lex_models_v2
using AWS.Compat
using AWS.UUIDs

"""
    build_bot_locale(bot_id, bot_version, locale_id)
    build_bot_locale(bot_id, bot_version, locale_id, params::Dict{String,<:Any})

Builds a bot, its intents, and its slot types into a specific locale. A bot can be built
into multiple locales. At runtime the locale is used to choose a specific build of the bot.

# Arguments
- `bot_id`: The identifier of the bot to build. The identifier is returned in the response
  from the operation.
- `bot_version`: The version of the bot to build. This can only be the draft version of the
  bot.
- `locale_id`: The identifier of the language and locale that the bot will be used in. The
  string must match one of the supported locales. All of the intents, slot types, and slots
  used in the bot must have the same locale. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.

"""
build_bot_locale(botId, botVersion, localeId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/"; aws_config=aws_config)
build_bot_locale(botId, botVersion, localeId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/", params; aws_config=aws_config)

"""
    create_bot(bot_name, data_privacy, idle_session_ttlin_seconds, role_arn)
    create_bot(bot_name, data_privacy, idle_session_ttlin_seconds, role_arn, params::Dict{String,<:Any})

Creates an Amazon Lex conversational bot.

# Arguments
- `bot_name`: The name of the bot. The bot name must be unique in the account that creates
  the bot.
- `data_privacy`: Provides information on additional privacy protections Amazon Lex should
  use with the bot's data.
- `idle_session_ttlin_seconds`: The time, in seconds, that Amazon Lex should keep
  information about a user's conversation with the bot.  A user interaction remains active
  for the amount of time specified. If no conversation occurs during this time, the session
  expires and Amazon Lex deletes any data provided before the timeout. You can specify
  between 60 (1 minute) and 86,400 (24 hours) seconds.
- `role_arn`: The Amazon Resource Name (ARN) of an IAM role that has permission to access
  the bot.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"botTags"`: A list of tags to add to the bot. You can only add tags when you create a
  bot. You can't use the UpdateBot operation to update tags. To update tags, use the
  TagResource operation.
- `"description"`: A description of the bot. It appears in lists to help you identify a
  particular bot.
- `"testBotAliasTags"`: A list of tags to add to the test alias for a bot. You can only add
  tags when you create a bot. You can't use the UpdateAlias operation to update tags. To
  update tags on the test alias, use the TagResource operation.
"""
create_bot(botName, dataPrivacy, idleSessionTTLInSeconds, roleArn; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/", Dict{String, Any}("botName"=>botName, "dataPrivacy"=>dataPrivacy, "idleSessionTTLInSeconds"=>idleSessionTTLInSeconds, "roleArn"=>roleArn); aws_config=aws_config)
create_bot(botName, dataPrivacy, idleSessionTTLInSeconds, roleArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("botName"=>botName, "dataPrivacy"=>dataPrivacy, "idleSessionTTLInSeconds"=>idleSessionTTLInSeconds, "roleArn"=>roleArn), params)); aws_config=aws_config)

"""
    create_bot_alias(bot_alias_name, bot_id)
    create_bot_alias(bot_alias_name, bot_id, params::Dict{String,<:Any})

Creates an alias for the specified version of a bot. Use an alias to enable you to change
the version of a bot without updating applications that use the bot. For example, you can
create an alias called \"PROD\" that your applications use to call the Amazon Lex bot.

# Arguments
- `bot_alias_name`: The alias to create. The name must be unique for the bot.
- `bot_id`: The unique identifier of the bot that the alias applies to.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"botAliasLocaleSettings"`: Maps configuration information to a specific locale. You can
  use this parameter to specify a specific Lambda function to run different functions in
  different locales.
- `"botVersion"`: The version of the bot that this alias points to. You can use the
  operation to change the bot version associated with the alias.
- `"conversationLogSettings"`: Specifies whether Amazon Lex logs text and audio for a
  conversation with the bot. When you enable conversation logs, text logs store text input,
  transcripts of audio input, and associated metadata in Amazon CloudWatch Logs. Audio logs
  store audio input in Amazon S3.
- `"description"`: A description of the alias. Use this description to help identify the
  alias.
- `"sentimentAnalysisSettings"`:
- `"tags"`: A list of tags to add to the bot alias. You can only add tags when you create
  an alias, you can't use the UpdateBotAlias operation to update the tags on a bot alias. To
  update tags, use the TagResource operation.
"""
create_bot_alias(botAliasName, botId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botaliases/", Dict{String, Any}("botAliasName"=>botAliasName); aws_config=aws_config)
create_bot_alias(botAliasName, botId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botaliases/", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("botAliasName"=>botAliasName), params)); aws_config=aws_config)

"""
    create_bot_locale(bot_id, bot_version, locale_id, nlu_intent_confidence_threshold)
    create_bot_locale(bot_id, bot_version, locale_id, nlu_intent_confidence_threshold, params::Dict{String,<:Any})

Creates a locale in the bot. The locale contains the intents and slot types that the bot
uses in conversations with users in the specified language and locale. You must add a
locale to a bot before you can add intents and slot types to the bot.

# Arguments
- `bot_id`: The identifier of the bot to create the locale for.
- `bot_version`: The version of the bot to create the locale for. This can only be the
  draft version of the bot.
- `locale_id`: The identifier of the language and locale that the bot will be used in. The
  string must match one of the supported locales. All of the intents, slot types, and slots
  used in the bot must have the same locale. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.
- `nlu_intent_confidence_threshold`: Determines the threshold where Amazon Lex will insert
  the AMAZON.FallbackIntent, AMAZON.KendraSearchIntent, or both when returning alternative
  intents. AMAZON.FallbackIntent and AMAZON.KendraSearchIntent are only inserted if they are
  configured for the bot. For example, suppose a bot is configured with the confidence
  threshold of 0.80 and the AMAZON.FallbackIntent. Amazon Lex returns three alternative
  intents with the following confidence scores: IntentA (0.70), IntentB (0.60), IntentC
  (0.50). The response from the PostText operation would be:   AMAZON.FallbackIntent
  IntentA   IntentB   IntentC

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"description"`: A description of the bot locale. Use this to help identify the bot
  locale in lists.
- `"voiceSettings"`: The Amazon Polly voice ID that Amazon Lex uses for voice interaction
  with the user.
"""
create_bot_locale(botId, botVersion, localeId, nluIntentConfidenceThreshold; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botversions/$(botVersion)/botlocales/", Dict{String, Any}("localeId"=>localeId, "nluIntentConfidenceThreshold"=>nluIntentConfidenceThreshold); aws_config=aws_config)
create_bot_locale(botId, botVersion, localeId, nluIntentConfidenceThreshold, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botversions/$(botVersion)/botlocales/", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("localeId"=>localeId, "nluIntentConfidenceThreshold"=>nluIntentConfidenceThreshold), params)); aws_config=aws_config)

"""
    create_bot_version(bot_id, bot_version_locale_specification)
    create_bot_version(bot_id, bot_version_locale_specification, params::Dict{String,<:Any})

Creates a new version of the bot based on the DRAFT version. If the DRAFT version of this
resource hasn't changed since you created the last version, Amazon Lex doesn't create a new
version, it returns the last created version. When you create the first version of a bot,
Amazon Lex sets the version to 1. Subsequent versions increment by 1.

# Arguments
- `bot_id`: The identifier of the bot to create the version for.
- `bot_version_locale_specification`: Specifies the locales that Amazon Lex adds to this
  version. You can choose the Draft version or any other previously published version for
  each locale. When you specify a source version, the locale data is copied from the source
  version to the new version.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"description"`: A description of the version. Use the description to help identify the
  version in lists.
"""
create_bot_version(botId, botVersionLocaleSpecification; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botversions/", Dict{String, Any}("botVersionLocaleSpecification"=>botVersionLocaleSpecification); aws_config=aws_config)
create_bot_version(botId, botVersionLocaleSpecification, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botversions/", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("botVersionLocaleSpecification"=>botVersionLocaleSpecification), params)); aws_config=aws_config)

"""
    create_intent(bot_id, bot_version, intent_name, locale_id)
    create_intent(bot_id, bot_version, intent_name, locale_id, params::Dict{String,<:Any})

Creates an intent. To define the interaction between the user and your bot, you define one
or more intents. For example, for a pizza ordering bot you would create an OrderPizza
intent. When you create an intent, you must provide a name. You can optionally provide the
following:   Sample utterances. For example, \"I want to order a pizza\" and \"Can I order
a pizza.\" You can't provide utterances for built-in intents.   Information to be gathered.
You specify slots for the information that you bot requests from the user. You can specify
standard slot types, such as date and time, or custom slot types for your application.
How the intent is fulfilled. You can provide a Lambda function or configure the intent to
return the intent information to your client application. If you use a Lambda function,
Amazon Lex invokes the function when all of the intent information is available.   A
confirmation prompt to send to the user to confirm an intent. For example, \"Shall I order
your pizza?\"   A conclusion statement to send to the user after the intent is fulfilled.
For example, \"I ordered your pizza.\"   A follow-up prompt that asks the user for
additional activity. For example, \"Do you want a drink with your pizza?\"

# Arguments
- `bot_id`: The identifier of the bot associated with this intent.
- `bot_version`: The identifier of the version of the bot associated with this intent.
- `intent_name`: The name of the intent. Intent names must be unique in the locale that
  contains the intent and cannot match the name of any built-in intent.
- `locale_id`: The identifier of the language and locale where this intent is used. All of
  the bots, slot types, and slots used by the intent must have the same locale.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"description"`: A description of the intent. Use the description to help identify the
  intent in lists.
- `"dialogCodeHook"`: Specifies that Amazon Lex invokes the alias Lambda function for each
  user input. You can invoke this Lambda function to personalize user interaction. For
  example, suppose that your bot determines that the user's name is John. You Lambda function
  might retrieve John's information from a backend database and prepopulate some of the
  values. For example, if you find that John is gluten intolerant, you might set the
  corresponding intent slot, glutenIntolerant to true. You might find John's phone number and
  set the corresponding session attribute.
- `"fulfillmentCodeHook"`: Specifies that Amazon Lex invokes the alias Lambda function when
  the intent is ready for fulfillment. You can invoke this function to complete the bot's
  transaction with the user. For example, in a pizza ordering bot, the Lambda function can
  look up the closest pizza restaurant to the customer's location and then place an order on
  the customer's behalf.
- `"inputContexts"`: A list of contexts that must be active for this intent to be
  considered by Amazon Lex. When an intent has an input context list, Amazon Lex only
  considers using the intent in an interaction with the user when the specified contexts are
  included in the active context list for the session. If the contexts are not active, then
  Amazon Lex will not use the intent. A context can be automatically activated using the
  outputContexts property or it can be set at runtime.  For example, if there are two intents
  with different input contexts that respond to the same utterances, only the intent with the
  active context will respond. An intent may have up to 5 input contexts. If an intent has
  multiple input contexts, all of the contexts must be active to consider the intent.
- `"intentClosingSetting"`: Sets the response that Amazon Lex sends to the user when the
  intent is closed.
- `"intentConfirmationSetting"`: Provides prompts that Amazon Lex sends to the user to
  confirm the completion of an intent. If the user answers \"no,\" the settings contain a
  statement that is sent to the user to end the intent.
- `"kendraConfiguration"`: Configuration information required to use the
  AMAZON.KendraSearchIntent intent to connect to an Amazon Kendra index. The
  AMAZON.KendraSearchIntent intent is called when Amazon Lex can't determine another intent
  to invoke.
- `"outputContexts"`: A lists of contexts that the intent activates when it is fulfilled.
  You can use an output context to indicate the intents that Amazon Lex should consider for
  the next turn of the conversation with a customer.  When you use the outputContextsList
  property, all of the contexts specified in the list are activated when the intent is
  fulfilled. You can set up to 10 output contexts. You can also set the number of
  conversation turns that the context should be active, or the length of time that the
  context should be active.
- `"parentIntentSignature"`: A unique identifier for the built-in intent to base this
  intent on.
- `"sampleUtterances"`: An array of strings that a user might say to signal the intent. For
  example, \"I want a pizza\", or \"I want a {PizzaSize} pizza\".  In an utterance, slot
  names are enclosed in curly braces (\"{\", \"}\") to indicate where they should be
  displayed in the utterance shown to the user..
"""
create_intent(botId, botVersion, intentName, localeId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/", Dict{String, Any}("intentName"=>intentName); aws_config=aws_config)
create_intent(botId, botVersion, intentName, localeId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("intentName"=>intentName), params)); aws_config=aws_config)

"""
    create_slot(bot_id, bot_version, intent_id, locale_id, slot_name, slot_type_id, value_elicitation_setting)
    create_slot(bot_id, bot_version, intent_id, locale_id, slot_name, slot_type_id, value_elicitation_setting, params::Dict{String,<:Any})

Creates a slot in an intent. A slot is a variable needed to fulfill an intent. For example,
an OrderPizza intent might need slots for size, crust, and number of pizzas. For each slot,
you define one or more utterances that Amazon Lex uses to elicit a response from the user.

# Arguments
- `bot_id`: The identifier of the bot associated with the slot.
- `bot_version`: The version of the bot associated with the slot.
- `intent_id`: The identifier of the intent that contains the slot.
- `locale_id`: The identifier of the language and locale that the slot will be used in. The
  string must match one of the supported locales. All of the bots, intents, slot types used
  by the slot must have the same locale. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.
- `slot_name`: The name of the slot. Slot names must be unique within the bot that contains
  the slot.
- `slot_type_id`: The unique identifier for the slot type associated with this slot. The
  slot type determines the values that can be entered into the slot.
- `value_elicitation_setting`: Specifies prompts that Amazon Lex sends to the user to
  elicit a response that provides the value for the slot.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"description"`: A description of the slot. Use this to help identify the slot in lists.
- `"obfuscationSetting"`: Determines how slot values are used in Amazon CloudWatch logs. If
  the value of the obfuscationSetting parameter is DefaultObfuscation, slot values are
  obfuscated in the log output. If the value is None, the actual value is present in the log
  output. The default is to obfuscate values in the CloudWatch logs.
"""
create_slot(botId, botVersion, intentId, localeId, slotName, slotTypeId, valueElicitationSetting; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/$(intentId)/slots/", Dict{String, Any}("slotName"=>slotName, "slotTypeId"=>slotTypeId, "valueElicitationSetting"=>valueElicitationSetting); aws_config=aws_config)
create_slot(botId, botVersion, intentId, localeId, slotName, slotTypeId, valueElicitationSetting, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/$(intentId)/slots/", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("slotName"=>slotName, "slotTypeId"=>slotTypeId, "valueElicitationSetting"=>valueElicitationSetting), params)); aws_config=aws_config)

"""
    create_slot_type(bot_id, bot_version, locale_id, slot_type_name, value_selection_setting)
    create_slot_type(bot_id, bot_version, locale_id, slot_type_name, value_selection_setting, params::Dict{String,<:Any})

Creates a custom slot type  To create a custom slot type, specify a name for the slot type
and a set of enumeration values, the values that a slot of this type can assume.

# Arguments
- `bot_id`: The identifier of the bot associated with this slot type.
- `bot_version`: The identifier of the bot version associated with this slot type.
- `locale_id`: The identifier of the language and locale that the slot type will be used
  in. The string must match one of the supported locales. All of the bots, intents, and slots
  used by the slot type must have the same locale. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.
- `slot_type_name`: The name for the slot. A slot type name must be unique within the
  account.
- `value_selection_setting`: Determines the strategy that Amazon Lex uses to select a value
  from the list of possible values. The field can be set to one of the following values:
  OriginalValue - Returns the value entered by the user, if the user value is similar to the
  slot value.    TopResolution - If there is a resolution list for the slot, return the first
  value in the resolution list. If there is no resolution list, return null.   If you don't
  specify the valueSelectionSetting parameter, the default is OriginalValue.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"description"`: A description of the slot type. Use the description to help identify the
  slot type in lists.
- `"parentSlotTypeSignature"`: The built-in slot type used as a parent of this slot type.
  When you define a parent slot type, the new slot type has the configuration of the parent
  slot type. Only AMAZON.AlphaNumeric is supported.
- `"slotTypeValues"`: A list of SlotTypeValue objects that defines the values that the slot
  type can take. Each value can have a list of synonyms, additional values that help train
  the machine learning model about the values that it resolves for a slot.
"""
create_slot_type(botId, botVersion, localeId, slotTypeName, valueSelectionSetting; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/slottypes/", Dict{String, Any}("slotTypeName"=>slotTypeName, "valueSelectionSetting"=>valueSelectionSetting); aws_config=aws_config)
create_slot_type(botId, botVersion, localeId, slotTypeName, valueSelectionSetting, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/slottypes/", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("slotTypeName"=>slotTypeName, "valueSelectionSetting"=>valueSelectionSetting), params)); aws_config=aws_config)

"""
    delete_bot(bot_id)
    delete_bot(bot_id, params::Dict{String,<:Any})

Deletes all versions of a bot, including the Draft version. To delete a specific version,
use the DeleteBotVersion operation. When you delete a bot, all of the resources contained
in the bot are also deleted. Deleting a bot removes all locales, intents, slot, and slot
types defined for the bot. If a bot has an alias, the DeleteBot operation returns a
ResourceInUseException exception. If you want to delete the bot and the alias, set the
skipResourceInUseCheck parameter to true.

# Arguments
- `bot_id`: The identifier of the bot to delete.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"skipResourceInUseCheck"`: When true, Amazon Lex doesn't check to see if another
  resource, such as an alias, is using the bot before it is deleted.
"""
delete_bot(botId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("DELETE", "/bots/$(botId)/"; aws_config=aws_config)
delete_bot(botId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("DELETE", "/bots/$(botId)/", params; aws_config=aws_config)

"""
    delete_bot_alias(bot_alias_id, bot_id)
    delete_bot_alias(bot_alias_id, bot_id, params::Dict{String,<:Any})

Deletes the specified bot alias.

# Arguments
- `bot_alias_id`: The unique identifier of the bot alias to delete.
- `bot_id`: The unique identifier of the bot associated with the alias to delete.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"skipResourceInUseCheck"`: When this parameter is true, Amazon Lex doesn't check to see
  if any other resource is using the alias before it is deleted.
"""
delete_bot_alias(botAliasId, botId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("DELETE", "/bots/$(botId)/botaliases/$(botAliasId)/"; aws_config=aws_config)
delete_bot_alias(botAliasId, botId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("DELETE", "/bots/$(botId)/botaliases/$(botAliasId)/", params; aws_config=aws_config)

"""
    delete_bot_locale(bot_id, bot_version, locale_id)
    delete_bot_locale(bot_id, bot_version, locale_id, params::Dict{String,<:Any})

Removes a locale from a bot. When you delete a locale, all intents, slots, and slot types
defined for the locale are also deleted.

# Arguments
- `bot_id`: The unique identifier of the bot that contains the locale.
- `bot_version`: The version of the bot that contains the locale.
- `locale_id`: The identifier of the language and locale that will be deleted. The string
  must match one of the supported locales. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.

"""
delete_bot_locale(botId, botVersion, localeId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("DELETE", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/"; aws_config=aws_config)
delete_bot_locale(botId, botVersion, localeId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("DELETE", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/", params; aws_config=aws_config)

"""
    delete_bot_version(bot_id, bot_version)
    delete_bot_version(bot_id, bot_version, params::Dict{String,<:Any})

Deletes a specific version of a bot. To delete all version of a bot, use the DeleteBot
operation.

# Arguments
- `bot_id`: The identifier of the bot that contains the version.
- `bot_version`: The version of the bot to delete.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"skipResourceInUseCheck"`: By default, the DeleteBotVersion operations throws a
  ResourceInUseException exception if you try to delete a bot version that has an alias
  pointing at it. Set the skipResourceInUseCheck parameter to true to skip this check and
  remove the version even if an alias points to it.
"""
delete_bot_version(botId, botVersion; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("DELETE", "/bots/$(botId)/botversions/$(botVersion)/"; aws_config=aws_config)
delete_bot_version(botId, botVersion, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("DELETE", "/bots/$(botId)/botversions/$(botVersion)/", params; aws_config=aws_config)

"""
    delete_intent(bot_id, bot_version, intent_id, locale_id)
    delete_intent(bot_id, bot_version, intent_id, locale_id, params::Dict{String,<:Any})

Removes the specified intent. Deleting an intent also deletes the slots associated with the
intent.

# Arguments
- `bot_id`: The identifier of the bot associated with the intent.
- `bot_version`: The version of the bot associated with the intent.
- `intent_id`: The unique identifier of the intent to delete.
- `locale_id`: The identifier of the language and locale where the bot will be deleted. The
  string must match one of the supported locales. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.

"""
delete_intent(botId, botVersion, intentId, localeId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("DELETE", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/$(intentId)/"; aws_config=aws_config)
delete_intent(botId, botVersion, intentId, localeId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("DELETE", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/$(intentId)/", params; aws_config=aws_config)

"""
    delete_slot(bot_id, bot_version, intent_id, locale_id, slot_id)
    delete_slot(bot_id, bot_version, intent_id, locale_id, slot_id, params::Dict{String,<:Any})

Deletes the specified slot from an intent.

# Arguments
- `bot_id`: The identifier of the bot associated with the slot to delete.
- `bot_version`: The version of the bot associated with the slot to delete.
- `intent_id`: The identifier of the intent associated with the slot.
- `locale_id`: The identifier of the language and locale that the slot will be deleted
  from. The string must match one of the supported locales. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.
- `slot_id`: The identifier of the slot to delete.

"""
delete_slot(botId, botVersion, intentId, localeId, slotId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("DELETE", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/$(intentId)/slots/$(slotId)/"; aws_config=aws_config)
delete_slot(botId, botVersion, intentId, localeId, slotId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("DELETE", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/$(intentId)/slots/$(slotId)/", params; aws_config=aws_config)

"""
    delete_slot_type(bot_id, bot_version, locale_id, slot_type_id)
    delete_slot_type(bot_id, bot_version, locale_id, slot_type_id, params::Dict{String,<:Any})

Deletes a slot type from a bot locale. If a slot is using the slot type, Amazon Lex throws
a ResourceInUseException exception. To avoid the exception, set the skipResourceInUseCheck
parameter to true.

# Arguments
- `bot_id`: The identifier of the bot associated with the slot type.
- `bot_version`: The version of the bot associated with the slot type.
- `locale_id`: The identifier of the language and locale that the slot type will be deleted
  from. The string must match one of the supported locales. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.
- `slot_type_id`: The identifier of the slot type to delete.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"skipResourceInUseCheck"`: By default, the DeleteSlotType operations throws a
  ResourceInUseException exception if you try to delete a slot type used by a slot. Set the
  skipResourceInUseCheck parameter to true to skip this check and remove the slot type even
  if a slot uses it.
"""
delete_slot_type(botId, botVersion, localeId, slotTypeId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("DELETE", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/slottypes/$(slotTypeId)/"; aws_config=aws_config)
delete_slot_type(botId, botVersion, localeId, slotTypeId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("DELETE", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/slottypes/$(slotTypeId)/", params; aws_config=aws_config)

"""
    describe_bot(bot_id)
    describe_bot(bot_id, params::Dict{String,<:Any})

Provides metadata information about a bot.

# Arguments
- `bot_id`: The unique identifier of the bot to describe.

"""
describe_bot(botId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("GET", "/bots/$(botId)/"; aws_config=aws_config)
describe_bot(botId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("GET", "/bots/$(botId)/", params; aws_config=aws_config)

"""
    describe_bot_alias(bot_alias_id, bot_id)
    describe_bot_alias(bot_alias_id, bot_id, params::Dict{String,<:Any})

Get information about a specific bot alias.

# Arguments
- `bot_alias_id`: The identifier of the bot alias to describe.
- `bot_id`: The identifier of the bot associated with the bot alias to describe.

"""
describe_bot_alias(botAliasId, botId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("GET", "/bots/$(botId)/botaliases/$(botAliasId)/"; aws_config=aws_config)
describe_bot_alias(botAliasId, botId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("GET", "/bots/$(botId)/botaliases/$(botAliasId)/", params; aws_config=aws_config)

"""
    describe_bot_locale(bot_id, bot_version, locale_id)
    describe_bot_locale(bot_id, bot_version, locale_id, params::Dict{String,<:Any})

Describes the settings that a bot has for a specific locale.

# Arguments
- `bot_id`: The identifier of the bot associated with the locale.
- `bot_version`: The identifier of the version of the bot associated with the locale.
- `locale_id`: The unique identifier of the locale to describe. The string must match one
  of the supported locales. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.

"""
describe_bot_locale(botId, botVersion, localeId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("GET", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/"; aws_config=aws_config)
describe_bot_locale(botId, botVersion, localeId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("GET", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/", params; aws_config=aws_config)

"""
    describe_bot_version(bot_id, bot_version)
    describe_bot_version(bot_id, bot_version, params::Dict{String,<:Any})

Provides metadata about a version of a bot.

# Arguments
- `bot_id`: The identifier of the bot containing the version to return metadata for.
- `bot_version`: The version of the bot to return metadata for.

"""
describe_bot_version(botId, botVersion; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("GET", "/bots/$(botId)/botversions/$(botVersion)/"; aws_config=aws_config)
describe_bot_version(botId, botVersion, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("GET", "/bots/$(botId)/botversions/$(botVersion)/", params; aws_config=aws_config)

"""
    describe_intent(bot_id, bot_version, intent_id, locale_id)
    describe_intent(bot_id, bot_version, intent_id, locale_id, params::Dict{String,<:Any})

Returns metadata about an intent.

# Arguments
- `bot_id`: The identifier of the bot associated with the intent.
- `bot_version`: The version of the bot associated with the intent.
- `intent_id`: The identifier of the intent to describe.
- `locale_id`: The identifier of the language and locale of the intent to describe. The
  string must match one of the supported locales. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.

"""
describe_intent(botId, botVersion, intentId, localeId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("GET", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/$(intentId)/"; aws_config=aws_config)
describe_intent(botId, botVersion, intentId, localeId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("GET", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/$(intentId)/", params; aws_config=aws_config)

"""
    describe_slot(bot_id, bot_version, intent_id, locale_id, slot_id)
    describe_slot(bot_id, bot_version, intent_id, locale_id, slot_id, params::Dict{String,<:Any})

Gets metadata information about a slot.

# Arguments
- `bot_id`: The identifier of the bot associated with the slot.
- `bot_version`: The version of the bot associated with the slot.
- `intent_id`: The identifier of the intent that contains the slot.
- `locale_id`: The identifier of the language and locale of the slot to describe. The
  string must match one of the supported locales. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.
- `slot_id`: The unique identifier for the slot.

"""
describe_slot(botId, botVersion, intentId, localeId, slotId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("GET", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/$(intentId)/slots/$(slotId)/"; aws_config=aws_config)
describe_slot(botId, botVersion, intentId, localeId, slotId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("GET", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/$(intentId)/slots/$(slotId)/", params; aws_config=aws_config)

"""
    describe_slot_type(bot_id, bot_version, locale_id, slot_type_id)
    describe_slot_type(bot_id, bot_version, locale_id, slot_type_id, params::Dict{String,<:Any})

Gets metadata information about a slot type.

# Arguments
- `bot_id`: The identifier of the bot associated with the slot type.
- `bot_version`: The version of the bot associated with the slot type.
- `locale_id`: The identifier of the language and locale of the slot type to describe. The
  string must match one of the supported locales. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.
- `slot_type_id`: The identifier of the slot type.

"""
describe_slot_type(botId, botVersion, localeId, slotTypeId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("GET", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/slottypes/$(slotTypeId)/"; aws_config=aws_config)
describe_slot_type(botId, botVersion, localeId, slotTypeId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("GET", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/slottypes/$(slotTypeId)/", params; aws_config=aws_config)

"""
    list_bot_aliases(bot_id)
    list_bot_aliases(bot_id, params::Dict{String,<:Any})

Gets a list of aliases for the specified bot.

# Arguments
- `bot_id`: The identifier of the bot to list aliases for.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of aliases to return in each page of results. If there
  are fewer results than the max page size, only the actual number of results are returned.
- `"nextToken"`: If the response from the ListBotAliases operation contains more results
  than specified in the maxResults parameter, a token is returned in the response. Use that
  token in the nextToken parameter to return the next page of results.
"""
list_bot_aliases(botId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/bots/$(botId)/botaliases/"; aws_config=aws_config)
list_bot_aliases(botId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/bots/$(botId)/botaliases/", params; aws_config=aws_config)

"""
    list_bot_locales(bot_id, bot_version)
    list_bot_locales(bot_id, bot_version, params::Dict{String,<:Any})

Gets a list of locales for the specified bot.

# Arguments
- `bot_id`: The identifier of the bot to list locales for.
- `bot_version`: The version of the bot to list locales for.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"filters"`: Provides the specification for a filter used to limit the response to only
  those locales that match the filter specification. You can only specify one filter and one
  value to filter on.
- `"maxResults"`: The maximum number of aliases to return in each page of results. If there
  are fewer results than the max page size, only the actual number of results are returned.
- `"nextToken"`: If the response from the ListBotLocales operation contains more results
  than specified in the maxResults parameter, a token is returned in the response. Use that
  token as the nextToken parameter to return the next page of results.
- `"sortBy"`: Specifies sorting parameters for the list of locales. You can sort by locale
  name in ascending or descending order.
"""
list_bot_locales(botId, botVersion; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/bots/$(botId)/botversions/$(botVersion)/botlocales/"; aws_config=aws_config)
list_bot_locales(botId, botVersion, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/bots/$(botId)/botversions/$(botVersion)/botlocales/", params; aws_config=aws_config)

"""
    list_bot_versions(bot_id)
    list_bot_versions(bot_id, params::Dict{String,<:Any})

Gets information about all of the versions of a bot. The ListBotVersions operation returns
a summary of each version of a bot. For example, if a bot has three numbered versions, the
ListBotVersions operation returns for summaries, one for each numbered version and one for
the DRAFT version. The ListBotVersions operation always returns at least one version, the
DRAFT version.

# Arguments
- `bot_id`: The identifier of the bot to list versions for.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of versions to return in each page of results. If
  there are fewer results than the max page size, only the actual number of results are
  returned.
- `"nextToken"`: If the response to the ListBotVersion operation contains more results than
  specified in the maxResults parameter, a token is returned in the response. Use that token
  in the nextToken parameter to return the next page of results.
- `"sortBy"`: Specifies sorting parameters for the list of versions. You can specify that
  the list be sorted by version name in either ascending or descending order.
"""
list_bot_versions(botId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/bots/$(botId)/botversions/"; aws_config=aws_config)
list_bot_versions(botId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/bots/$(botId)/botversions/", params; aws_config=aws_config)

"""
    list_bots()
    list_bots(params::Dict{String,<:Any})

Gets a list of available bots.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"filters"`: Provides the specification of a filter used to limit the bots in the
  response to only those that match the filter specification. You can only specify one filter
  and one string to filter on.
- `"maxResults"`: The maximum number of bots to return in each page of results. If there
  are fewer results than the maximum page size, only the actual number of results are
  returned.
- `"nextToken"`: If the response from the ListBots operation contains more results than
  specified in the maxResults parameter, a token is returned in the response. Use that token
  in the nextToken parameter to return the next page of results.
- `"sortBy"`: Specifies sorting parameters for the list of bots. You can specify that the
  list be sorted by bot name in ascending or descending order.
"""
list_bots(; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/bots/"; aws_config=aws_config)
list_bots(params::AbstractDict{String, Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/bots/", params; aws_config=aws_config)

"""
    list_built_in_intents(locale_id)
    list_built_in_intents(locale_id, params::Dict{String,<:Any})

Gets a list of built-in intents provided by Amazon Lex that you can use in your bot.  To
use a built-in intent as a the base for your own intent, include the built-in intent
signature in the parentIntentSignature parameter when you call the CreateIntent operation.
For more information, see CreateIntent.

# Arguments
- `locale_id`: The identifier of the language and locale of the intents to list. The string
  must match one of the supported locales. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of built-in intents to return in each page of results.
  If there are fewer results than the max page size, only the actual number of results are
  returned.
- `"nextToken"`: If the response from the ListBuiltInIntents operation contains more
  results than specified in the maxResults parameter, a token is returned in the response.
  Use that token in the nextToken parameter to return the next page of results.
- `"sortBy"`: Specifies sorting parameters for the list of built-in intents. You can
  specify that the list be sorted by the built-in intent signature in either ascending or
  descending order.
"""
list_built_in_intents(localeId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/builtins/locales/$(localeId)/intents/"; aws_config=aws_config)
list_built_in_intents(localeId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/builtins/locales/$(localeId)/intents/", params; aws_config=aws_config)

"""
    list_built_in_slot_types(locale_id)
    list_built_in_slot_types(locale_id, params::Dict{String,<:Any})

Gets a list of built-in slot types that meet the specified criteria.

# Arguments
- `locale_id`: The identifier of the language and locale of the slot types to list. The
  string must match one of the supported locales. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of built-in slot types to return in each page of
  results. If there are fewer results than the max page size, only the actual number of
  results are returned.
- `"nextToken"`: If the response from the ListBuiltInSlotTypes operation contains more
  results than specified in the maxResults parameter, a token is returned in the response.
  Use that token in the nextToken parameter to return the next page of results.
- `"sortBy"`: Determines the sort order for the response from the ListBuiltInSlotTypes
  operation. You can choose to sort by the slot type signature in either ascending or
  descending order.
"""
list_built_in_slot_types(localeId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/builtins/locales/$(localeId)/slottypes/"; aws_config=aws_config)
list_built_in_slot_types(localeId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/builtins/locales/$(localeId)/slottypes/", params; aws_config=aws_config)

"""
    list_intents(bot_id, bot_version, locale_id)
    list_intents(bot_id, bot_version, locale_id, params::Dict{String,<:Any})

Get a list of intents that meet the specified criteria.

# Arguments
- `bot_id`: The unique identifier of the bot that contains the intent.
- `bot_version`: The version of the bot that contains the intent.
- `locale_id`: The identifier of the language and locale of the intents to list. The string
  must match one of the supported locales. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"filters"`: Provides the specification of a filter used to limit the intents in the
  response to only those that match the filter specification. You can only specify one filter
  and only one string to filter on.
- `"maxResults"`: The maximum number of intents to return in each page of results. If there
  are fewer results than the max page size, only the actual number of results are returned.
- `"nextToken"`: If the response from the ListIntents operation contains more results than
  specified in the maxResults parameter, a token is returned in the response. Use that token
  in the nextToken parameter to return the next page of results.
- `"sortBy"`: Determines the sort order for the response from the ListIntents operation.
  You can choose to sort by the intent name or last updated date in either ascending or
  descending order.
"""
list_intents(botId, botVersion, localeId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/"; aws_config=aws_config)
list_intents(botId, botVersion, localeId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/", params; aws_config=aws_config)

"""
    list_slot_types(bot_id, bot_version, locale_id)
    list_slot_types(bot_id, bot_version, locale_id, params::Dict{String,<:Any})

Gets a list of slot types that match the specified criteria.

# Arguments
- `bot_id`: The unique identifier of the bot that contains the slot types.
- `bot_version`: The version of the bot that contains the slot type.
- `locale_id`: The identifier of the language and locale of the slot types to list. The
  string must match one of the supported locales. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"filters"`: Provides the specification of a filter used to limit the slot types in the
  response to only those that match the filter specification. You can only specify one filter
  and only one string to filter on.
- `"maxResults"`: The maximum number of slot types to return in each page of results. If
  there are fewer results than the max page size, only the actual number of results are
  returned.
- `"nextToken"`: If the response from the ListSlotTypes operation contains more results
  than specified in the maxResults parameter, a token is returned in the response. Use that
  token in the nextToken parameter to return the next page of results.
- `"sortBy"`: Determines the sort order for the response from the ListSlotTypes operation.
  You can choose to sort by the slot type name or last updated date in either ascending or
  descending order.
"""
list_slot_types(botId, botVersion, localeId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/slottypes/"; aws_config=aws_config)
list_slot_types(botId, botVersion, localeId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/slottypes/", params; aws_config=aws_config)

"""
    list_slots(bot_id, bot_version, intent_id, locale_id)
    list_slots(bot_id, bot_version, intent_id, locale_id, params::Dict{String,<:Any})

Gets a list of slots that match the specified criteria.

# Arguments
- `bot_id`: The identifier of the bot that contains the slot.
- `bot_version`: The version of the bot that contains the slot.
- `intent_id`: The unique identifier of the intent that contains the slot.
- `locale_id`: The identifier of the language and locale of the slots to list. The string
  must match one of the supported locales. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"filters"`: Provides the specification of a filter used to limit the slots in the
  response to only those that match the filter specification. You can only specify one filter
  and only one string to filter on.
- `"maxResults"`: The maximum number of slots to return in each page of results. If there
  are fewer results than the max page size, only the actual number of results are returned.
- `"nextToken"`: If the response from the ListSlots operation contains more results than
  specified in the maxResults parameter, a token is returned in the response. Use that token
  in the nextToken parameter to return the next page of results.
- `"sortBy"`: Determines the sort order for the response from the ListSlots operation. You
  can choose to sort by the slot name or last updated date in either ascending or descending
  order.
"""
list_slots(botId, botVersion, intentId, localeId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/$(intentId)/slots/"; aws_config=aws_config)
list_slots(botId, botVersion, intentId, localeId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/$(intentId)/slots/", params; aws_config=aws_config)

"""
    list_tags_for_resource(resource_arn)
    list_tags_for_resource(resource_arn, params::Dict{String,<:Any})

Gets a list of tags associated with a resource. Only bots, bot aliases, and bot channels
can have tags associated with them.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the resource to get a list of tags for.

"""
list_tags_for_resource(resourceARN; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("GET", "/tags/$(resourceARN)"; aws_config=aws_config)
list_tags_for_resource(resourceARN, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("GET", "/tags/$(resourceARN)", params; aws_config=aws_config)

"""
    tag_resource(resource_arn, tags)
    tag_resource(resource_arn, tags, params::Dict{String,<:Any})

Adds the specified tags to the specified resource. If a tag key already exists, the
existing value is replaced with the new value.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the bot, bot alias, or bot channel to
  tag.
- `tags`: A list of tag keys to add to the resource. If a tag key already exists, the
  existing value is replaced with the new value.

"""
tag_resource(resourceARN, tags; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/tags/$(resourceARN)", Dict{String, Any}("tags"=>tags); aws_config=aws_config)
tag_resource(resourceARN, tags, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("POST", "/tags/$(resourceARN)", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("tags"=>tags), params)); aws_config=aws_config)

"""
    untag_resource(resource_arn, tag_keys)
    untag_resource(resource_arn, tag_keys, params::Dict{String,<:Any})

Removes tags from a bot, bot alias, or bot channel.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the resource to remove the tags from.
- `tag_keys`: A list of tag keys to remove from the resource. If a tag key does not exist
  on the resource, it is ignored.

"""
untag_resource(resourceARN, tagKeys; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("DELETE", "/tags/$(resourceARN)", Dict{String, Any}("tagKeys"=>tagKeys); aws_config=aws_config)
untag_resource(resourceARN, tagKeys, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("DELETE", "/tags/$(resourceARN)", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("tagKeys"=>tagKeys), params)); aws_config=aws_config)

"""
    update_bot(bot_id, bot_name, data_privacy, idle_session_ttlin_seconds, role_arn)
    update_bot(bot_id, bot_name, data_privacy, idle_session_ttlin_seconds, role_arn, params::Dict{String,<:Any})

Updates the configuration of an existing bot.

# Arguments
- `bot_id`: The unique identifier of the bot to update. This identifier is returned by the
  CreateBot operation.
- `bot_name`: The new name of the bot. The name must be unique in the account that creates
  the bot.
- `data_privacy`: Provides information on additional privacy protections Amazon Lex should
  use with the bot's data.
- `idle_session_ttlin_seconds`: The time, in seconds, that Amazon Lex should keep
  information about a user's conversation with the bot. A user interaction remains active for
  the amount of time specified. If no conversation occurs during this time, the session
  expires and Amazon Lex deletes any data provided before the timeout. You can specify
  between 60 (1 minute) and 86,400 (24 hours) seconds.
- `role_arn`: The Amazon Resource Name (ARN) of an IAM role that has permissions to access
  the bot.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"description"`: A description of the bot.
"""
update_bot(botId, botName, dataPrivacy, idleSessionTTLInSeconds, roleArn; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/", Dict{String, Any}("botName"=>botName, "dataPrivacy"=>dataPrivacy, "idleSessionTTLInSeconds"=>idleSessionTTLInSeconds, "roleArn"=>roleArn); aws_config=aws_config)
update_bot(botId, botName, dataPrivacy, idleSessionTTLInSeconds, roleArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("botName"=>botName, "dataPrivacy"=>dataPrivacy, "idleSessionTTLInSeconds"=>idleSessionTTLInSeconds, "roleArn"=>roleArn), params)); aws_config=aws_config)

"""
    update_bot_alias(bot_alias_id, bot_alias_name, bot_id)
    update_bot_alias(bot_alias_id, bot_alias_name, bot_id, params::Dict{String,<:Any})

Updates the configuration of an existing bot alias.

# Arguments
- `bot_alias_id`: The unique identifier of the bot alias.
- `bot_alias_name`: The new name to assign to the bot alias.
- `bot_id`: The identifier of the bot with the updated alias.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"botAliasLocaleSettings"`: The new Lambda functions to use in each locale for the bot
  alias.
- `"botVersion"`: The new bot version to assign to the bot alias.
- `"conversationLogSettings"`: The new settings for storing conversation logs in Amazon
  CloudWatch Logs and Amazon S3 buckets.
- `"description"`: The new description to assign to the bot alias.
- `"sentimentAnalysisSettings"`:
"""
update_bot_alias(botAliasId, botAliasName, botId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botaliases/$(botAliasId)/", Dict{String, Any}("botAliasName"=>botAliasName); aws_config=aws_config)
update_bot_alias(botAliasId, botAliasName, botId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botaliases/$(botAliasId)/", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("botAliasName"=>botAliasName), params)); aws_config=aws_config)

"""
    update_bot_locale(bot_id, bot_version, locale_id, nlu_intent_confidence_threshold)
    update_bot_locale(bot_id, bot_version, locale_id, nlu_intent_confidence_threshold, params::Dict{String,<:Any})

Updates the settings that a bot has for a specific locale.

# Arguments
- `bot_id`: The unique identifier of the bot that contains the locale.
- `bot_version`: The version of the bot that contains the locale to be updated. The version
  can only be the DRAFT version.
- `locale_id`: The identifier of the language and locale to update. The string must match
  one of the supported locales. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.
- `nlu_intent_confidence_threshold`: The new confidence threshold where Amazon Lex inserts
  the AMAZON.FallbackIntent and AMAZON.KendraSearchIntent intents in the list of possible
  intents for an utterance.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"description"`: The new description of the locale.
- `"voiceSettings"`: The new Amazon Polly voice Amazon Lex should use for voice interaction
  with the user.
"""
update_bot_locale(botId, botVersion, localeId, nluIntentConfidenceThreshold; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/", Dict{String, Any}("nluIntentConfidenceThreshold"=>nluIntentConfidenceThreshold); aws_config=aws_config)
update_bot_locale(botId, botVersion, localeId, nluIntentConfidenceThreshold, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("nluIntentConfidenceThreshold"=>nluIntentConfidenceThreshold), params)); aws_config=aws_config)

"""
    update_intent(bot_id, bot_version, intent_id, intent_name, locale_id)
    update_intent(bot_id, bot_version, intent_id, intent_name, locale_id, params::Dict{String,<:Any})

Updates the settings for an intent.

# Arguments
- `bot_id`: The identifier of the bot that contains the intent.
- `bot_version`: The version of the bot that contains the intent. Must be DRAFT.
- `intent_id`: The unique identifier of the intent to update.
- `intent_name`: The new name for the intent.
- `locale_id`: The identifier of the language and locale where this intent is used. The
  string must match one of the supported locales. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"description"`: The new description of the intent.
- `"dialogCodeHook"`: The new Lambda function to use between each turn of the conversation
  with the bot.
- `"fulfillmentCodeHook"`: The new Lambda function to call when all of the intents required
  slots are provided and the intent is ready for fulfillment.
- `"inputContexts"`: A new list of contexts that must be active in order for Amazon Lex to
  consider the intent.
- `"intentClosingSetting"`: The new response that Amazon Lex sends the user when the intent
  is closed.
- `"intentConfirmationSetting"`: New prompts that Amazon Lex sends to the user to confirm
  the completion of an intent.
- `"kendraConfiguration"`: New configuration settings for connecting to an Amazon Kendra
  index.
- `"outputContexts"`: A new list of contexts that Amazon Lex activates when the intent is
  fulfilled.
- `"parentIntentSignature"`: The signature of the new built-in intent to use as the parent
  of this intent.
- `"sampleUtterances"`: New utterances used to invoke the intent.
- `"slotPriorities"`: A new list of slots and their priorities that are contained by the
  intent.
"""
update_intent(botId, botVersion, intentId, intentName, localeId; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/$(intentId)/", Dict{String, Any}("intentName"=>intentName); aws_config=aws_config)
update_intent(botId, botVersion, intentId, intentName, localeId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/$(intentId)/", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("intentName"=>intentName), params)); aws_config=aws_config)

"""
    update_slot(bot_id, bot_version, intent_id, locale_id, slot_id, slot_name, slot_type_id, value_elicitation_setting)
    update_slot(bot_id, bot_version, intent_id, locale_id, slot_id, slot_name, slot_type_id, value_elicitation_setting, params::Dict{String,<:Any})

Updates the settings for a slot.

# Arguments
- `bot_id`: The unique identifier of the bot that contains the slot.
- `bot_version`: The version of the bot that contains the slot. Must always be DRAFT.
- `intent_id`: The identifier of the intent that contains the slot.
- `locale_id`: The identifier of the language and locale that contains the slot. The string
  must match one of the supported locales. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.
- `slot_id`: The unique identifier for the slot to update.
- `slot_name`: The new name for the slot.
- `slot_type_id`: The unique identifier of the new slot type to associate with this slot.
- `value_elicitation_setting`: A new set of prompts that Amazon Lex sends to the user to
  elicit a response the provides a value for the slot.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"description"`: The new description for the slot.
- `"obfuscationSetting"`: New settings that determine how slot values are formatted in
  Amazon CloudWatch logs.
"""
update_slot(botId, botVersion, intentId, localeId, slotId, slotName, slotTypeId, valueElicitationSetting; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/$(intentId)/slots/$(slotId)/", Dict{String, Any}("slotName"=>slotName, "slotTypeId"=>slotTypeId, "valueElicitationSetting"=>valueElicitationSetting); aws_config=aws_config)
update_slot(botId, botVersion, intentId, localeId, slotId, slotName, slotTypeId, valueElicitationSetting, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/intents/$(intentId)/slots/$(slotId)/", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("slotName"=>slotName, "slotTypeId"=>slotTypeId, "valueElicitationSetting"=>valueElicitationSetting), params)); aws_config=aws_config)

"""
    update_slot_type(bot_id, bot_version, locale_id, slot_type_id, slot_type_name, value_selection_setting)
    update_slot_type(bot_id, bot_version, locale_id, slot_type_id, slot_type_name, value_selection_setting, params::Dict{String,<:Any})

Updates the configuration of an existing slot type.

# Arguments
- `bot_id`: The identifier of the bot that contains the slot type.
- `bot_version`: The version of the bot that contains the slot type. Must be DRAFT.
- `locale_id`: The identifier of the language and locale that contains the slot type. The
  string must match one of the supported locales. For more information, see
  https://docs.aws.amazon.com/lex/latest/dg/supported-locales.html.
- `slot_type_id`: The unique identifier of the slot type to update.
- `slot_type_name`: The new name of the slot type.
- `value_selection_setting`: The strategy that Amazon Lex should use when deciding on a
  value from the list of slot type values.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"description"`: The new description of the slot type.
- `"parentSlotTypeSignature"`: The new built-in slot type that should be used as the parent
  of this slot type.
- `"slotTypeValues"`: A new list of values and their optional synonyms that define the
  values that the slot type can take.
"""
update_slot_type(botId, botVersion, localeId, slotTypeId, slotTypeName, valueSelectionSetting; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/slottypes/$(slotTypeId)/", Dict{String, Any}("slotTypeName"=>slotTypeName, "valueSelectionSetting"=>valueSelectionSetting); aws_config=aws_config)
update_slot_type(botId, botVersion, localeId, slotTypeId, slotTypeName, valueSelectionSetting, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = lex_models_v2("PUT", "/bots/$(botId)/botversions/$(botVersion)/botlocales/$(localeId)/slottypes/$(slotTypeId)/", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("slotTypeName"=>slotTypeName, "valueSelectionSetting"=>valueSelectionSetting), params)); aws_config=aws_config)


text:
using Distributed
using Profile

if haskey(ENV, "JULIA_NUM_THREADS")
    nw = parse(Int, ENV["JULIA_NUM_THREADS"])
    addprocs(nw)
else
    @warn "Running in serial mode."
end

const nt = 10
const nx = 160
const ny = 80
const Δt = 1E-1

@everywhere begin
    using Pkg; Pkg.activate(".")  # required
    using SharedArrays
end

@everywhere module CollisionOperator

    using Distributed
    using ParallelDataTransfer
    using SharedArrays

    export run_simulation

    struct Grid2d{M,N,T}
        x::Vector{T}
        y::Vector{T}
    end

    function Grid2d(M, N; x1=0, x2=2π, y1=0, y2=2π)
        x = [x1 + i*(x2-x1)/M for i in 0:M-1]
        y = [y1 + j*(y2-y1)/N for j in 0:N-1]
        Grid2d{M,N,eltype(x)}(x, y)
    end

    struct RungeKutta{M,N,T}
        u::Vector{SharedArray{T,2}}
        f::Vector{SharedArray{T,2}}

        Δt::T

        a::Vector{T}
        b::Vector{T}
        c::Vector{T}
    end

    function RungeKutta(M, N, Δt::T) where {T}
        u = [SharedArray{T}((M,N)), SharedArray{T}((M,N)), SharedArray{T}((M,N))]
        f = [SharedArray{T}((M,N)), SharedArray{T}((M,N)), SharedArray{T}((M,N))]

        a = [0.0, 0.5, 1.0]
        b = [1/6, 2/3, 1/6]
        c = [0.0, 0.5, 1.0]

        RungeKutta{M,N,T}(u, f, Δt, a, b, c)
    end

    function run_simulation(nt::Int, nx::Int, ny::Int, Δt::Number, uinit::Function, mfunc::Function)
        # grid = Grid2d(nx,ny)
        mgrid = Grid2d(nx,ny)
        rk   = RungeKutta(nx, ny, Δt)

        Core.eval(CollisionOperator, Expr(:(=), :grid, mgrid))
        # @eval @everywhere grid = $grid
        @sync for (p,w) in enumerate(workers())
            # @spawnat(w, Core.eval(CollisionOperator, Expr(:(=), :grid, mgrid)))
            @spawnat(w, Core.eval(CollisionOperator, quote grid = Grid2d($nx,$ny) end))
        end

        # @passobj 1 workers() grid

        u₀ = zeros(nx,ny)
        u₁ = zeros(nx,ny)

        # compute initial conditions
        for j in 1:size(u₀,2)
            for i in 1:size(u₀,1)
                 u₀[i,j] = uinit(mgrid.x[i], mgrid.y[j])
            end
        end

        # run for nt time steps
        @time for n in 1:nt
            timestep!(mgrid, rk, mfunc, u₀, u₁)
            # ...
            # save solution
            # ...
            u₀ .= u₁
        end
    end

    "Runge-Kutta time stepping algorithm solving u'=f(u)"
    # function timestep!(grid::Grid2d{M,N,T}, rk::RungeKutta{M,N,T}, mfunc::Function, u₀::Matrix{T}, u₁::Matrix{T}) where {M,N,T}
    function timestep!(grid, rk::RungeKutta{M,N,T}, mfunc::Function, u₀::Matrix{T}, u₁::Matrix{T}) where {M,N,T}
        @assert size(u₀) == size(u₁) == (M,N)

        # compute intermediate steps
        rk.u[1] .= u₀
        collision_operator!(grid, rk, mfunc, rk.u[1], rk.f[1])

        for i in 2:length(rk.a)
            rk.u[i] .= u₀ .+ rk.Δt .* rk.a[i] .* rk.f[i-1]
            collision_operator!(grid, rk, mfunc, rk.u[i], rk.f[i])
        end

        # compute final solution
        u₁ .= u₀
        for i in eachindex(rk.b, rk.f)
            u₁ .+= rk.Δt .* rk.b[i] .* rk.f[i]
        end
    end

    "Collison operator: computes the vector field f(u) where f is a complicated integro-differential operator"
    # function collision_operator!(grid::Grid2d{M,N,T}, m::Function, u::SharedArray{T,2}, f::SharedArray{T,2}) where {M,N,T}
    function collision_operator!(tmp, rk::RungeKutta{M,N,T}, m::Function, u::SharedArray{T,2}, f::SharedArray{T,2}) where {M,N,T}
        # ...
        # do something not too expensive
        # ...

        # compute expensive part in parallel
        if nworkers() > 1
            wn = div(N, nworkers())

            # @Threads.threads for p in 1:nworkers()
            #     j1 = wn*(p-1) + 1
            #     j2 = wn*p
            #     convolution_kernel!(grid, M, N, j1, j2, m, u, f)
            # end

            # @Threads.threads for j in 1:N
            #     convolution_kernel!(grid, M, N, j, j, m, u, f)
            # end

            # @sync @distributed for j in 1:N
            #     convolution_kernel!(grid, M, N, j, j, m, u, f)
            # end

            @sync for (p,w) in enumerate(workers())
                j1 = wn*(p-1) + 1
                j2 = wn*p
                @spawnat w begin
                    convolution_kernel!(grid, M, N, j1, j2, m, u, f)
                end
            end

            # @sync for (p,w) in enumerate(workers())
            #     j1 = wn*(p-1) + 1
            #     j2 = wn*p
            #     @async remotecall_wait(convolution_kernel!, w, grid, M, N, j1, j2, m, u, f)
            # end

        else
            convolution_kernel!(grid, M, N, 1, N, m, u, f)
        end
    end

    "Convolution kernel: most expensive part in vector field computation"
    # @generated function convolution_kernel!(grid::Grid2d{M,N,T}, j1::Int, j2::Int, m::Function, u::SharedArray{T,2}, f::SharedArray{T,2}) where {M,N,T}
    @generated function convolution_kernel!(mgrid, M, N, j1::Int, j2::Int, m::Function, u::SharedArray{T,2}, f::SharedArray{T,2}) where {T}
        # ...
        # create some local arrays
        # ...

        quote
            for j in j1:j2
                for i in 1:M
                    # ...
                    # do some expensive computation involving the function m()
                    # ...
                    f[i,j] = rand()
                    for k in 1:100
                        f[i,j] += cbrt(rand())^3.14159265359 + sqrt(rand())^2.71828182846
                    end
                    u[i,j] = cosh(mgrid.x[i]) + sinh(mgrid.y[j]) + exp(f[i,j])
                end
            end
        end
    end

end

# function that is used in the convolution kernel
@everywhere function m_func!(u::Array{T,2}, m::Union{Array{T,2},SharedArray{T,2}}) where {T}
    m .= u
end

# function that sets initial conditions
@everywhere function u_init(x,y)
    sin(x)^4 * sin(y)^4
end

# load CollisionOperator module
using .CollisionOperator

# warmup
run_simulation(nt, nx, ny, Δt, u_init, m_func!)

# timing
run_simulation(nt, nx, ny, Δt, u_init, m_func!)

# profile
Profile.clear_malloc_data()
run_simulation(nt, nx, ny, Δt, u_init, m_func!)

ext: jl


text:
module TestODEModel
using CovidModels
using OrdinaryDiffEq
import OrdinaryDiffEq: ODEProblem
using Petri
using Test
using Plots

function makeplots_seir(sol, prefix)
    mkpath(dirname(prefix))
    p1 = plot(
        sol,
        vars = [1, 2, 3, 4],
        xlabel = "",
        ylabel = "people",
        linewidth = 3,
        title = "Cities",
        legend = false,
    )
    p2 = plot(
        sol,
        vars = [5, 6, 7, 8],
        xlabel = "",
        ylabel = "people",
        linewidth = 3,
        legend = false,
    )
    p3 = plot(
        sol,
        vars = [9, 10, 11, 12],
        xlabel = "time",
        ylabel = "people",
        linewidth = 3,
        legend = false,
    )
    p4 = plot(
        sol,
        vars = [2, 6, 10],
        xlabel = "",
        linewidth = 3,
        labels = ["i1" "i2" "i3"],
        legend = true,
    )
    p5 = plot(
        sol,
        vars = [3, 7, 11],
        xlabel = "",
        linewidth = 3,
        title = "Populations",
        labels = ["e1" "e2" "e3"],
        legend = true,
    )
    p6 = plot(
        sol,
        vars = [4, 8, 12],
        xlabel = "time",
        linewidth = 3,
        labels = ["r1" "r2" "r3"],
        legend = true,
    )
    p = plot(
        p1,
        p5,
        p2,
        p4,
        p3,
        p6,
        layout = (3, 2),
        linewidth = 3,
        link = :both,
    )
    savefig(p, "$(prefix)combined.pdf")
    p
end

function makeplots_seird(sol, prefix)
    mkpath(dirname(prefix))
    p1 = plot(
        sol,
        vars = [1, 2, 3, 4, 5],
        xlabel = "",
        ylabel = "people",
        linewidth = 3,
        title = "Cities",
        legend = false,
    )
    p2 = plot(
        sol,
        vars = [6, 7, 8, 9, 10],
        xlabel = "",
        ylabel = "people",
        linewidth = 3,
        legend = false,
    )
    p3 = plot(
        sol,
        vars = [11, 12, 13, 14, 15],
        xlabel = "time",
        ylabel = "people",
        linewidth = 3,
        legend = false,
    )
    p4 = plot(
        sol,
        vars = [2, 7, 12],
        xlabel = "",
        linewidth = 3,
        labels = ["i1" "i2" "i3"],
        legend = true,
    )
    p5 = plot(
        sol,
        vars = [3, 8, 13],
        xlabel = "",
        linewidth = 3,
        title = "Populations",
        labels = ["e1" "e2" "e3"],
        legend = true,
    )
    p6 = plot(
        sol,
        vars = [5, 10, 15],
        xlabel = "time",
        linewidth = 3,
        labels = ["d1" "d2" "d3"],
        legend = true,
    )
    p = plot(
        p1,
        p5,
        p2,
        p4,
        p3,
        p6,
        layout = (3, 2),
        linewidth = 3,
        link = :both,
    )
    savefig(p, "$(prefix)combined.pdf")
    p
end

T = [
    # City 1 SEIR
    ([1, 2], [3, 2]),
    ([3], [2]), # E→I
    ([2], [4]), # I→R
    # outflow 1→2
    ([1], [5]), # S→S′
    ([2], [6]), # I→I′
    ([3], [7]), # E→E′
    # City 2 SEIR
    ([5, 6], [7, 6]),
    ([7], [6]), # E→I
    ([6], [8]), # I→R
    # outflow 2→3
    ([5], [9]), # S→S′
    ([6], [10]),# I→I′
    ([7], [11]),# E→E′
    # City 3 SEIR
    ([9, 10], [11, 10]),
    ([11], [10]), # E→I
    ([10], [12]), # I→R
]

m = Petri.Model(1:12, T)
nS = length(m.S)
β = ones(Float64, length(T))
@test fluxes(m)(zeros(Float64, nS), ones(Float64, nS), β, 1) |> length ==
      length(m.S)

tspan = (0.0, 60.0)
prob = ODEProblem(fluxes(m), u₀(m, 1, 0), tspan, β)
sol = OrdinaryDiffEq.solve(prob, Tsit5(), reltol = 1e-8, abstol = 1e-8)
@test sol.u[end][end-3] > 0.90
@test sol.u[end][end-2] == 0
@test sol.u[end][end-1] == 0
@test sol.u[end][end] == 0

u0 = zeros(Float64, length(m.S))
u0[1] = 10000
u0[5] = 10000
u0[9] = 10000
u0[2] = 1
u0
βseir = [10 / sum(u0), 1 / 2, 1 / 5]
βtravel = [1 / 2, 1 / 2, 1 / 2] / 1000
β = vcat(βseir, βtravel, βseir, βtravel, βseir)
@show β
prob = ODEProblem(fluxes(m), u0, tspan, β)
sol = OrdinaryDiffEq.solve(prob, Tsit5(), reltol = 1e-8, abstol = 1e-8)
@show sol.u[end]

using Plots
makeplots_seir(sol, "img/seir/baseline")

βseir = [10 / sum(u0), 1 / 2, 1 / 5]
βtravel = [1 / 2, 1 / 2, 1 / 2] / 100
β = vcat(βseir, βtravel, βseir, βtravel, βseir)
prob = ODEProblem(fluxes(m), u0, tspan, β)
sol = OrdinaryDiffEq.solve(prob, Tsit5(), reltol = 1e-8, abstol = 1e-8)
@show sol.u[end]
makeplots_seir(sol, "img/seir/travel")

βseir = [10 / sum(u0), 1 / 2, 1 / 5]
βtravel = [1 / 2, 1 / 200, 1 / 2] / 100
β = vcat(βseir, βtravel, βseir, βtravel, βseir)
prob = ODEProblem(fluxes(m), u0, tspan, β)
sol = OrdinaryDiffEq.solve(prob, Tsit5(), reltol = 1e-8, abstol = 1e-8)
@show sol.u[end]
makeplots_seir(sol, "img/seir/screening")

βseir = [10 / sum(u0), 1 / 2, 1 / 5]
βtravel = [1 / 200, 1 / 200, 1 / 200] / 100000
β = vcat(βseir, βtravel, βseir, βtravel, βseir)
prob = ODEProblem(fluxes(m), u0, tspan, β)
sol = OrdinaryDiffEq.solve(prob, Tsit5(), reltol = 1e-8, abstol = 1e-8)
@show sol.u[end]
makeplots_seir(sol, "img/seir/shutdown")

println("Exploring the SEIRD^3 example")

S = 1:15
T = [
    ([1, 2], [3, 2]),
    ([3], [2]),
    ([2], [4]),
    ([2], [5]),
    ([1], [6]),
    ([2], [7]),
    ([3], [8]),
    ([6, 7], [8, 7]),
    ([8], [7]),
    ([7], [9]),
    ([7], [10]),
    ([6], [11]),
    ([7], [12]),
    ([8], [13]),
    ([11, 12], [13, 12]),
    ([13], [12]),
    ([12], [14]),
    ([12], [15]),
]
m = Petri.Model(S, T)
u0 = zeros(Float64, length(m.S))
u0[1] = 10000
u0[6] = 10000
u0[11] = 10000
u0[2] = 1
u0
βseir = [10 / sum(u0), 1 / 2, 1 / 5, 1 / 10]
βtravel = [1 / 2, 1 / 2, 1 / 2] / 1000
β = vcat(βseir, βtravel, βseir, βtravel, βseir)
@show β
prob = ODEProblem(fluxes(m), u0, tspan, β)
sol = OrdinaryDiffEq.solve(prob, Tsit5(), reltol = 1e-8, abstol = 1e-8)
@show sol.u[end]
makeplots_seird(sol, "img/seird/baseline")

function paramsweep(f::Function, m::Petri.Model, initials, tspan, params)
    map(params) do p
        prob = ODEProblem(fluxes(m), initials, tspan, p)
        sol = OrdinaryDiffEq.solve(prob, Tsit5(), reltol = 1e-8, abstol = 1e-8)
        return f(sol)
    end
end

packparams(βlocal, βflow) = vcat(βlocal, βflow, βlocal, βflow, βlocal)

# The βseir parameters are the mass action kinetics rates of
# 1. S+I --> E+I
# 2. E --> I
# 3. I --> R
# The βtravel parameters are the mass action kinetics rates of outflow to the next
# city in the transit network.
# 1. S --> S⁺
# 2. I --> I⁺
# 3. E --> E⁺

# Baseline scenario

βseir = [10 / sum(u0), 1 / 2, 1 / 5]
βtravel = [1 / 2, 1 / 2, 1 / 2] / 100
β1 = packparams(βseir, βtravel)

# Travel scenario
βtravel = [1 / 2, 1 / 2, 1 / 2] / 10
β2 = packparams(βseir, βtravel)

# Screening scenario
βtravel = [1 / 2, 1 / 20, 1 / 2] / 100
β3 = packparams(βseir, βtravel)

# Shutdown scenario
βtravel = [1 / 2, 1 / 2, 1 / 2] / 1000
β4 = packparams(βseir, βtravel)

# Total and Complete Shutdown scenario
βtravel = [1 / 2, 1 / 2, 1 / 2] / 10000

β5 = packparams(βseir, βtravel)
βs = [β1, β2, β3, β4, β5]

T = [
    # City 1 SEIR
    ([1, 2], [3, 2]),
    ([3], [2]), # E→I
    ([2], [4]), # I→R
    # outflow 1→2
    ([1], [5]), # S→S′
    ([2], [6]), # I→I′
    ([3], [7]), # E→E′
    # City 2 SEIR
    ([5, 6], [7, 6]),
    ([7], [6]), # E→I
    ([6], [8]), # I→R
    # outflow 2→3
    ([5], [9]), # S→S′
    ([6], [10]),# I→I′
    ([7], [11]),# E→E′
    # City 3 SEIR
    ([9, 10], [11, 10]),
    ([11], [10]), # E→I
    ([10], [12]), # I→R
]

# u0 is the initial configuration of the system
# u0[[1,5,9]] = number of initially Susceptible people in each population
# u0[2] = number of Infected individuals
u0 = zeros(Float64, length(m.S))
u0[1] = 10000
u0[5] = 10000
u0[9] = 10000
u0[2] = 1
u0

m = Petri.Model(1:12, T)
gaps = paramsweep(sol -> peakgap(sol, 2, 10), m, u0, tspan, βs)

# prob = ODEProblem(fluxes(m), u0, tspan, βs[1])
# sol = OrdinaryDiffEq.solve(prob,Tsit5(),reltol=1e-8,abstol=1e-8)
# makeplots_seir(sol, "img/debug_1")

travelparams(k::Number) = begin
    βseir = [10 / sum(u0), 1 / 2, 1 / 5]
    βtravel = [1 / 2, 1 / 2, 1 / 2] / (100k)
    β = packparams(βseir, βtravel)
    return β
end

travelsweep(r::AbstractVector) = begin
    return travelparams.(2 .^ r)
end

βrange = 1:8
gaps = paramsweep(sol -> peakgap(sol, 2, 10), m, u0, tspan, travelsweep(βrange))

coeffs = linreg(βrange, gaps)
@test sum(abs.((coeffs[1] .+ (coeffs[2] * (βrange))) .- gaps)) /
      length(βrange) <= 1e-1

# struct GapResult{P,G}
#     param::P
#     gap::G
# end
#
# GapResult(t::Tuple) = GapResult(t...)
#
# struct GapStudy
#     result::Vector
#     coeffs::Vector
# end
#
# slope(gs::GapStudy) = gs.coeffs[end]

function estimatedelay(r::AbstractVector)
    gaps = paramsweep(sol -> peakgap(sol, 2, 10), m, u0, tspan, travelsweep(r))
    coeffs = linreg(βrange, gaps)
    return (results = zip(r, gaps), coeffs = coeffs)
end

function estimatedelay(m::Petri.Model, u0, tspan, parameters)
    gaps = paramsweep(sol -> peakgap(sol, 2, 10), m, u0, tspan, parameters)
    coeffs = linreg(βrange, gaps)
    return (results = zip(parameters, gaps), coeffs = coeffs)
end

slope(gs) = gs.coeffs[end]

gs = estimatedelay(βrange)
@test slope(gs) > 1
collect(gs.results)
gs.coeffs

using Catlab
using Catlab.Doctrines
using Catlab.Graphics
using Catlab.WiringDiagrams
using Catlab.Programs
using SemanticModels.CategoryTheory
import SemanticModels.CategoryTheory: undecorate, ⊔
using SemanticModels.PetriModels
using SemanticModels.PetriCospans
import SemanticModels: model

model(c::PetriCospan) = left(c.f).d[1].model

X = FinSet(1)
Fseir = compose(
    exposure(X, X, X),
    otimes(spontaneous(X, X), id(X)),
    mmerge(X),
    mcopy(X),
    otimes(id(X), spontaneous(X, X)),
)
# states are [S, I, E, R]
seir_petri = left(Fseir.f).d[1]
f = FinSetMorph(1:4, [1, 2, 3])
g = FinSetMorph(1:4, [1, 2, 3])
Fseir′ = PetriCospan(Cospan(Decorated(f, seir_petri), Decorated(g, seir_petri)))
s = spontaneous(X, X)
Fflow = otimes(s, s, s)
@test length(model(Fseir′).S) == 4
@test length(model(Fseir′).Δ) == 3

m = model(Fseir′ ⋅ Fflow ⋅ Fseir′ ⋅ Fflow ⋅ Fseir′)

u0 = zeros(Float64, length(m.S))
u0[1] = 10000
u0[5] = 10000
u0[9] = 10000
u0[2] = 1
res = estimatedelay(m::Petri.Model, u0, tspan, travelsweep(1:8))
seirgaps = collect(map(last, res.results))

@test 1.35 <= slope(res) <= 1.45

Pseird = PetriModel(Petri.Model(
    1:5,
    [
        ([1, 2], [3, 2]), # exposure
        ([3], [2]),     # onset
        ([2], [4]),     # recovery
        ([2], [5]),     # death
    ],
))
inputs = FinSetMorph(1:5, [1, 2, 3])
outputs = FinSetMorph(1:5, [1, 2, 3])
Fcityd =
    PetriCospan(Cospan(Decorated(inputs, Pseird), Decorated(outputs, Pseird)))
s = spontaneous(X, X)
Fflow = otimes(s, s, s)
Fcity₀ = Fcityd ⋅ Fflow
Fcity₁ = Fcityd ⋅ Fflow
Fcityₑ = Fcityd
Fcity³ = Fcity₀ ⋅ Fcity₁ ⋅ Fcityₑ

m = model(Fcity³)

u0 = zeros(Float64, length(m.S))
u0[1] = 10000
u0[6] = 10000
u0[11] = 10000
u0[2] = 1
seirdparams(k) = begin
    βseird = [10 / sum(u0), 1 / 2, 1 / 5, 1 / 16]
    βtravel = [1 / 2, 1 / 2, 1 / 2] / (100k)
    β = vcat(βseird, βtravel)
    return vcat(β, β, β)
end

gaps = paramsweep(
    sol -> peakgap(sol, 2, 12),
    m,
    u0,
    tspan,
    seirdparams.(2 .^ (1:8)),
)

prob = ODEProblem(fluxes(model(Fcity³)), u0, tspan, seirdparams(2))
sol = OrdinaryDiffEq.solve(prob, alg = Tsit5())

seirdgaps = gaps

@test model(Fcity³).S == 1:15
@test length(model(Fcity³).Δ) == 18

makeplots_seird(sol, "img/tmp")

gp = plot(
    [seirgaps seirdgaps],
    marker = :square,
    labels = [:seir :seird],
    xlabel = "2^x fold reduction in travel",
    ylabel = "Gap between first and last epidemic",
    legend = :bottomright,
    title = "Effect of model assumptions on travel restrictions",
)
savefig(gp, "img/gapplot.pdf")
end


text:
export strict_events_shuffle, strict_events_shuffle!, links_shuffle

"""
    strict_events_shuffle(G::SparseMatrixCSC{Events}, prob::Number)
    strict_events_shuffle!(G::SparseMatrixCSC{Events}, prob::Number)

- `prob` : `0 <= prob <= 1`

The following does the event shuffle as
in page 15/30 of modern temporal network theory a colloquim eur phys j b 2015.
After that it merges overlapping events between node pairs.
The number of events between node pairs will not be conserved
because it merges overlapping events.

The topology of the resulting network when it is flattened does not change
since only the event times are changed.
"""
strict_events_shuffle(G::SparseMatrixCSC{Events}, prob::Number) =
    strict_events_shuffle!(deepcopy(G),prob)
function strict_events_shuffle!(G::SparseMatrixCSC{Events}, prob::Number)
    I,J,V = findnz(G)
    ns = map(x -> length(x.timestamps), V)
    cns = cumsum(ns)
    n = cns[end] # number of events
    pcns = [0;cns]

    for u = 1:n
        if rand() < prob
            v = rand(1:n)

            uix = searchsorted(cns,u).start # pick uth = (uix,ui) and vth = (vix,vi) event
            vix = searchsorted(cns,v).start
            ui = u-pcns[uix]
            vi = v-pcns[vix]

            temp = V[uix].timestamps[ui]
            V[uix].timestamps[ui] = V[vix].timestamps[vi]
            V[vix].timestamps[vi] = temp
        end
    end
    V = map(x -> Events(mergeevents!(sort!(x.timestamps))), V)
    sparse(I, J, V, size(G,1), size(G,2), mergeevents)
end

function stack(xs::AbstractVector{<:AbstractVector})
    ns = map(length, xs)
    ys = Vector{eltype(eltype(xs))}(sum(ns))
    k = 1
    for x in xs
        for z in x
            ys[k] = z
            k += 1
        end
    end
    ys
end

"""
    links_shuffle(G::SparseMatrixCSC{Events}, prob::Number)

- `prob` : `0 <= prob <= 1`

Page 16/30 of modern temporal network theory.
Rewires each link with probability `prob`.
"""
function links_shuffle(G::SparseMatrixCSC{Events}, prob::Number)
    Ih,Jh,Vh = findnz(G)
    ns = map(x -> length(x.timestamps), Vh)
    I = stack(map(i -> fill(Ih[i],ns[i]), 1:length(Vh)))
    J = stack(map(i -> fill(Jh[i],ns[i]), 1:length(Vh)))
    V = stack(map(x -> x.timestamps, Vh))
    n = sum(ns)
    for u = 1:length(V)
        if rand() < prob
            noselflink = false
            i,j,ip,jp = 0,0,0,0
            v = 0
            while !noselflink
                v = rand(1:n)
                i,j,ip,jp = I[u],J[u],I[v],J[v]
                # Pick link (i,j) and (i',j')
                if rand() < 0.5
                    # Replace (i,j)  and (i',j')
                    #      by (i,j') and (i',j)
                    i,j,ip,jp = i,jp,ip,j
                else
                    # Replace (i,j)  and (i',j')
                    #      by (i,i') and (j,j')
                    i,j,ip,jp = i,ip,j,jp
                end
                if !(i==j || ip==jp) && !(min(i,j)==min(ip,jp) && max(i,j)==max(ip,jp))
                    noselflink = true
                end
            end
            I[u],J[u] = min(i,j),max(i,j)
            I[v],J[v] = min(ip,jp),max(ip,jp)
        end
    end
    sparse(I, J, map(x -> Events([x]), V), size(G,1), size(G,1), mergeevents)
end


text:
using FastTransforms, LinearAlgebra

function oprec!(n::Integer, v::AbstractVector, alpha::Real, delta2::Real)
    if n > 0
        v[1] = 1
    end
    if n > 1
        v[2] = (4*alpha+8-(alpha+4)*delta2)/4
    end
    for i = 1:n-2
        v[i+2] = (((2*i+alpha+2)*(2*i+alpha+4)+alpha*(alpha+2))/(2*(i+1)*(2*i+alpha+2))*(2*i+alpha+3)/(i+alpha+3) - delta2/4*(2*i+alpha+3)/(i+1)*(2*i+alpha+4)/(i+alpha+3))*v[i+1] - (i+alpha+1)/(i+alpha+3)*(2*i+alpha+4)/(2*i+alpha+2)*v[i]
    end
    return v
end

"""
This example calculates the spectrum of the nonlocal diffusion operator:

```math
ℒ_δ u = ∫_𝕊² ρ_δ(|𝐱-𝐲|)[u(𝐱) - u(𝐲)] dΩ(𝐲),
```

defined in Eq. (2) of

    R. M. Slevinsky, H. Montanelli, and Q. Du, A spectral method for nonlocal diffusion operators on the sphere, J. Comp. Phys., 372:893--911, 2018.

available at https://doi.org/10.1016/j.jcp.2018.06.024
"""
function evaluate_lambda(n::Integer, alpha::T, delta::T) where T
    delta2 = delta*delta
    scl = (1+alpha)*(2-delta2/2)

    lambda = Vector{T}(undef, n)

    if n > 0
        lambda[1] = 0
    end
    if n > 1
        lambda[2] = -2
    end

    oprec!(n-2, view(lambda, 3:n), alpha, delta2)

    for i = 2:n-1
        lambda[i+1] *= -scl/(i-1)
    end

    p = plan_jac2jac(T, n-1, zero(T), zero(T), alpha, zero(T))

    lambda[2:end] .= p'lambda[2:end]

    for i = 2:n-1
        lambda[i+1] = ((2i-1)*lambda[i+1] + (i-1)*lambda[i])/i
    end

    for i = 2:n-1
        lambda[i+1] += lambda[i]
    end

    return lambda
end

lambda = evaluate_lambda(1024, -0.5, 1.0)
lambdabf = evaluate_lambda(1024, parse(BigFloat, "-0.5"), parse(BigFloat, "1.0"))

norm(lambda-lambdabf, Inf)/norm(lambda, Inf)


text:
"""
    @snapshotoutput(name)

A function that returns some instantaneous output about a time-varying solution should have
the signature `name(state,constraint,sys::ILMSystem,t[,kwargs...])`, where `state` is a solution vector
(of the same type as returned by `state(zeros_sol(sys))`), `constraint` is
of the same type as returned by `constraint(zeros_sol(sys))`),
`sys` is the system struct,
`t` is time, and `kwargs` are any additional keyword arguments. This macro
extends that function so that it will also operate on the integrator
e.g, `name(integrator)`, and the solution history array `sol`, e.g.,
`name(sol::ODESolution,sys,t)`, using interpolation for values of `t` that are not explicitly
in the solution array. It can also take a range of values of `t`, e.g,
`name(sol::ODESolution,sys,0.1:0.01:0.2)`.
"""
macro snapshotoutput(name)

  return esc(quote

      $name(u::ConstrainedSystems.ArrayPartition,sys::ILMSystem{S,P,N},t,args...;kwargs...) where {S,P,N} = $name(state(u),constraint(u),sys,t,args...;kwargs...)

      $name(u::ConstrainedSystems.ArrayPartition,sys::ILMSystem{S,P,0},t,args...;kwargs...) where {S,P} = $name(state(u),zeros_surface(sys),sys,t,args...;kwargs...)

      $name(integ::ConstrainedSystems.OrdinaryDiffEq.ODEIntegrator,args...;kwargs...) = $name(integ.u,integ.p,integ.t,args...;kwargs...)

      $name(sol::ConstrainedSystems.OrdinaryDiffEq.ODESolution,sys::ILMSystem,t::Real,args...;kwargs...) = $name(sol(t),sys,t,args...;kwargs...)

      $name(sol::ConstrainedSystems.OrdinaryDiffEq.ODESolution,sys::ILMSystem,t::AbstractArray,args...;kwargs...) =
          map(ti -> $name(sol(ti),sys,ti,args...;kwargs...),t)

      export $name

  end)

end

"""
    @scalarsurfacemetric(name)

A function that returns a time-varying scalar surface metric should have
the signature `name(state,constraint,sys::ILMSystem,t,bodyid,[,kwargs...])`, where `state` is a solution vector
(of the same type as returned by `state(zeros_sol(sys))`), `constraint` is
of the same type as returned by `constraint(zeros_sol(sys))`),
`sys` is the system struct,
`t` is time, `bodyid` is the body ID, and `kwargs` are any additional keyword arguments. This macro
extends that function so that it will also operate on the integrator
e.g, `name(integrator,bodyid)`, and the solution history array `sol`, e.g.,
`name(sol::ODESolution,sys,t,bodyid)`, using interpolation for values of `t` that are not explicitly
in the solution array. It can also take a range of values of `t`, e.g,
`name(sol::ODESolution,sys,0.1:0.01:0.2,bodyid)`. And finally, it
can simply take `name(sol::ODESolution,sys,bodyid)` to return
the entire history.
"""
macro scalarsurfacemetric(name)
    return esc(quote
        function $name(sol::ConstrainedSystems.OrdinaryDiffEq.ODESolution,sys::ILMSystem,bodyid::Int;kwargs...)
            mom = map((u,t) -> $name(u,sys,t,bodyid;kwargs...),sol.u,sol.t)
            mom
        end

        @snapshotoutput $name
    end)
end

"""
    @vectorsurfacemetric(name)

A function that returns a time-varying scalar surface metric should have
the signature `name(state,constraint,sys::ILMSystem,t,bodyid,[,kwargs...])`, where `state` is a solution vector
(of the same type as returned by `state(zeros_sol(sys))`), `constraint` is
of the same type as returned by `constraint(zeros_sol(sys))`),
`sys` is the system struct,
`t` is time, `bodyid` is the body ID, and `kwargs` are any additional keyword arguments. This macro
extends that function so that it will also operate on the integrator
e.g, `name(integrator,bodyid)`, and the solution history array `sol`, e.g.,
`name(sol::ODESolution,sys,t,bodyid)`, using interpolation for values of `t` that are not explicitly
in the solution array. It can also take a range of values of `t`, e.g,
`name(sol::ODESolution,sys,0.1:0.01:0.2,bodyid)`. And finally, it
can simply take `name(sol::ODESolution,sys,bodyid)` to return
the entire history.
"""
macro vectorsurfacemetric(name)
    return esc(quote
        function $name(sol::ConstrainedSystems.OrdinaryDiffEq.ODESolution,sys::ILMSystem,bodyid::Int;kwargs...)
            vx = map((u,t) -> $name(u,sys,t,bodyid;kwargs...)[1],sol.u,sol.t)
            vy = map((u,t) -> $name(u,sys,t,bodyid;kwargs...)[2],sol.u,sol.t)
            vx, vy
        end

        @snapshotoutput $name
    end)
end


text:
using SpatialIndexing
using Test, Random

const SI=SpatialIndexing

include("regions.jl")
include("rtree.jl")


text:
using TableDistances
using Tables
using Test
using CategoricalArrays
using CoDa
using Distances
using ScientificTypes

@testset "TableDistances.jl" begin
  @testset "Pairwise" begin
    # test data
    table₁ = (a = rand(4), b = rand(Composition{5}, 4))
    table₂ = (a = rand(6), b = rand(Composition{5}, 6))
    table₃ = (a = categorical(["a", "b", "a", "c"]), b = categorical([1, 4, 1, 5]))

    # specific columns
    euclidcol₁ = Tables.getcolumn(table₁, :a)
    euclidcol₂ = Tables.getcolumn(table₂, :a)
    codacol₁   = Tables.getcolumn(table₁, :b)
    codacol₂   = Tables.getcolumn(table₂, :b)
    multiclass = Tables.getcolumn(table₃, :a)
    ordered    = Tables.getcolumn(table₃, :b)

    # column normalization
    D₁ = pairwise(TableDistance(normalize=true), table₁, table₂)
    D₂ = pairwise(TableDistance(normalize=false), table₁, table₂)
    D₃ = 0.5*pairwise(Euclidean(), euclidcol₁, euclidcol₂) +
         0.5*pairwise(Aitchison(), codacol₁, codacol₂)
    @test sum(D₁ .≤ D₂) > 4*6/2
    @test D₂ ≈ D₃

    # non-uniform weights
    D₁ = pairwise(TableDistance(normalize=false, weights=Dict(:a => 2., :b => 8.)), table₁, table₂)
    D₂ = 0.2*pairwise(Euclidean(), euclidcol₁, euclidcol₂) +
         0.8*pairwise(Aitchison(), codacol₁, codacol₂)
    @test D₁ ≈ D₂

    # pairwise with single table
    D₁ = pairwise(TableDistance(normalize=false), table₁)
    D₂ = 0.5*pairwise(Euclidean(), euclidcol₁) +
         0.5*pairwise(Aitchison(), codacol₁)
    @test D₁ ≈ D₂

    # pairwise with multiclass and ordered factor
    table₃ = coerce(table₃, :a => Multiclass, :b => OrderedFactor)
    D₁ = pairwise(TableDistance(normalize=false), table₃)
    D₂ = 0.5*pairwise(TableDistances.MulticlassDistance(), multiclass) +
         0.5*pairwise(TableDistances.OrderedFactorDistance(), ordered)
    @test D₁ ≈ D₂
  end
end


text:
using Persa
using DatasetsCF
using Test

# write your own tests here
ds = DatasetsCF.MovieLens()
@test Persa.users(ds) == 943
@test Persa.items(ds) == 1682
@test Persa.size(ds.preference) == 5
@test Persa.minimum(ds.preference) == 1
@test Persa.maximum(ds.preference) == 5

ds = DatasetsCF.MovieLens1M()
@test Persa.users(ds) == 6040
@test Persa.items(ds) == 3706
@test Persa.size(ds.preference) == 5
@test Persa.minimum(ds.preference) == 1
@test Persa.maximum(ds.preference) == 5


text:
module problem125

description = """
Palindromic sums

The palindromic number 595 is interesting because it can be written as the sum of consecutive squares: 6^2 + 7^2 + 8^2 + 9^2 + 10^2 + 11^2 + 12^2.
There are exactly eleven palindromes below one-thousand that can be written as consecutive square sums, and the sum of these palindromes is 4164.
Note that 1 = 0^2 + 1^2 has not been included as this problem is concerned with the squares of positive integers.
Find the sum of all the numbers less than 10^8 that are both palindromic and can be written as the sum of consecutive squares.
"""

function palendromic(n)
  digits = Int[]
  while n > 0
    push!(digits, n % 10)
    n = div(n, 10)
  end
  return digits == digits[end:-1:1]
end

function squaresFrom(i, maxSq)
  k = 2
  n = i^2 + (i+1)^2
  result = Int[]
  while n < maxSq
    push!(result, n)
    n += (i+k)^2
    k += 1
  end
  return result
end

function palendromicSquares(n)
  for i = 1:sqrt(n), sq in filter(palendromic, squaresFrom(i, n))
    produce(sq)
  end
end

function solve(n=10^8)
  return sum(unique(@task palendromicSquares(n)))
end

using Base.Test

@test palendromic(595)
@test !palendromic(1234)
@test solve(1000) == 4164

end

max_stars_repo_name: mbuhot/mbuhot-euler-solutions

max_issues_repo_name: mbuhot/mbuhot-euler-solutions

max_forks_repo_name: mbuhot/mbuhot-euler-solutions