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

"""
    assume_role(role_arn, role_session_name)
    assume_role(role_arn, role_session_name, params::Dict{String,<:Any})

Returns a set of temporary security credentials that you can use to access AWS resources
that you might not normally have access to. These temporary credentials consist of an
access key ID, a secret access key, and a security token. Typically, you use AssumeRole
within your account or for cross-account access. For a comparison of AssumeRole with other
API operations that produce temporary credentials, see Requesting Temporary Security
Credentials and Comparing the AWS STS API operations in the IAM User Guide.  You cannot use
AWS account root user credentials to call AssumeRole. You must use credentials for an IAM
user or an IAM role to call AssumeRole.  For cross-account access, imagine that you own
multiple accounts and need to access resources in each account. You could create long-term
credentials in each account to access those resources. However, managing all those
credentials and remembering which one can access which account can be time consuming.
Instead, you can create one set of long-term credentials in one account. Then use temporary
security credentials to access all the other accounts by assuming roles in those accounts.
For more information about roles, see IAM Roles in the IAM User Guide.   Session Duration
By default, the temporary security credentials created by AssumeRole last for one hour.
However, you can use the optional DurationSeconds parameter to specify the duration of your
session. You can provide a value from 900 seconds (15 minutes) up to the maximum session
duration setting for the role. This setting can have a value from 1 hour to 12 hours. To
learn how to view the maximum value for your role, see View the Maximum Session Duration
Setting for a Role in the IAM User Guide. The maximum session duration limit applies when
you use the AssumeRole* API operations or the assume-role* CLI commands. However the limit
does not apply when you use those operations to create a console URL. For more information,
see Using IAM Roles in the IAM User Guide.  Permissions  The temporary security credentials
created by AssumeRole can be used to make API calls to any AWS service with the following
exception: You cannot call the AWS STS GetFederationToken or GetSessionToken API
operations. (Optional) You can pass inline or managed session policies to this operation.
You can pass a single JSON policy document to use as an inline session policy. You can also
specify up to 10 managed policies to use as managed session policies. The plain text that
you use for both inline and managed session policies can't exceed 2,048 characters. Passing
policies to this operation returns new temporary credentials. The resulting session's
permissions are the intersection of the role's identity-based policy and the session
policies. You can use the role's temporary credentials in subsequent AWS API calls to
access resources in the account that owns the role. You cannot use session policies to
grant more permissions than those allowed by the identity-based policy of the role that is
being assumed. For more information, see Session Policies in the IAM User Guide. To assume
a role from a different account, your AWS account must be trusted by the role. The trust
relationship is defined in the role's trust policy when the role is created. That trust
policy states which accounts are allowed to delegate that access to users in the account.
A user who wants to access a role in a different account must also have permissions that
are delegated from the user account administrator. The administrator must attach a policy
that allows the user to call AssumeRole for the ARN of the role in the other account. If
the user is in the same account as the role, then you can do either of the following:
Attach a policy to the user (identical to the previous user in a different account).   Add
the user as a principal directly in the role's trust policy.   In this case, the trust
policy acts as an IAM resource-based policy. Users in the same account as the role do not
need explicit permission to assume the role. For more information about trust policies and
resource-based policies, see IAM Policies in the IAM User Guide.  Tags  (Optional) You can
pass tag key-value pairs to your session. These tags are called session tags. For more
information about session tags, see Passing Session Tags in STS in the IAM User Guide. An
administrator must grant you the permissions necessary to pass session tags. The
administrator can also create granular permissions to allow you to pass only specific
session tags. For more information, see Tutorial: Using Tags for Attribute-Based Access
Control in the IAM User Guide. You can set the session tags as transitive. Transitive tags
persist during role chaining. For more information, see Chaining Roles with Session Tags in
the IAM User Guide.  Using MFA with AssumeRole  (Optional) You can include multi-factor
authentication (MFA) information when you call AssumeRole. This is useful for cross-account
scenarios to ensure that the user that assumes the role has been authenticated with an AWS
MFA device. In that scenario, the trust policy of the role being assumed includes a
condition that tests for MFA authentication. If the caller does not include valid MFA
information, the request to assume the role is denied. The condition in a trust policy that
tests for MFA authentication might look like the following example.  \"Condition\":
{\"Bool\": {\"aws:MultiFactorAuthPresent\": true}}  For more information, see Configuring
MFA-Protected API Access in the IAM User Guide guide. To use MFA with AssumeRole, you pass
values for the SerialNumber and TokenCode parameters. The SerialNumber value identifies the
user's hardware or virtual MFA device. The TokenCode is the time-based one-time password
(TOTP) that the MFA device produces.

# Arguments
- `role_arn`: The Amazon Resource Name (ARN) of the role to assume.
- `role_session_name`: An identifier for the assumed role session. Use the role session
  name to uniquely identify a session when the same role is assumed by different principals
  or for different reasons. In cross-account scenarios, the role session name is visible to,
  and can be logged by the account that owns the role. The role session name is also used in
  the ARN of the assumed role principal. This means that subsequent cross-account API
  requests that use the temporary security credentials will expose the role session name to
  the external account in their AWS CloudTrail logs. The regex used to validate this
  parameter is a string of characters consisting of upper- and lower-case alphanumeric
  characters with no spaces. You can also include underscores or any of the following
  characters: =,.@-

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DurationSeconds"`: The duration, in seconds, of the role session. The value can range
  from 900 seconds (15 minutes) up to the maximum session duration setting for the role. This
  setting can have a value from 1 hour to 12 hours. If you specify a value higher than this
  setting, the operation fails. For example, if you specify a session duration of 12 hours,
  but your administrator set the maximum session duration to 6 hours, your operation fails.
  To learn how to view the maximum value for your role, see View the Maximum Session Duration
  Setting for a Role in the IAM User Guide. By default, the value is set to 3600 seconds.
  The DurationSeconds parameter is separate from the duration of a console session that you
  might request using the returned credentials. The request to the federation endpoint for a
  console sign-in token takes a SessionDuration parameter that specifies the maximum length
  of the console session. For more information, see Creating a URL that Enables Federated
  Users to Access the AWS Management Console in the IAM User Guide.
- `"ExternalId"`: A unique identifier that might be required when you assume a role in
  another account. If the administrator of the account to which the role belongs provided you
  with an external ID, then provide that value in the ExternalId parameter. This value can be
  any string, such as a passphrase or account number. A cross-account role is usually set up
  to trust everyone in an account. Therefore, the administrator of the trusting account might
  send an external ID to the administrator of the trusted account. That way, only someone
  with the ID can assume the role, rather than everyone in the account. For more information
  about the external ID, see How to Use an External ID When Granting Access to Your AWS
  Resources to a Third Party in the IAM User Guide. The regex used to validate this parameter
  is a string of characters consisting of upper- and lower-case alphanumeric characters with
  no spaces. You can also include underscores or any of the following characters: =,.@:/-
- `"Policy"`: An IAM policy in JSON format that you want to use as an inline session
  policy. This parameter is optional. Passing policies to this operation returns new
  temporary credentials. The resulting session's permissions are the intersection of the
  role's identity-based policy and the session policies. You can use the role's temporary
  credentials in subsequent AWS API calls to access resources in the account that owns the
  role. You cannot use session policies to grant more permissions than those allowed by the
  identity-based policy of the role that is being assumed. For more information, see Session
  Policies in the IAM User Guide. The plain text that you use for both inline and managed
  session policies can't exceed 2,048 characters. The JSON policy characters can be any ASCII
  character from the space character to the end of the valid character list (u0020 through
  u00FF). It can also include the tab (u0009), linefeed (u000A), and carriage return (u000D)
  characters.  An AWS conversion compresses the passed session policies and session tags into
  a packed binary format that has a separate limit. Your request can fail for this limit even
  if your plain text meets the other requirements. The PackedPolicySize response element
  indicates by percentage how close the policies and tags for your request are to the upper
  size limit.
- `"PolicyArns"`: The Amazon Resource Names (ARNs) of the IAM managed policies that you
  want to use as managed session policies. The policies must exist in the same account as the
  role. This parameter is optional. You can provide up to 10 managed policy ARNs. However,
  the plain text that you use for both inline and managed session policies can't exceed 2,048
  characters. For more information about ARNs, see Amazon Resource Names (ARNs) and AWS
  Service Namespaces in the AWS General Reference.  An AWS conversion compresses the passed
  session policies and session tags into a packed binary format that has a separate limit.
  Your request can fail for this limit even if your plain text meets the other requirements.
  The PackedPolicySize response element indicates by percentage how close the policies and
  tags for your request are to the upper size limit.   Passing policies to this operation
  returns new temporary credentials. The resulting session's permissions are the intersection
  of the role's identity-based policy and the session policies. You can use the role's
  temporary credentials in subsequent AWS API calls to access resources in the account that
  owns the role. You cannot use session policies to grant more permissions than those allowed
  by the identity-based policy of the role that is being assumed. For more information, see
  Session Policies in the IAM User Guide.
- `"SerialNumber"`: The identification number of the MFA device that is associated with the
  user who is making the AssumeRole call. Specify this value if the trust policy of the role
  being assumed includes a condition that requires MFA authentication. The value is either
  the serial number for a hardware device (such as GAHT12345678) or an Amazon Resource Name
  (ARN) for a virtual device (such as arn:aws:iam::123456789012:mfa/user). The regex used to
  validate this parameter is a string of characters consisting of upper- and lower-case
  alphanumeric characters with no spaces. You can also include underscores or any of the
  following characters: =,.@-
- `"Tags"`: A list of session tags that you want to pass. Each session tag consists of a
  key name and an associated value. For more information about session tags, see Tagging AWS
  STS Sessions in the IAM User Guide. This parameter is optional. You can pass up to 50
  session tags. The plain text session tag keys can’t exceed 128 characters, and the values
  can’t exceed 256 characters. For these and additional limits, see IAM and STS Character
  Limits in the IAM User Guide.  An AWS conversion compresses the passed session policies and
  session tags into a packed binary format that has a separate limit. Your request can fail
  for this limit even if your plain text meets the other requirements. The PackedPolicySize
  response element indicates by percentage how close the policies and tags for your request
  are to the upper size limit.   You can pass a session tag with the same key as a tag that
  is already attached to the role. When you do, session tags override a role tag with the
  same key.  Tag key–value pairs are not case sensitive, but case is preserved. This means
  that you cannot have separate Department and department tag keys. Assume that the role has
  the Department=Marketing tag and you pass the department=engineering session tag.
  Department and department are not saved as separate tags, and the session tag passed in the
  request takes precedence over the role tag. Additionally, if you used temporary credentials
  to perform this operation, the new session inherits any transitive session tags from the
  calling session. If you pass a session tag with the same key as an inherited tag, the
  operation fails. To view the inherited tags for a session, see the AWS CloudTrail logs. For
  more information, see Viewing Session Tags in CloudTrail in the IAM User Guide.
- `"TokenCode"`: The value provided by the MFA device, if the trust policy of the role
  being assumed requires MFA (that is, if the policy includes a condition that tests for
  MFA). If the role being assumed requires MFA and if the TokenCode value is missing or
  expired, the AssumeRole call returns an \"access denied\" error. The format for this
  parameter, as described by its regex pattern, is a sequence of six numeric digits.
- `"TransitiveTagKeys"`: A list of keys for session tags that you want to set as
  transitive. If you set a tag key as transitive, the corresponding key and value passes to
  subsequent sessions in a role chain. For more information, see Chaining Roles with Session
  Tags in the IAM User Guide. This parameter is optional. When you set session tags as
  transitive, the session policy and session tags packed binary limit is not affected. If you
  choose not to specify a transitive tag key, then no tags are passed from this session to
  any subsequent sessions.
"""
assume_role(RoleArn, RoleSessionName; aws_config::AbstractAWSConfig=global_aws_config()) = sts("AssumeRole", Dict{String, Any}("RoleArn"=>RoleArn, "RoleSessionName"=>RoleSessionName); aws_config=aws_config)
assume_role(RoleArn, RoleSessionName, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = sts("AssumeRole", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("RoleArn"=>RoleArn, "RoleSessionName"=>RoleSessionName), params)); aws_config=aws_config)

"""
    assume_role_with_saml(principal_arn, role_arn, samlassertion)
    assume_role_with_saml(principal_arn, role_arn, samlassertion, params::Dict{String,<:Any})

Returns a set of temporary security credentials for users who have been authenticated via a
SAML authentication response. This operation provides a mechanism for tying an enterprise
identity store or directory to role-based AWS access without user-specific credentials or
configuration. For a comparison of AssumeRoleWithSAML with the other API operations that
produce temporary credentials, see Requesting Temporary Security Credentials and Comparing
the AWS STS API operations in the IAM User Guide. The temporary security credentials
returned by this operation consist of an access key ID, a secret access key, and a security
token. Applications can use these temporary security credentials to sign calls to AWS
services.  Session Duration  By default, the temporary security credentials created by
AssumeRoleWithSAML last for one hour. However, you can use the optional DurationSeconds
parameter to specify the duration of your session. Your role session lasts for the duration
that you specify, or until the time specified in the SAML authentication response's
SessionNotOnOrAfter value, whichever is shorter. You can provide a DurationSeconds value
from 900 seconds (15 minutes) up to the maximum session duration setting for the role. This
setting can have a value from 1 hour to 12 hours. To learn how to view the maximum value
for your role, see View the Maximum Session Duration Setting for a Role in the IAM User
Guide. The maximum session duration limit applies when you use the AssumeRole* API
operations or the assume-role* CLI commands. However the limit does not apply when you use
those operations to create a console URL. For more information, see Using IAM Roles in the
IAM User Guide.  Permissions  The temporary security credentials created by
AssumeRoleWithSAML can be used to make API calls to any AWS service with the following
exception: you cannot call the STS GetFederationToken or GetSessionToken API operations.
(Optional) You can pass inline or managed session policies to this operation. You can pass
a single JSON policy document to use as an inline session policy. You can also specify up
to 10 managed policies to use as managed session policies. The plain text that you use for
both inline and managed session policies can't exceed 2,048 characters. Passing policies to
this operation returns new temporary credentials. The resulting session's permissions are
the intersection of the role's identity-based policy and the session policies. You can use
the role's temporary credentials in subsequent AWS API calls to access resources in the
account that owns the role. You cannot use session policies to grant more permissions than
those allowed by the identity-based policy of the role that is being assumed. For more
information, see Session Policies in the IAM User Guide. Calling AssumeRoleWithSAML does
not require the use of AWS security credentials. The identity of the caller is validated by
using keys in the metadata document that is uploaded for the SAML provider entity for your
identity provider.   Calling AssumeRoleWithSAML can result in an entry in your AWS
CloudTrail logs. The entry includes the value in the NameID element of the SAML assertion.
We recommend that you use a NameIDType that is not associated with any personally
identifiable information (PII). For example, you could instead use the persistent
identifier (urn:oasis:names:tc:SAML:2.0:nameid-format:persistent).   Tags  (Optional) You
can configure your IdP to pass attributes into your SAML assertion as session tags. Each
session tag consists of a key name and an associated value. For more information about
session tags, see Passing Session Tags in STS in the IAM User Guide. You can pass up to 50
session tags. The plain text session tag keys can’t exceed 128 characters and the values
can’t exceed 256 characters. For these and additional limits, see IAM and STS Character
Limits in the IAM User Guide.  An AWS conversion compresses the passed session policies and
session tags into a packed binary format that has a separate limit. Your request can fail
for this limit even if your plain text meets the other requirements. The PackedPolicySize
response element indicates by percentage how close the policies and tags for your request
are to the upper size limit.   You can pass a session tag with the same key as a tag that
is attached to the role. When you do, session tags override the role's tags with the same
key. An administrator must grant you the permissions necessary to pass session tags. The
administrator can also create granular permissions to allow you to pass only specific
session tags. For more information, see Tutorial: Using Tags for Attribute-Based Access
Control in the IAM User Guide. You can set the session tags as transitive. Transitive tags
persist during role chaining. For more information, see Chaining Roles with Session Tags in
the IAM User Guide.  SAML Configuration  Before your application can call
AssumeRoleWithSAML, you must configure your SAML identity provider (IdP) to issue the
claims required by AWS. Additionally, you must use AWS Identity and Access Management (IAM)
to create a SAML provider entity in your AWS account that represents your identity
provider. You must also create an IAM role that specifies this SAML provider in its trust
policy.  For more information, see the following resources:    About SAML 2.0-based
Federation in the IAM User Guide.     Creating SAML Identity Providers in the IAM User
Guide.     Configuring a Relying Party and Claims in the IAM User Guide.     Creating a
Role for SAML 2.0 Federation in the IAM User Guide.

# Arguments
- `principal_arn`: The Amazon Resource Name (ARN) of the SAML provider in IAM that
  describes the IdP.
- `role_arn`: The Amazon Resource Name (ARN) of the role that the caller is assuming.
- `samlassertion`: The base-64 encoded SAML authentication response provided by the IdP.
  For more information, see Configuring a Relying Party and Adding Claims in the IAM User
  Guide.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DurationSeconds"`: The duration, in seconds, of the role session. Your role session
  lasts for the duration that you specify for the DurationSeconds parameter, or until the
  time specified in the SAML authentication response's SessionNotOnOrAfter value, whichever
  is shorter. You can provide a DurationSeconds value from 900 seconds (15 minutes) up to the
  maximum session duration setting for the role. This setting can have a value from 1 hour to
  12 hours. If you specify a value higher than this setting, the operation fails. For
  example, if you specify a session duration of 12 hours, but your administrator set the
  maximum session duration to 6 hours, your operation fails. To learn how to view the maximum
  value for your role, see View the Maximum Session Duration Setting for a Role in the IAM
  User Guide. By default, the value is set to 3600 seconds.   The DurationSeconds parameter
  is separate from the duration of a console session that you might request using the
  returned credentials. The request to the federation endpoint for a console sign-in token
  takes a SessionDuration parameter that specifies the maximum length of the console session.
  For more information, see Creating a URL that Enables Federated Users to Access the AWS
  Management Console in the IAM User Guide.
- `"Policy"`: An IAM policy in JSON format that you want to use as an inline session
  policy. This parameter is optional. Passing policies to this operation returns new
  temporary credentials. The resulting session's permissions are the intersection of the
  role's identity-based policy and the session policies. You can use the role's temporary
  credentials in subsequent AWS API calls to access resources in the account that owns the
  role. You cannot use session policies to grant more permissions than those allowed by the
  identity-based policy of the role that is being assumed. For more information, see Session
  Policies in the IAM User Guide.  The plain text that you use for both inline and managed
  session policies can't exceed 2,048 characters. The JSON policy characters can be any ASCII
  character from the space character to the end of the valid character list (u0020 through
  u00FF). It can also include the tab (u0009), linefeed (u000A), and carriage return (u000D)
  characters.  An AWS conversion compresses the passed session policies and session tags into
  a packed binary format that has a separate limit. Your request can fail for this limit even
  if your plain text meets the other requirements. The PackedPolicySize response element
  indicates by percentage how close the policies and tags for your request are to the upper
  size limit.
- `"PolicyArns"`: The Amazon Resource Names (ARNs) of the IAM managed policies that you
  want to use as managed session policies. The policies must exist in the same account as the
  role. This parameter is optional. You can provide up to 10 managed policy ARNs. However,
  the plain text that you use for both inline and managed session policies can't exceed 2,048
  characters. For more information about ARNs, see Amazon Resource Names (ARNs) and AWS
  Service Namespaces in the AWS General Reference.  An AWS conversion compresses the passed
  session policies and session tags into a packed binary format that has a separate limit.
  Your request can fail for this limit even if your plain text meets the other requirements.
  The PackedPolicySize response element indicates by percentage how close the policies and
  tags for your request are to the upper size limit.   Passing policies to this operation
  returns new temporary credentials. The resulting session's permissions are the intersection
  of the role's identity-based policy and the session policies. You can use the role's
  temporary credentials in subsequent AWS API calls to access resources in the account that
  owns the role. You cannot use session policies to grant more permissions than those allowed
  by the identity-based policy of the role that is being assumed. For more information, see
  Session Policies in the IAM User Guide.
"""
assume_role_with_saml(PrincipalArn, RoleArn, SAMLAssertion; aws_config::AbstractAWSConfig=global_aws_config()) = sts("AssumeRoleWithSAML", Dict{String, Any}("PrincipalArn"=>PrincipalArn, "RoleArn"=>RoleArn, "SAMLAssertion"=>SAMLAssertion); aws_config=aws_config)
assume_role_with_saml(PrincipalArn, RoleArn, SAMLAssertion, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = sts("AssumeRoleWithSAML", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("PrincipalArn"=>PrincipalArn, "RoleArn"=>RoleArn, "SAMLAssertion"=>SAMLAssertion), params)); aws_config=aws_config)

"""
    assume_role_with_web_identity(role_arn, role_session_name, web_identity_token)
    assume_role_with_web_identity(role_arn, role_session_name, web_identity_token, params::Dict{String,<:Any})

Returns a set of temporary security credentials for users who have been authenticated in a
mobile or web application with a web identity provider. Example providers include Amazon
Cognito, Login with Amazon, Facebook, Google, or any OpenID Connect-compatible identity
provider.  For mobile applications, we recommend that you use Amazon Cognito. You can use
Amazon Cognito with the AWS SDK for iOS Developer Guide and the AWS SDK for Android
Developer Guide to uniquely identify a user. You can also supply the user with a consistent
identity throughout the lifetime of an application. To learn more about Amazon Cognito, see
Amazon Cognito Overview in AWS SDK for Android Developer Guide and Amazon Cognito Overview
in the AWS SDK for iOS Developer Guide.  Calling AssumeRoleWithWebIdentity does not require
the use of AWS security credentials. Therefore, you can distribute an application (for
example, on mobile devices) that requests temporary security credentials without including
long-term AWS credentials in the application. You also don't need to deploy server-based
proxy services that use long-term AWS credentials. Instead, the identity of the caller is
validated by using a token from the web identity provider. For a comparison of
AssumeRoleWithWebIdentity with the other API operations that produce temporary credentials,
see Requesting Temporary Security Credentials and Comparing the AWS STS API operations in
the IAM User Guide. The temporary security credentials returned by this API consist of an
access key ID, a secret access key, and a security token. Applications can use these
temporary security credentials to sign calls to AWS service API operations.  Session
Duration  By default, the temporary security credentials created by
AssumeRoleWithWebIdentity last for one hour. However, you can use the optional
DurationSeconds parameter to specify the duration of your session. You can provide a value
from 900 seconds (15 minutes) up to the maximum session duration setting for the role. This
setting can have a value from 1 hour to 12 hours. To learn how to view the maximum value
for your role, see View the Maximum Session Duration Setting for a Role in the IAM User
Guide. The maximum session duration limit applies when you use the AssumeRole* API
operations or the assume-role* CLI commands. However the limit does not apply when you use
those operations to create a console URL. For more information, see Using IAM Roles in the
IAM User Guide.   Permissions  The temporary security credentials created by
AssumeRoleWithWebIdentity can be used to make API calls to any AWS service with the
following exception: you cannot call the STS GetFederationToken or GetSessionToken API
operations. (Optional) You can pass inline or managed session policies to this operation.
You can pass a single JSON policy document to use as an inline session policy. You can also
specify up to 10 managed policies to use as managed session policies. The plain text that
you use for both inline and managed session policies can't exceed 2,048 characters. Passing
policies to this operation returns new temporary credentials. The resulting session's
permissions are the intersection of the role's identity-based policy and the session
policies. You can use the role's temporary credentials in subsequent AWS API calls to
access resources in the account that owns the role. You cannot use session policies to
grant more permissions than those allowed by the identity-based policy of the role that is
being assumed. For more information, see Session Policies in the IAM User Guide.  Tags
(Optional) You can configure your IdP to pass attributes into your web identity token as
session tags. Each session tag consists of a key name and an associated value. For more
information about session tags, see Passing Session Tags in STS in the IAM User Guide. You
can pass up to 50 session tags. The plain text session tag keys can’t exceed 128
characters and the values can’t exceed 256 characters. For these and additional limits,
see IAM and STS Character Limits in the IAM User Guide.  An AWS conversion compresses the
passed session policies and session tags into a packed binary format that has a separate
limit. Your request can fail for this limit even if your plain text meets the other
requirements. The PackedPolicySize response element indicates by percentage how close the
policies and tags for your request are to the upper size limit.   You can pass a session
tag with the same key as a tag that is attached to the role. When you do, the session tag
overrides the role tag with the same key. An administrator must grant you the permissions
necessary to pass session tags. The administrator can also create granular permissions to
allow you to pass only specific session tags. For more information, see Tutorial: Using
Tags for Attribute-Based Access Control in the IAM User Guide. You can set the session tags
as transitive. Transitive tags persist during role chaining. For more information, see
Chaining Roles with Session Tags in the IAM User Guide.  Identities  Before your
application can call AssumeRoleWithWebIdentity, you must have an identity token from a
supported identity provider and create a role that the application can assume. The role
that your application assumes must trust the identity provider that is associated with the
identity token. In other words, the identity provider must be specified in the role's trust
policy.   Calling AssumeRoleWithWebIdentity can result in an entry in your AWS CloudTrail
logs. The entry includes the Subject of the provided Web Identity Token. We recommend that
you avoid using any personally identifiable information (PII) in this field. For example,
you could instead use a GUID or a pairwise identifier, as suggested in the OIDC
specification.  For more information about how to use web identity federation and the
AssumeRoleWithWebIdentity API, see the following resources:     Using Web Identity
Federation API Operations for Mobile Apps and Federation Through a Web-based Identity
Provider.      Web Identity Federation Playground. Walk through the process of
authenticating through Login with Amazon, Facebook, or Google, getting temporary security
credentials, and then using those credentials to make a request to AWS.     AWS SDK for iOS
Developer Guide and AWS SDK for Android Developer Guide. These toolkits contain sample apps
that show how to invoke the identity providers. The toolkits then show how to use the
information from these providers to get and use temporary security credentials.     Web
Identity Federation with Mobile Applications. This article discusses web identity
federation and shows an example of how to use web identity federation to get access to
content in Amazon S3.

# Arguments
- `role_arn`: The Amazon Resource Name (ARN) of the role that the caller is assuming.
- `role_session_name`: An identifier for the assumed role session. Typically, you pass the
  name or identifier that is associated with the user who is using your application. That
  way, the temporary security credentials that your application will use are associated with
  that user. This session name is included as part of the ARN and assumed role ID in the
  AssumedRoleUser response element. The regex used to validate this parameter is a string of
  characters consisting of upper- and lower-case alphanumeric characters with no spaces. You
  can also include underscores or any of the following characters: =,.@-
- `web_identity_token`: The OAuth 2.0 access token or OpenID Connect ID token that is
  provided by the identity provider. Your application must get this token by authenticating
  the user who is using your application with a web identity provider before the application
  makes an AssumeRoleWithWebIdentity call.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DurationSeconds"`: The duration, in seconds, of the role session. The value can range
  from 900 seconds (15 minutes) up to the maximum session duration setting for the role. This
  setting can have a value from 1 hour to 12 hours. If you specify a value higher than this
  setting, the operation fails. For example, if you specify a session duration of 12 hours,
  but your administrator set the maximum session duration to 6 hours, your operation fails.
  To learn how to view the maximum value for your role, see View the Maximum Session Duration
  Setting for a Role in the IAM User Guide. By default, the value is set to 3600 seconds.
  The DurationSeconds parameter is separate from the duration of a console session that you
  might request using the returned credentials. The request to the federation endpoint for a
  console sign-in token takes a SessionDuration parameter that specifies the maximum length
  of the console session. For more information, see Creating a URL that Enables Federated
  Users to Access the AWS Management Console in the IAM User Guide.
- `"Policy"`: An IAM policy in JSON format that you want to use as an inline session
  policy. This parameter is optional. Passing policies to this operation returns new
  temporary credentials. The resulting session's permissions are the intersection of the
  role's identity-based policy and the session policies. You can use the role's temporary
  credentials in subsequent AWS API calls to access resources in the account that owns the
  role. You cannot use session policies to grant more permissions than those allowed by the
  identity-based policy of the role that is being assumed. For more information, see Session
  Policies in the IAM User Guide. The plain text that you use for both inline and managed
  session policies can't exceed 2,048 characters. The JSON policy characters can be any ASCII
  character from the space character to the end of the valid character list (u0020 through
  u00FF). It can also include the tab (u0009), linefeed (u000A), and carriage return (u000D)
  characters.  An AWS conversion compresses the passed session policies and session tags into
  a packed binary format that has a separate limit. Your request can fail for this limit even
  if your plain text meets the other requirements. The PackedPolicySize response element
  indicates by percentage how close the policies and tags for your request are to the upper
  size limit.
- `"PolicyArns"`: The Amazon Resource Names (ARNs) of the IAM managed policies that you
  want to use as managed session policies. The policies must exist in the same account as the
  role. This parameter is optional. You can provide up to 10 managed policy ARNs. However,
  the plain text that you use for both inline and managed session policies can't exceed 2,048
  characters. For more information about ARNs, see Amazon Resource Names (ARNs) and AWS
  Service Namespaces in the AWS General Reference.  An AWS conversion compresses the passed
  session policies and session tags into a packed binary format that has a separate limit.
  Your request can fail for this limit even if your plain text meets the other requirements.
  The PackedPolicySize response element indicates by percentage how close the policies and
  tags for your request are to the upper size limit.   Passing policies to this operation
  returns new temporary credentials. The resulting session's permissions are the intersection
  of the role's identity-based policy and the session policies. You can use the role's
  temporary credentials in subsequent AWS API calls to access resources in the account that
  owns the role. You cannot use session policies to grant more permissions than those allowed
  by the identity-based policy of the role that is being assumed. For more information, see
  Session Policies in the IAM User Guide.
- `"ProviderId"`: The fully qualified host component of the domain name of the identity
  provider. Specify this value only for OAuth 2.0 access tokens. Currently www.amazon.com and
  graph.facebook.com are the only supported identity providers for OAuth 2.0 access tokens.
  Do not include URL schemes and port numbers. Do not specify this value for OpenID Connect
  ID tokens.
"""
assume_role_with_web_identity(RoleArn, RoleSessionName, WebIdentityToken; aws_config::AbstractAWSConfig=global_aws_config()) = sts("AssumeRoleWithWebIdentity", Dict{String, Any}("RoleArn"=>RoleArn, "RoleSessionName"=>RoleSessionName, "WebIdentityToken"=>WebIdentityToken); aws_config=aws_config)
assume_role_with_web_identity(RoleArn, RoleSessionName, WebIdentityToken, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = sts("AssumeRoleWithWebIdentity", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("RoleArn"=>RoleArn, "RoleSessionName"=>RoleSessionName, "WebIdentityToken"=>WebIdentityToken), params)); aws_config=aws_config)

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

Decodes additional information about the authorization status of a request from an encoded
message returned in response to an AWS request. For example, if a user is not authorized to
perform an operation that he or she has requested, the request returns a
Client.UnauthorizedOperation response (an HTTP 403 response). Some AWS operations
additionally return an encoded message that can provide details about this authorization
failure.   Only certain AWS operations return an encoded authorization message. The
documentation for an individual operation indicates whether that operation returns an
encoded message in addition to returning an HTTP code.  The message is encoded because the
details of the authorization status can constitute privileged information that the user who
requested the operation should not see. To decode an authorization status message, a user
must be granted permissions via an IAM policy to request the DecodeAuthorizationMessage
(sts:DecodeAuthorizationMessage) action.  The decoded message includes the following type
of information:   Whether the request was denied due to an explicit deny or due to the
absence of an explicit allow. For more information, see Determining Whether a Request is
Allowed or Denied in the IAM User Guide.    The principal who made the request.   The
requested action.   The requested resource.   The values of condition keys in the context
of the user's request.

# Arguments
- `encoded_message`: The encoded message that was returned with the response.

"""
decode_authorization_message(EncodedMessage; aws_config::AbstractAWSConfig=global_aws_config()) = sts("DecodeAuthorizationMessage", Dict{String, Any}("EncodedMessage"=>EncodedMessage); aws_config=aws_config)
decode_authorization_message(EncodedMessage, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = sts("DecodeAuthorizationMessage", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("EncodedMessage"=>EncodedMessage), params)); aws_config=aws_config)

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

Returns the account identifier for the specified access key ID. Access keys consist of two
parts: an access key ID (for example, AKIAIOSFODNN7EXAMPLE) and a secret access key (for
example, wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY). For more information about access keys,
see Managing Access Keys for IAM Users in the IAM User Guide. When you pass an access key
ID to this operation, it returns the ID of the AWS account to which the keys belong. Access
key IDs beginning with AKIA are long-term credentials for an IAM user or the AWS account
root user. Access key IDs beginning with ASIA are temporary credentials that are created
using STS operations. If the account in the response belongs to you, you can sign in as the
root user and review your root user access keys. Then, you can pull a credentials report to
learn which IAM user owns the keys. To learn who requested the temporary credentials for an
ASIA access key, view the STS events in your CloudTrail logs in the IAM User Guide. This
operation does not indicate the state of the access key. The key might be active, inactive,
or deleted. Active keys might not have permissions to perform an operation. Providing a
deleted access key might return an error that the key doesn't exist.

# Arguments
- `access_key_id`: The identifier of an access key. This parameter allows (through its
  regex pattern) a string of characters that can consist of any upper- or lowercase letter or
  digit.

"""
get_access_key_info(AccessKeyId; aws_config::AbstractAWSConfig=global_aws_config()) = sts("GetAccessKeyInfo", Dict{String, Any}("AccessKeyId"=>AccessKeyId); aws_config=aws_config)
get_access_key_info(AccessKeyId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = sts("GetAccessKeyInfo", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("AccessKeyId"=>AccessKeyId), params)); aws_config=aws_config)

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

Returns details about the IAM user or role whose credentials are used to call the
operation.  No permissions are required to perform this operation. If an administrator adds
a policy to your IAM user or role that explicitly denies access to the
sts:GetCallerIdentity action, you can still perform this operation. Permissions are not
required because the same information is returned when an IAM user or role is denied
access. To view an example response, see I Am Not Authorized to Perform:
iam:DeleteVirtualMFADevice in the IAM User Guide.

"""
get_caller_identity(; aws_config::AbstractAWSConfig=global_aws_config()) = sts("GetCallerIdentity"; aws_config=aws_config)
get_caller_identity(params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = sts("GetCallerIdentity", params; aws_config=aws_config)

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

Returns a set of temporary security credentials (consisting of an access key ID, a secret
access key, and a security token) for a federated user. A typical use is in a proxy
application that gets temporary security credentials on behalf of distributed applications
inside a corporate network. You must call the GetFederationToken operation using the
long-term security credentials of an IAM user. As a result, this call is appropriate in
contexts where those credentials can be safely stored, usually in a server-based
application. For a comparison of GetFederationToken with the other API operations that
produce temporary credentials, see Requesting Temporary Security Credentials and Comparing
the AWS STS API operations in the IAM User Guide.  You can create a mobile-based or
browser-based app that can authenticate users using a web identity provider like Login with
Amazon, Facebook, Google, or an OpenID Connect-compatible identity provider. In this case,
we recommend that you use Amazon Cognito or AssumeRoleWithWebIdentity. For more
information, see Federation Through a Web-based Identity Provider in the IAM User Guide.
You can also call GetFederationToken using the security credentials of an AWS account root
user, but we do not recommend it. Instead, we recommend that you create an IAM user for the
purpose of the proxy application. Then attach a policy to the IAM user that limits
federated users to only the actions and resources that they need to access. For more
information, see IAM Best Practices in the IAM User Guide.   Session duration  The
temporary credentials are valid for the specified duration, from 900 seconds (15 minutes)
up to a maximum of 129,600 seconds (36 hours). The default session duration is 43,200
seconds (12 hours). Temporary credentials that are obtained by using AWS account root user
credentials have a maximum duration of 3,600 seconds (1 hour).  Permissions  You can use
the temporary credentials created by GetFederationToken in any AWS service except the
following:   You cannot call any IAM operations using the AWS CLI or the AWS API.    You
cannot call any STS operations except GetCallerIdentity.   You must pass an inline or
managed session policy to this operation. You can pass a single JSON policy document to use
as an inline session policy. You can also specify up to 10 managed policies to use as
managed session policies. The plain text that you use for both inline and managed session
policies can't exceed 2,048 characters. Though the session policy parameters are optional,
if you do not pass a policy, then the resulting federated user session has no permissions.
When you pass session policies, the session permissions are the intersection of the IAM
user policies and the session policies that you pass. This gives you a way to further
restrict the permissions for a federated user. You cannot use session policies to grant
more permissions than those that are defined in the permissions policy of the IAM user. For
more information, see Session Policies in the IAM User Guide. For information about using
GetFederationToken to create temporary security credentials, see
GetFederationToken—Federation Through a Custom Identity Broker.  You can use the
credentials to access a resource that has a resource-based policy. If that policy
specifically references the federated user session in the Principal element of the policy,
the session has the permissions allowed by the policy. These permissions are granted in
addition to the permissions granted by the session policies.  Tags  (Optional) You can pass
tag key-value pairs to your session. These are called session tags. For more information
about session tags, see Passing Session Tags in STS in the IAM User Guide. An administrator
must grant you the permissions necessary to pass session tags. The administrator can also
create granular permissions to allow you to pass only specific session tags. For more
information, see Tutorial: Using Tags for Attribute-Based Access Control in the IAM User
Guide. Tag key–value pairs are not case sensitive, but case is preserved. This means that
you cannot have separate Department and department tag keys. Assume that the user that you
are federating has the Department=Marketing tag and you pass the department=engineering
session tag. Department and department are not saved as separate tags, and the session tag
passed in the request takes precedence over the user tag.

# Arguments
- `name`: The name of the federated user. The name is used as an identifier for the
  temporary security credentials (such as Bob). For example, you can reference the federated
  user name in a resource-based policy, such as in an Amazon S3 bucket policy. The regex used
  to validate this parameter is a string of characters consisting of upper- and lower-case
  alphanumeric characters with no spaces. You can also include underscores or any of the
  following characters: =,.@-

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DurationSeconds"`: The duration, in seconds, that the session should last. Acceptable
  durations for federation sessions range from 900 seconds (15 minutes) to 129,600 seconds
  (36 hours), with 43,200 seconds (12 hours) as the default. Sessions obtained using AWS
  account root user credentials are restricted to a maximum of 3,600 seconds (one hour). If
  the specified duration is longer than one hour, the session obtained by using root user
  credentials defaults to one hour.
- `"Policy"`: An IAM policy in JSON format that you want to use as an inline session
  policy. You must pass an inline or managed session policy to this operation. You can pass a
  single JSON policy document to use as an inline session policy. You can also specify up to
  10 managed policies to use as managed session policies. This parameter is optional.
  However, if you do not pass any session policies, then the resulting federated user session
  has no permissions. When you pass session policies, the session permissions are the
  intersection of the IAM user policies and the session policies that you pass. This gives
  you a way to further restrict the permissions for a federated user. You cannot use session
  policies to grant more permissions than those that are defined in the permissions policy of
  the IAM user. For more information, see Session Policies in the IAM User Guide. The
  resulting credentials can be used to access a resource that has a resource-based policy. If
  that policy specifically references the federated user session in the Principal element of
  the policy, the session has the permissions allowed by the policy. These permissions are
  granted in addition to the permissions that are granted by the session policies. The plain
  text that you use for both inline and managed session policies can't exceed 2,048
  characters. The JSON policy characters can be any ASCII character from the space character
  to the end of the valid character list (u0020 through u00FF). It can also include the tab
  (u0009), linefeed (u000A), and carriage return (u000D) characters.  An AWS conversion
  compresses the passed session policies and session tags into a packed binary format that
  has a separate limit. Your request can fail for this limit even if your plain text meets
  the other requirements. The PackedPolicySize response element indicates by percentage how
  close the policies and tags for your request are to the upper size limit.
- `"PolicyArns"`: The Amazon Resource Names (ARNs) of the IAM managed policies that you
  want to use as a managed session policy. The policies must exist in the same account as the
  IAM user that is requesting federated access. You must pass an inline or managed session
  policy to this operation. You can pass a single JSON policy document to use as an inline
  session policy. You can also specify up to 10 managed policies to use as managed session
  policies. The plain text that you use for both inline and managed session policies can't
  exceed 2,048 characters. You can provide up to 10 managed policy ARNs. For more information
  about ARNs, see Amazon Resource Names (ARNs) and AWS Service Namespaces in the AWS General
  Reference. This parameter is optional. However, if you do not pass any session policies,
  then the resulting federated user session has no permissions. When you pass session
  policies, the session permissions are the intersection of the IAM user policies and the
  session policies that you pass. This gives you a way to further restrict the permissions
  for a federated user. You cannot use session policies to grant more permissions than those
  that are defined in the permissions policy of the IAM user. For more information, see
  Session Policies in the IAM User Guide. The resulting credentials can be used to access a
  resource that has a resource-based policy. If that policy specifically references the
  federated user session in the Principal element of the policy, the session has the
  permissions allowed by the policy. These permissions are granted in addition to the
  permissions that are granted by the session policies.  An AWS conversion compresses the
  passed session policies and session tags into a packed binary format that has a separate
  limit. Your request can fail for this limit even if your plain text meets the other
  requirements. The PackedPolicySize response element indicates by percentage how close the
  policies and tags for your request are to the upper size limit.
- `"Tags"`: A list of session tags. Each session tag consists of a key name and an
  associated value. For more information about session tags, see Passing Session Tags in STS
  in the IAM User Guide. This parameter is optional. You can pass up to 50 session tags. The
  plain text session tag keys can’t exceed 128 characters and the values can’t exceed 256
  characters. For these and additional limits, see IAM and STS Character Limits in the IAM
  User Guide.  An AWS conversion compresses the passed session policies and session tags into
  a packed binary format that has a separate limit. Your request can fail for this limit even
  if your plain text meets the other requirements. The PackedPolicySize response element
  indicates by percentage how close the policies and tags for your request are to the upper
  size limit.   You can pass a session tag with the same key as a tag that is already
  attached to the user you are federating. When you do, session tags override a user tag with
  the same key.  Tag key–value pairs are not case sensitive, but case is preserved. This
  means that you cannot have separate Department and department tag keys. Assume that the
  role has the Department=Marketing tag and you pass the department=engineering session tag.
  Department and department are not saved as separate tags, and the session tag passed in the
  request takes precedence over the role tag.
"""
get_federation_token(Name; aws_config::AbstractAWSConfig=global_aws_config()) = sts("GetFederationToken", Dict{String, Any}("Name"=>Name); aws_config=aws_config)
get_federation_token(Name, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = sts("GetFederationToken", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Name"=>Name), params)); aws_config=aws_config)

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

Returns a set of temporary credentials for an AWS account or IAM user. The credentials
consist of an access key ID, a secret access key, and a security token. Typically, you use
GetSessionToken if you want to use MFA to protect programmatic calls to specific AWS API
operations like Amazon EC2 StopInstances. MFA-enabled IAM users would need to call
GetSessionToken and submit an MFA code that is associated with their MFA device. Using the
temporary security credentials that are returned from the call, IAM users can then make
programmatic calls to API operations that require MFA authentication. If you do not supply
a correct MFA code, then the API returns an access denied error. For a comparison of
GetSessionToken with the other API operations that produce temporary credentials, see
Requesting Temporary Security Credentials and Comparing the AWS STS API operations in the
IAM User Guide.  Session Duration  The GetSessionToken operation must be called by using
the long-term AWS security credentials of the AWS account root user or an IAM user.
Credentials that are created by IAM users are valid for the duration that you specify. This
duration can range from 900 seconds (15 minutes) up to a maximum of 129,600 seconds (36
hours), with a default of 43,200 seconds (12 hours). Credentials based on account
credentials can range from 900 seconds (15 minutes) up to 3,600 seconds (1 hour), with a
default of 1 hour.   Permissions  The temporary security credentials created by
GetSessionToken can be used to make API calls to any AWS service with the following
exceptions:   You cannot call any IAM API operations unless MFA authentication information
is included in the request.   You cannot call any STS API except AssumeRole or
GetCallerIdentity.    We recommend that you do not call GetSessionToken with AWS account
root user credentials. Instead, follow our best practices by creating one or more IAM
users, giving them the necessary permissions, and using IAM users for everyday interaction
with AWS.   The credentials that are returned by GetSessionToken are based on permissions
associated with the user whose credentials were used to call the operation. If
GetSessionToken is called using AWS account root user credentials, the temporary
credentials have root user permissions. Similarly, if GetSessionToken is called using the
credentials of an IAM user, the temporary credentials have the same permissions as the IAM
user.  For more information about using GetSessionToken to create temporary credentials, go
to Temporary Credentials for Users in Untrusted Environments in the IAM User Guide.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DurationSeconds"`: The duration, in seconds, that the credentials should remain valid.
  Acceptable durations for IAM user sessions range from 900 seconds (15 minutes) to 129,600
  seconds (36 hours), with 43,200 seconds (12 hours) as the default. Sessions for AWS account
  owners are restricted to a maximum of 3,600 seconds (one hour). If the duration is longer
  than one hour, the session for AWS account owners defaults to one hour.
- `"SerialNumber"`: The identification number of the MFA device that is associated with the
  IAM user who is making the GetSessionToken call. Specify this value if the IAM user has a
  policy that requires MFA authentication. The value is either the serial number for a
  hardware device (such as GAHT12345678) or an Amazon Resource Name (ARN) for a virtual
  device (such as arn:aws:iam::123456789012:mfa/user). You can find the device for an IAM
  user by going to the AWS Management Console and viewing the user's security credentials.
  The regex used to validate this parameter is a string of characters consisting of upper-
  and lower-case alphanumeric characters with no spaces. You can also include underscores or
  any of the following characters: =,.@:/-
- `"TokenCode"`: The value provided by the MFA device, if MFA is required. If any policy
  requires the IAM user to submit an MFA code, specify this value. If MFA authentication is
  required, the user must provide a code when requesting a set of temporary security
  credentials. A user who fails to provide the code receives an \"access denied\" response
  when requesting resources that require MFA authentication. The format for this parameter,
  as described by its regex pattern, is a sequence of six numeric digits.
"""
get_session_token(; aws_config::AbstractAWSConfig=global_aws_config()) = sts("GetSessionToken"; aws_config=aws_config)
get_session_token(params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = sts("GetSessionToken", params; aws_config=aws_config)


text:
# This file is a part of AstroLib.jl. License is MIT "Expat".
# Copyright (C) 2016 Mosè Giordano.

include("adstring.jl")
export adstring

include("airtovac.jl")
export airtovac

include("aitoff.jl")
export aitoff

include("altaz2hadec.jl")
export altaz2hadec

include("baryvel.jl")
export baryvel

include("bprecess.jl")
export bprecess

include("calz_unred.jl")
export calz_unred

include("co_aberration.jl")
export co_aberration

include("co_nutate.jl")
export co_nutate

include("co_refract.jl")
export co_refract

include("ct2lst.jl")
export ct2lst

include("daycnv.jl")
export daycnv

include("deredd.jl")
export deredd

include("eci2geo.jl")
export eci2geo

include("eq2hor.jl")
export eq2hor

include("eqpole.jl")
export eqpole

include("euler.jl")
export euler

include("flux2mag.jl")
export flux2mag

include("gal_uvw.jl")
export gal_uvw

include("geo2eci.jl")
export geo2eci

include("geo2geodetic.jl")
export geo2geodetic

include("geo2mag.jl")
export geo2mag

include("geodetic2geo.jl")
export geodetic2geo

include("get_date.jl")
export get_date

include("get_juldate.jl")
export get_juldate

include("gcirc.jl")
export gcirc

include("hadec2altaz.jl")
export hadec2altaz

include("helio_jd.jl")
export helio_jd

include("helio_rv.jl")
export helio_rv

include("helio.jl")
export helio

include("hor2eq.jl")
export hor2eq

include("imf.jl")
export imf

include("ismeuv.jl")
export ismeuv

include("jdcnv.jl")
export jdcnv

include("jprecess.jl")
export jprecess

include("juldate.jl")
export juldate

include("kepler_solver.jl")
export kepler_solver

include("lsf_rotate.jl")
export lsf_rotate

include("mag2flux.jl")
export mag2flux

include("mag2geo.jl")
export mag2geo

include("mean_obliquity.jl")
export mean_obliquity

include("month_cnv.jl")
export month_cnv

include("moonpos.jl")
export moonpos

include("mphase.jl")
export mphase

include("nutate.jl")
export nutate

include("paczynski.jl")
export paczynski

include("planck_freq.jl")
export planck_freq

include("planck_wave.jl")
export planck_wave

include("planet_coords.jl")
export planet_coords

include("polrec.jl")
export polrec

include("posang.jl")
export posang

include("precess.jl")
export precess

include("precess_cd.jl")
export precess_cd

include("precess_xyz.jl")
export precess_xyz

include("premat.jl")
export premat

include("radec.jl")
export radec

include("recpol.jl")
export recpol

include("rhotheta.jl")
export rhotheta

include("sixty.jl")
export sixty

include("sphdist.jl")
export sphdist

include("sunpos.jl")
export sunpos

include("ten.jl")
export ten

include("tic_one.jl")
export tic_one

include("ticpos.jl")
export ticpos

include("tics.jl")
export tics

include("true_obliquity.jl")
export true_obliquity

include("trueanom.jl")
export trueanom

include("uvbybeta.jl")
export uvbybeta

include("vactoair.jl")
export vactoair

include("xyz.jl")
export xyz

include("ydn2md.jl")
export ydn2md

include("ymd2dn.jl")
export ymd2dn

include("zenpos.jl")
export zenpos

ext: jl


text:
@testset "Config" begin
    clearm = lake_initial_state(Clear, Martin)
    clears = lake_initial_state(Clear, Scheffer)
    @test length(clearm[1]) == 3
    @test length(clears[1]) == 2
    @test clears[2].K == 100.0
    @test_throws ErrorException clearm[2].K
    clears = lake_initial_state(Clear, Scheffer; K = 50.0)
    @test clears[2].K == 50.0
end


text:
################################################################
# PARAMETER LEARNING OF SPNs
################################################################

using StatsBase

"""
Learns the parameters of an SPN using hard EM.

## Arguments
* `spn::SumProductNetwork`
* `x::AbstractMatrix`

## Keyword Arguments
* `iterations`
* `batchsize`

"""
function parameterLearnHardEM!(spn::SumProductNetwork, x::AbstractMatrix; iterations=30, batchsize=size(x,1))
	n, d = size(x)

	# normalize all sum nodes:
	normalize!(spn)

	llhvals = Vector{Float64}(iterations)

	for t in 1:iterations
		# set counts of all sum nodes to 0.0:
		resetCounts!(spn)
		# draw batchsize datapoints at random:
		indices = sample(1:n,batchsize,replace=false)
		indices = 1:n  # TODO: remove
		for i in indices
			xi = vec(x[i,:])  # get datapoint
			setInput!(spn, xi)
			eval!(spn, max=true)

			for node in spn.order
				if isa(node, SumNode)
					#=
					iMax = -1
					rMax = -Inf
					for cidx in 1:length(node.children)
						r = exp(node.children[cidx].logval) * node.weights[cidx]
						if r > rMax
							rMax = r
							iMax = cidx
						end
					end

					if iMax == -1
						continue
					end
					node.counts[iMax] += 1.0
					=#
					node.counts[node.maxidx] += 1.0
				end
			end
		end

		# set weights according to counts:
		for node in spn.order
			if isa(node, SumNode)
				@assert sum(node.counts) == n
				println(node.counts)
				node.weights = node.counts
                normalize!(node)
			end
		end

		llhvals[t] = dataLikelihood!(spn, x)
		@printf "iteration %d:\t llh=%d\n" t llhvals[t]
	end

	return llhvals
end

"""
Learns the parameters of an SPN using EM.

## Arguments
* `spn::SumProductNetwork`
* `x::AbstractMatrix`

## Keyword Arguments
* `iterations`
* `batchsize`

"""
function parameterLearnEM!(spn::SumProductNetwork, x::AbstractMatrix; iterations=30)
	n, d = size(x)

	# normalize all sum nodes:
	normalize!(spn)

	llhvals = Vector{Float64}(iterations)

	for t in 1:iterations

		# set counts of all sum nodes to 0.0:
		resetCounts!(spn)

		indices = 1:n
		for i in indices
			xi = vec(x[i,:])  # get datapoint
			setInput!(spn, xi)
			initDerivatives!(spn)
			eval!(spn, max=true)
			computeDerivatives!(spn)

			for node in spn.order
				if typeof(node) == SumNode
					for cidx in 1:length(node.children)
						r = exp(node.children[cidx].logval) * node.weights[cidx]# / exp(node.logval) * exp(node.logdrv)
						node.counts[cidx] += r
					end
				end
			end
		end

		# set weights according to counts:
		for node in spn.order
			if typeof(node) == SumNode
				node.weights = node.counts
                normalize!(node)
			end
		end

		llhvals[t] = dataLikelihood!(spn, x)
		@printf "iteration %d:\t llh=%d\n" t llhvals[t]
	end

	return llhvals
end

function parameterLearnGD!(spn::SumProductNetwork, x::AbstractMatrix; iterations=30, learnrate=0.1)
	n,d = size(x)

	# normalize all sum nodes:
	normalize!(spn)

	llhvals = Vector{Float64}(iterations)

	for t in 1:iterations
		indices = 1:n
		for i in indices
			xi = vec(x[i,:])
			setInput!(spn, xi)
			initDerivatives!(spn)
			eval!(spn)
			computeDerivatives!(spn)

			for node in spn.order
				if isa(node, SumNode)
					for i in 1:length(node.weights)
						node.weights[i] += learnrate * node.logdrv * node.children[i].logval
					end
		            normalize!(node)
				end
			end

		end

		llhvals[t] = dataLikelihood!(spn, x)
		@printf "iteration %d:\t llh=%f\n" t llhvals[t]
	end
end


text:
function CircularFieldOfView(arg0::Vector3D, arg1::jdouble, arg2::jdouble)
    return CircularFieldOfView((Vector3D, jdouble, jdouble), arg0, arg1, arg2)
end

function get_center(obj::SmoothFieldOfView)
    return jcall(obj, "getCenter", Vector3D, ())
end

function get_footprint(obj::SmoothFieldOfView, arg0::Transform, arg1::OneAxisEllipsoid, arg2::jdouble)
    return jcall(obj, "getFootprint", List, (Transform, OneAxisEllipsoid, jdouble), arg0, arg1, arg2)
end

function get_half_aperture(obj::CircularFieldOfView)
    return jcall(obj, "getHalfAperture", jdouble, ())
end

function get_x(obj::SmoothFieldOfView)
    return jcall(obj, "getX", Vector3D, ())
end

function get_y(obj::SmoothFieldOfView)
    return jcall(obj, "getY", Vector3D, ())
end

function get_z(obj::SmoothFieldOfView)
    return jcall(obj, "getZ", Vector3D, ())
end

function offset_from_boundary(obj::CircularFieldOfView, arg0::Vector3D, arg1::jdouble, arg2::VisibilityTrigger)
    return jcall(obj, "offsetFromBoundary", jdouble, (Vector3D, jdouble, VisibilityTrigger), arg0, arg1, arg2)
end

function project_to_boundary(obj::CircularFieldOfView, arg0::Vector3D)
    return jcall(obj, "projectToBoundary", Vector3D, (Vector3D,), arg0)
end


text:
using Kinetic, Plots, Flux
using KitBase.JLD2
using KitBase.ProgressMeter: @showprogress
using Base.Threads: @threads
using Flux: @epochs
cd(@__DIR__)

X = Float32.([[1e-4, 0.0, 1e-4]; zeros(3); 1.0])
Y = Float32.(0.0)

###
# Kn = 1e-4
###

begin
    set = Setup(case = "sod", space = "1d1f3v", collision = "bgk", maxTime = 0.15, boundary = ["fix", "fix"], cfl = 0.5)
    ps = PSpace1D(0, 1, 100, 1)
    vs = VSpace3D(-6.0, 6.0, 64, -6.0, 6.0, 28, -6.0, 6.0, 28)
    gas = Gas(Kn = 1e-4, K = 0.0)
    ib = IB1F(ib_sod(set, ps, vs, gas)...)
    ks = SolverSet(set, ps, vs, gas, ib)
    ctr, face = init_fvm(ks)
end

t = 0.0
dt = timestep(ks, ctr, t)
nt = Int(ks.set.maxTime ÷ dt)
res = zero(ctr[1].w)

@showprogress for iter = 1:nt
    evolve!(ks, ctr, face, dt)
    update!(ks, ctr, face, dt, res)

    if iter % 3 == 0
        for i = 1:ks.ps.nx
            sw = (ctr[i+1].w .- ctr[i-1].w) / ks.ps.dx[i] / 2.0
            x, y = regime_data(ks, ctr[i].w, sw, zero(sw), zero(sw), ctr[i].f)
            global X = hcat(X, [x[1:2]; x[5:7]; x[10:11]])
            global Y = hcat(Y, y)
        end
    end
end

###
# Kn = 1e-3
###

begin
    gas = Gas(Kn = 1e-3, K = 0.0)
    ib = IB1F(ib_sod(set, ps, vs, gas)...)
    ks = SolverSet(set, ps, vs, gas, ib)
    ctr, face = init_fvm(ks)
end

@showprogress for iter = 1:nt
    evolve!(ks, ctr, face, dt)
    update!(ks, ctr, face, dt, res)

    if iter % 3 == 0
        for i = 1:ks.ps.nx
            sw = (ctr[i+1].w .- ctr[i-1].w) / ks.ps.dx[i] / 2.0
            x, y = regime_data(ks, ctr[i].w, sw, zero(sw), zero(sw), ctr[i].f)
            global X = hcat(X, [x[1:2]; x[5:7]; x[10:11]])
            global Y = hcat(Y, y)
        end
    end
end

###
# Kn = 1e-2
###

begin
    gas = Gas(Kn = 1e-2, K = 0.0)
    ib = IB1F(ib_sod(set, ps, vs, gas)...)
    ks = SolverSet(set, ps, vs, gas, ib)
    ctr, face = init_fvm(ks)
end

@showprogress for iter = 1:nt
    evolve!(ks, ctr, face, dt)
    update!(ks, ctr, face, dt, res)

    if iter % 3 == 0
        for i = 1:ks.ps.nx
            sw = (ctr[i+1].w .- ctr[i-1].w) / ks.ps.dx[i] / 2.0
            x, y = regime_data(ks, ctr[i].w, sw, zero(sw), zero(sw), ctr[i].f)
            global X = hcat(X, [x[1:2]; x[5:7]; x[10:11]])
            global Y = hcat(Y, y)
        end
    end
end

@save "data_sod.jld2" X Y

###
# model
###

#@load "../../nn_scalar.jld2" nn
#@load "nn_sod.jld2" nn
@load "data_sod.jld2" X Y

nn = Chain(
    Dense(7, 28, sigmoid),
    Dense(28, 56, sigmoid),
    Dense(56, 28, sigmoid),
    Dense(28, 1, sigmoid),
)

data = Flux.Data.DataLoader((X, Y), shuffle = true)
ps = params(nn)
loss(x, y) = Flux.binarycrossentropy(nn(x), y)
cb = () -> println("loss: $(loss(X, Y))")
opt = ADAM()

@epochs 5 Flux.train!(loss, ps, data, opt, cb = Flux.throttle(cb, 1))

#--- test ---#

function accuracy(nn, X, Z)
    Z1 = nn(X)

    ZA1 = [round(Z1[1, i]) for i in axes(Z1, 2)]
    ZA = [round(Z[1, i]) for i in axes(Z, 2)]

    accuracy = 0.0
    for i in eachindex(ZA)
        if ZA[i] == ZA1[i]
            accuracy += 1.0
        end
    end
    accuracy /= length(ZA)

    return accuracy
end

accuracy(nn, X, Y)

function split_regime!(regime, ks, ctr, nn)
    regime[0] = 0
    regime[end] = 0

    @inbounds @threads for i = 1:ks.ps.nx
        wR = [ctr[i+1].w[1:2]; ctr[i+1].w[end]]
        wL = [ctr[i-1].w[1:2]; ctr[i-1].w[end]]
        w = [ctr[i].w[1:2]; ctr[i].w[end]]
        sw = (wR .- wL) ./ ks.ps.dx[i] ./ 2
        τ = vhs_collision_time(ctr[i].prim, ks.gas.μᵣ, ks.gas.ω)
        regime[i] = Int(round(nn([w; abs.(sw); τ])[1]))
    end

    return nothing
end

regime = ones(Int, axes(ks.ps.x))
split_regime!(regime, ks, ctr, nn)

plot(ks, ctr)
plot!(ks.ps.x[1:ks.ps.nx], regime[1:ks.ps.nx])

@save "nn_sod.jld2" nn

max_stars_repo_name: CSMMLab/Flowmachine

max_issues_repo_name: CSMMLab/Flowmachine

max_forks_repo_name: CSMMLab/Flowmachine


text:
using UnPack

"""
This struct configures port Hamiltonian mass-spring-damper systems described in
S. Gugercin et al.:
      Structure-preserving tangential interpolation for model reduction of
      port-Hamiltonian systems
# Arguments
- `n_cells`: The number of masses. The system dimension is `2n_cells`
- `c_i`: The amount of damping
- `m_i`: The weight of the masses
- `k_i`: The stiffness of the springs
# Outputs
Matrices: ``J, R, Q, B``. The resulting transfer function is ``H(s) = B^\\mathsf{T} Q  (sI-(J-R)Q)^{-1}B``.
"""
struct SingleMSDConfig{TC, TM, TK} <: BenchmarkConfig
  n_cells::Int
  io_dim::Int
  c::TC
  m::TM
  k::TK
  function SingleMSDConfig(n_cells::Int, io_dim::Int, c::TC, m::TM, k::TK) where {TC, TM, TK}
    @assert n_cells > 0 "number of cells must be positive"
    @assert io_dim > 0 "number of inputs and outputs must be positive"
    @assert c >= 0 "damping cannot be negative"
    @assert m >= 0 "masses cannot be negative"
    @assert k >= 0 "stiffnesses cannot be negative"
    return new{TC, TM, TK}(n_cells, io_dim, c, m, k)
  end
end

function SingleMSDConfig()
  return SingleMSDConfig{Float64, Float64, Float64}(100, 2, 1.0, 2.0, 3.0)
end

function construct_system(config::SingleMSDConfig{TC, TM, TK}) where {TC <: Number, TM <: Number, TK <: Number}
  @unpack n_cells, io_dim, c, m, k = config
  n=2*n_cells;
  # B is initialized as dense matrix. Since all results of transfer function
  # computations will lead to dense results.
  B=zeros(n, io_dim);
  [B[2*i,i]=1.0 for i in 1:io_dim]
  J=spzeros(n,n);
  [J[i,i+1]=1.0 for i in 1:2:(n-1)];
  J=J-J'
  # Set constants.
  R=spzeros(n,n);
  [R[i,i]=c for i in 2:2:n]
  Q=spzeros(n,n);
  Q[1,1]=k
  [Q[i,i]=2*k for i in 3:2:(n-1)]
  [Q[i,i]=1/m for i in 2:2:n]
  [Q[i,i+2]=-k for i in 1:2:(n-2)]
  [Q[i+2,i]=-k for i in 1:2:(n-2)]
  return (J=J, R=R, Q=Q, B=B)
end

function PHSystem(config::SingleMSDConfig)
  J, R, Q, G = construct_system(config)
  n, m = size(G)
  E = I(n)
  P = spzeros(n, m)
  S = spzeros(m, m)
  N = spzeros(m, m)
  return PHSystem(E, J, R, Q, G, P, S, N)
end

"""
    gugercin_pH_msd_chain(; n_cells=50, m=2, c_i=1.0, m_i=4.0, k_i=4.0)

This function returns the port Hamiltonian mass-spring-damper system described in
S. Gugercin et al.:
      Structure-preserving tangential interpolation for model reduction of
      port-Hamiltonian systems
# Arguments
- `n_cells`: The number of masses. The system dimension is `2n_cells`
- `c_i`: The amount of damping
- `m_i`: The weight of the masses
- `k_i`: The stiffness of the springs
# Outputs
Matrices: ``J, R, Q, B``. The resulting transfer function is ``H(s) = B^\\mathsf{T} Q  (sI-(J-R)Q)^{-1}B``.
"""
function gugercin_pH_msd_chain(;
    n_cells=50,
    m=2,
    c_i=1.0,
    m_i=4.0,
    k_i = 4.0
  )
  config = SingleMSDConfig(n_cells, m, c_i, m_i, k_i)
  return construct_system(config)
end

export SingleMSDConfig, gugercin_pH_msd_chain


text:
module CommunalHelperCrystalHeart

using ..Ahorn, Maple

@mapdef Entity "CommunalHelper/CrystalHeart" CrystalHeart(
    x::Integer,
    y::Integer,
    removeCameraTriggers::Bool=false,
)

const placements = Ahorn.PlacementDict(
    "Crystal Heart (Shards) (Communal Helper)" => Ahorn.EntityPlacement(
        CrystalHeart,
        "point",
        Dict{String,Any}(),
        function (entity)
            entity.data["nodes"] = [
                (Int(entity.data["x"]) - 20, Int(entity.data["y"]) - 20),
                (Int(entity.data["x"]), Int(entity.data["y"]) - 20),
                (Int(entity.data["x"]) + 20, Int(entity.data["y"]) - 20),
            ]
        end,
    ),
)

Ahorn.nodeLimits(entity::CrystalHeart) = 1, -1

const sprite = "collectables/heartGem/ghost00"

const shardSprites = Tuple{String,String}[(
        "collectables/CommunalHelper/heartGemShard/shard_outline0$i",
        "collectables/CommunalHelper/heartGemShard/shard0$i",
    ) for i in 0:2
]

function Ahorn.selection(entity::CrystalHeart)
    x, y = Ahorn.position(entity)

    nodes = get(entity.data, "nodes", ())

    res = Ahorn.Rectangle[Ahorn.getSpriteRectangle(sprite, x, y)]

    for i in 1:length(nodes)
        nx, ny = nodes[i]
        push!(res, Ahorn.getSpriteRectangle(shardSprites[mod1(i, 3)][1], nx, ny))
    end

    return res
end

function Ahorn.renderSelectedAbs(ctx::Ahorn.Cairo.CairoContext, entity::CrystalHeart)
    x, y = Ahorn.position(entity)

    nodes = get(entity.data, "nodes", ())

    for i in 1:length(nodes)
        nx, ny = nodes[i]

        Ahorn.drawLines(ctx, Tuple{Number, Number}[(x, y), (nx, ny)], Ahorn.colors.selection_selected_fc)
    end
end

function Ahorn.renderAbs(ctx::Ahorn.Cairo.CairoContext, entity::CrystalHeart)
    x, y = Ahorn.position(entity)

    nodes = get(entity.data, "nodes", ())

    for i in 1:length(nodes)
        nx, ny = nodes[i]
        sprIdx = mod1(i, 3)
        Ahorn.drawSprite(ctx, shardSprites[sprIdx][1], nx, ny)
        Ahorn.drawSprite(ctx, shardSprites[sprIdx][2], nx, ny)
    end

    Ahorn.drawSprite(ctx, sprite, x, y)
end

end


text:
d = 3    # number of dimensions
K = 50   # number of points along each dimension
N = 10^6  # number of points at which to interpolate
vecsize = 10

orders = Int64[K for i=1:d]
A = rand([K for i = 1:d]...)    # filtered coefficients
B = rand(N,d)                    # points at which to evaluate the splines

println("Comparison (d=",d,", K=", K, ", N=", N,")")

# interpolations.jl
using Interpolations
itp = interpolate(A, BSpline(Quadratic(Reflect())), OnGrid())

# what is the fastest way to operate on a list of points ?
LB = Vector{Float64}[copy(slice(B,i,:)) for i=1:size(B,1)]

function evaluate(itp, LB)
    s = 0.0
    for i=1:size(LB,1)
        I = LB[i]
        s += itp[I[1],I[2],I[3]]
    end
    return s
end

total_2 = evaluate(itp, LB)

println("interpolations.jl (cubic)")
@time total_2 = evaluate(itp, LB)
# exit()

using FixedSizeArrays

AA = rand(vecsize,orders...)
A0 = reinterpret(Vec{vecsize,Float64}, AA, (K,K,K))

bitp = interpolate(A0, BSpline(Cubic(Flat())), OnGrid())
function foo(itp, X)
    s = zero(eltype(itp))
    for x in X
        # s += itp[x[1]]
        s += itp[x[1],x[2],x[3]]
    end
    s
end

foo(bitp, LB)
println("interpolations.jl: (vector x",vecsize,")")

@time foo(bitp, LB)
# exit(0)
#
# orders = Int64[K for i in 1:d]
# a = rand(vecsize,orders...)
# b = reinterpret(Vec{vecsize,Float64}, a, (K,K,K))
# bitp = interpolate(b, BSpline(Cubic(Flat())), OnGrid())
# function foo(itp, X)
#     s = zero(eltype(itp))
#     for x in X
#         # s += itp[x[1]]
#         s += itp[x[1],x[2],x[3]]
#     end
#     s
# end
#
# # X = 2+150*rand(N)
# foo(bitp, XX) # warmup
# println("interpolations.jl (vector x",vecsize,")")
# @time foo(bitp, XX)

##################skyp
# with splines.jl #
###################

# splines.jl
using splines

# dummy boundaries
a = [0.0 for i=1:d]
b = [1.0 for i=1:d]

vals = rand(orders...)
coeffs = filter_coeffs(a,b,orders,vals)

# mcoeffs represent vecsize identical splines
mcoeffs = zeros(vecsize, size(coeffs)...)
for s in 1:vecsize
    mcoeffs[s,:] =  coeffs
end
# jit
# X = 150*rand(N,d)

println("splines.jl: (scalar)")
values_1 = eval_UC_spline(a,b,orders,coeffs,B);
tot = sum(values_1)
@time  values_1 = eval_UC_spline(a,b,orders,coeffs,B); tot = sum(values_1)

println("splines.jl: (vector x",vecsize,")")
values_1 = eval_UC_multi_spline(a,b,orders,mcoeffs,B);
tot = sum(values_1)
@time  values_1 = eval_UC_multi_spline(a,b,orders,mcoeffs,B); tot = sum(values_1)
@time  eval_UC_multi_spline!(a,b,orders,mcoeffs,B, values_1);


text:
"""
    Layer
A structure to store a `LittleDict` of operations that can be selected during the learning phase of an ICN. If the layer is exclusive, only one operation can be selected at a time.
"""
struct Layer
    functions::LittleDict{Symbol, Function}
    exclusive::Bool
end

"""
    functions(layer)
Access the operations of a layer. The container is ordered.
"""
functions(layer) = layer.functions

"""
    length(layer)
Return the number of operations in a layer.
"""
Base.length(layer::Layer) = length(functions(layer))

"""
    exclu(layer)
Return `true` if the layer has mutually exclusive operations.
"""
exclu(layer) = layer.exclusive

"""
    symbol(layer, i)
Return the i-th symbols of the operations in a given layer.
"""
symbol(layer, i) = collect(keys(functions(layer)))[i]

"""
    nbits_exclu(layer)
Convert the length of an exclusive layer into a number of bits.
"""
nbits_exclu(layer) = ceil(Int, log2(length(layer)))

"""
    show_layer(layer)
Return a string that contains the elements in a layer.
"""
show_layer(layer) = layer |> functions |> keys |> string

"""
    selected_size(layer, layer_weights)
Return the number of operations selected by `layer_weights` in `layer`.
"""
selected_size(layer, layer_weights) = exclu(layer) ? 1 : sum(layer_weights)

"""
    is_viable(layer, w)
    is_viable(icn)
    is_viable(icn, w)
Assert if a pair of layer/icn and weigths compose a viable pattern. If no weigths are given with an icn, it will check the current internal value.
"""
is_viable(layer::Layer, w) = exclu(layer) ? as_int(w) < length(layer) : any(w)

"""
    generate_inclusive_operations(predicate, bits)
    generate_exclusive_operation(max_op_number)
Generates the operations (weigths) of a layer with inclusive/exclusive operations.
"""
function generate_inclusive_operations(predicate, bits)
    ind = falses(bits)
    while true
        ind = bitrand(bits)
        predicate(ind) && break
    end
    return ind
end

function generate_exclusive_operation(max_op_number)
    op = rand(1:max_op_number)
    return as_bitvector(op, max_op_number)
end

"""
    generate_weights(layers)
    generate_weights(icn)
Generate the weigths of a collection of layers or of an ICN.
"""
function generate_weights(layers)
    bitvecs = map(l -> exclu(l) ?
            generate_exclusive_operation(length(l)) :
            generate_inclusive_operations(any, length(l)),
            layers
    )
    return vcat(bitvecs...)
end


text:
# ******************************************************************************************
# Notices:
#
# Copyright © 2022 United States Government as represented by the Administrator of the
# National Aeronautics and Space Administration.  All Rights Reserved.
#
# Disclaimers
#
# No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
# EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY
# THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY
# WARRANTY THAT THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION,
# IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER,
# CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS,
# RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS RESULTING FROM
# USE OF THE SUBJECT SOFTWARE.  FURTHER, GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND
# LIABILITIES REGARDING THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND
# DISTRIBUTES IT "AS IS."
#
# Waiver and Indemnity:  RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST THE UNITED
# STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY PRIOR RECIPIENT.
# IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN ANY LIABILITIES, DEMANDS, DAMAGES,
# EXPENSES OR LOSSES ARISING FROM SUCH USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON,
# OR RESULTING FROM, RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND
# HOLD HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL
# AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW.  RECIPIENT'S SOLE REMEDY FOR ANY
# SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS AGREEMENT.
# ******************************************************************************************

"""
Job description sent to worker processes. Stores new policy to be rolled out.
"""
struct Master2Worker
    ac::MLPActorCritic      # policy
    n_steps::Int            # number of steps
    random_policy::Bool     # whether to follow policy
end

"""
Result sent from worker processes to master process. Stores data from rollouts.
"""
struct Worker2Master
    id::Int                                     # worker ID
    transition_tuples::Vector{NamedTuple}       # data from rollouts
end

"""
Worker-side task. Runs in loop, receiving policies and sending observed data.
"""
function simulation_task(jobs::RemoteChannel, results::RemoteChannel, env_fn::Function, max_ep_len::Int)

    # Initialize environment and collection
	Random.seed!(myid())
    env = env_fn()
    transition_tuples = []

    # Loop until end of program
    while true
        # Receive job from master process and initialize RNG
        job = take!(jobs)
        copy!(job.ac.pi.rng, Random.default_rng())

        empty!(transition_tuples)
        ep_ret, ep_len = 0.0, 0
        reset!(env)
        o = observe(env)
        for _ in 1:job.n_steps
            # Choose action
        	a = job.random_policy ? rand(actions(env); flat=true) : job.ac(o)

            # Step environment
            d = terminated(env)
            r = act!(env, a)
            o2 = observe(env)
            ep_ret += r
            ep_len += 1

            # Ignore done signal if due to overtime
            d = (ep_len > max_ep_len) ? false : d

            push!(transition_tuples, (o=o, a=a, r=r, o2=o2, d=d))
            o = o2

            # End of trajectory handling
            if d || ep_len > max_ep_len
                d, ep_ret, ep_len = false, 0.0, 0
                reset!(env)
                o = observe(env)
            end
        end

        # Send results to master process
        result = Worker2Master(myid(), transition_tuples)
        put!(results, result)
    end
end

"""
Master-side code. Delegates work and performs updates.
"""
function distributed_solve(sac::SAC, env_fn::Function; channel_size::Int=32)
    # Create remote channels
    jobs = RemoteChannel(()->Channel{Master2Worker}(channel_size));
    results = RemoteChannel(()->Channel{Worker2Master}(channel_size));

    # Initialize AC agent and auxiliary data structures
    test_env = env_fn()
    replay_buffer = ReplayBuffer(sac.obs_dim, sac.act_dim, sac.max_buffer_size)
    ac = MLPActorCritic(sac.obs_dim, sac.act_dim, sac.act_mins, sac.act_maxs,
        sac.hidden_sizes, sac.num_q, sac.activation, sac.rng)
    ac_targ = deepcopy(ac)
    alpha = [1.0]
    total_steps = sac.steps_per_epoch * sac.epochs

    # Enforce even work delegation
    steps_per_worker = Int(sac.update_every // nworkers())
    @assert sac.steps_per_epoch % sac.update_every == 0

    # Set up remote task
    for p in workers()
        remote_do(simulation_task, p, jobs, results, env_fn, sac.max_ep_len)
    end

    # Initialize displayed information and progress meter
    @debug "Solve" total_steps
    disptups = [(:score, []), (:qdiff, []), ((sym, []) for (sym, _) in sac.displays)...]
    p = Progress(total_steps)

    for t in sac.update_every:sac.update_every:total_steps

        # Delegate work
        random_policy = t <= sac.start_steps
        ac_cpu = deepcopy(ac)
        to_cpu!(ac_cpu)
        for _ in 1:nworkers()
            job = Master2Worker(ac_cpu, steps_per_worker, random_policy)
            put!(jobs, job)
        end

        # Actor-critic update (concurrent with rollouts)
        if t >= sac.update_after
            @debug "Updating models" t
            for _ in 1:sac.num_batches
                batch = sample_batch(replay_buffer, sac.batch_size)
                update(ac, ac_targ, batch, sac.q_optimizer, sac.pi_optimizer, sac.polyak,
                    sac.gamma, sac.alpha_optimizer, alpha, sac.target_entropy)
            end
        end

        # End of epoch handling
        epoch = (t - 1) ÷ sac.steps_per_epoch + 1
        if t % sac.steps_per_epoch == 0
            # Update display values
            dispvals = test_agent(ac, test_env, sac.displays, sac.max_ep_len, sac.num_test_episodes)
            for ((_, hist), val) in zip(disptups, dispvals)
                push!(hist, val)
            end

            # Log info about epoch
            @debug("Evaluation",
            	  alpha[],
            	  mean(mean.(params([q.q for q in ac.qs]))),
            	  mean(mean.(Flux.params([ac.pi.net, ac.pi.mu_layer, ac.pi.log_std_layer])))
            )
        end

        # Collect and order results (will block here)
        results_acc = []
        for _ in 1:nworkers()
        	push!(results_acc, take!(results))
        end
        sort!(results_acc, by=r->r.id)

        # Store in replay buffer
        for result in results_acc
            for tup in result.transition_tuples
                store!(replay_buffer, tup...)
            end
        end

        # Checkpointing
        if sac.save && t > sac.update_after && t % sac.save_every == 0
            checkpoint(ac, sac.save_dir, sac.max_saved)
        end

        # Progress meter
        if t > sac.update_after
            ProgressMeter.next!(p; showvalues=gen_showvalues(epoch, disptups))
        end
    end

    # Save display values and replay buffer
    info = Dict{String,Any}()
    for (sym, hist) in disptups
        info[String(sym)] = hist
    end
    info["replay_buffer"] = replay_buffer

    return ac, info
end