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

"""
    associate_lenses(lens_aliases, workload_id)
    associate_lenses(lens_aliases, workload_id, params::Dict{String,<:Any})

Associate a lens to a workload.

# Arguments
- `lens_aliases`:
- `workload_id`:

"""
associate_lenses(LensAliases, WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("PATCH", "/workloads/$(WorkloadId)/associateLenses", Dict{String, Any}("LensAliases"=>LensAliases); aws_config=aws_config)
associate_lenses(LensAliases, WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("PATCH", "/workloads/$(WorkloadId)/associateLenses", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("LensAliases"=>LensAliases), params)); aws_config=aws_config)

"""
    create_milestone(client_request_token, milestone_name, workload_id)
    create_milestone(client_request_token, milestone_name, workload_id, params::Dict{String,<:Any})

Create a milestone for an existing workload.

# Arguments
- `client_request_token`:
- `milestone_name`:
- `workload_id`:

"""
create_milestone(ClientRequestToken, MilestoneName, WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("POST", "/workloads/$(WorkloadId)/milestones", Dict{String, Any}("ClientRequestToken"=>ClientRequestToken, "MilestoneName"=>MilestoneName); aws_config=aws_config)
create_milestone(ClientRequestToken, MilestoneName, WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("POST", "/workloads/$(WorkloadId)/milestones", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ClientRequestToken"=>ClientRequestToken, "MilestoneName"=>MilestoneName), params)); aws_config=aws_config)

"""
    create_workload(client_request_token, description, environment, lenses, review_owner, workload_name)
    create_workload(client_request_token, description, environment, lenses, review_owner, workload_name, params::Dict{String,<:Any})

Create a new workload. The owner of a workload can share the workload with other AWS
accounts and IAM users in the same AWS Region. Only the owner of a workload can delete it.
For more information, see Defining a Workload in the AWS Well-Architected Tool User Guide.

# Arguments
- `client_request_token`:
- `description`:
- `environment`:
- `lenses`:
- `review_owner`:
- `workload_name`:

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"AccountIds"`:
- `"ArchitecturalDesign"`:
- `"AwsRegions"`:
- `"Industry"`:
- `"IndustryType"`:
- `"NonAwsRegions"`:
- `"Notes"`:
- `"PillarPriorities"`:
- `"Tags"`: The tags to be associated with the workload.
"""
create_workload(ClientRequestToken, Description, Environment, Lenses, ReviewOwner, WorkloadName; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("POST", "/workloads", Dict{String, Any}("ClientRequestToken"=>ClientRequestToken, "Description"=>Description, "Environment"=>Environment, "Lenses"=>Lenses, "ReviewOwner"=>ReviewOwner, "WorkloadName"=>WorkloadName); aws_config=aws_config)
create_workload(ClientRequestToken, Description, Environment, Lenses, ReviewOwner, WorkloadName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("POST", "/workloads", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ClientRequestToken"=>ClientRequestToken, "Description"=>Description, "Environment"=>Environment, "Lenses"=>Lenses, "ReviewOwner"=>ReviewOwner, "WorkloadName"=>WorkloadName), params)); aws_config=aws_config)

"""
    create_workload_share(client_request_token, permission_type, shared_with, workload_id)
    create_workload_share(client_request_token, permission_type, shared_with, workload_id, params::Dict{String,<:Any})

Create a workload share. The owner of a workload can share it with other AWS accounts and
IAM users in the same AWS Region. Shared access to a workload is not removed until the
workload invitation is deleted. For more information, see Sharing a Workload in the AWS
Well-Architected Tool User Guide.

# Arguments
- `client_request_token`:
- `permission_type`:
- `shared_with`:
- `workload_id`:

"""
create_workload_share(ClientRequestToken, PermissionType, SharedWith, WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("POST", "/workloads/$(WorkloadId)/shares", Dict{String, Any}("ClientRequestToken"=>ClientRequestToken, "PermissionType"=>PermissionType, "SharedWith"=>SharedWith); aws_config=aws_config)
create_workload_share(ClientRequestToken, PermissionType, SharedWith, WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("POST", "/workloads/$(WorkloadId)/shares", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ClientRequestToken"=>ClientRequestToken, "PermissionType"=>PermissionType, "SharedWith"=>SharedWith), params)); aws_config=aws_config)

"""
    delete_workload(client_request_token, workload_id)
    delete_workload(client_request_token, workload_id, params::Dict{String,<:Any})

Delete an existing workload.

# Arguments
- `client_request_token`:
- `workload_id`:

"""
delete_workload(ClientRequestToken, WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("DELETE", "/workloads/$(WorkloadId)", Dict{String, Any}("ClientRequestToken"=>ClientRequestToken); aws_config=aws_config)
delete_workload(ClientRequestToken, WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("DELETE", "/workloads/$(WorkloadId)", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ClientRequestToken"=>ClientRequestToken), params)); aws_config=aws_config)

"""
    delete_workload_share(client_request_token, share_id, workload_id)
    delete_workload_share(client_request_token, share_id, workload_id, params::Dict{String,<:Any})

Delete a workload share.

# Arguments
- `client_request_token`:
- `share_id`:
- `workload_id`:

"""
delete_workload_share(ClientRequestToken, ShareId, WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("DELETE", "/workloads/$(WorkloadId)/shares/$(ShareId)", Dict{String, Any}("ClientRequestToken"=>ClientRequestToken); aws_config=aws_config)
delete_workload_share(ClientRequestToken, ShareId, WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("DELETE", "/workloads/$(WorkloadId)/shares/$(ShareId)", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ClientRequestToken"=>ClientRequestToken), params)); aws_config=aws_config)

"""
    disassociate_lenses(lens_aliases, workload_id)
    disassociate_lenses(lens_aliases, workload_id, params::Dict{String,<:Any})

Disassociate a lens from a workload.  The AWS Well-Architected Framework lens
(wellarchitected) cannot be removed from a workload.

# Arguments
- `lens_aliases`:
- `workload_id`:

"""
disassociate_lenses(LensAliases, WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("PATCH", "/workloads/$(WorkloadId)/disassociateLenses", Dict{String, Any}("LensAliases"=>LensAliases); aws_config=aws_config)
disassociate_lenses(LensAliases, WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("PATCH", "/workloads/$(WorkloadId)/disassociateLenses", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("LensAliases"=>LensAliases), params)); aws_config=aws_config)

"""
    get_answer(lens_alias, question_id, workload_id)
    get_answer(lens_alias, question_id, workload_id, params::Dict{String,<:Any})

Get the answer to a specific question in a workload review.

# Arguments
- `lens_alias`:
- `question_id`:
- `workload_id`:

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MilestoneNumber"`:
"""
get_answer(LensAlias, QuestionId, WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/workloads/$(WorkloadId)/lensReviews/$(LensAlias)/answers/$(QuestionId)"; aws_config=aws_config)
get_answer(LensAlias, QuestionId, WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/workloads/$(WorkloadId)/lensReviews/$(LensAlias)/answers/$(QuestionId)", params; aws_config=aws_config)

"""
    get_lens_review(lens_alias, workload_id)
    get_lens_review(lens_alias, workload_id, params::Dict{String,<:Any})

Get lens review.

# Arguments
- `lens_alias`:
- `workload_id`:

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MilestoneNumber"`:
"""
get_lens_review(LensAlias, WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/workloads/$(WorkloadId)/lensReviews/$(LensAlias)"; aws_config=aws_config)
get_lens_review(LensAlias, WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/workloads/$(WorkloadId)/lensReviews/$(LensAlias)", params; aws_config=aws_config)

"""
    get_lens_review_report(lens_alias, workload_id)
    get_lens_review_report(lens_alias, workload_id, params::Dict{String,<:Any})

Get lens review report.

# Arguments
- `lens_alias`:
- `workload_id`:

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MilestoneNumber"`:
"""
get_lens_review_report(LensAlias, WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/workloads/$(WorkloadId)/lensReviews/$(LensAlias)/report"; aws_config=aws_config)
get_lens_review_report(LensAlias, WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/workloads/$(WorkloadId)/lensReviews/$(LensAlias)/report", params; aws_config=aws_config)

"""
    get_lens_version_difference(base_lens_version, lens_alias)
    get_lens_version_difference(base_lens_version, lens_alias, params::Dict{String,<:Any})

Get lens version differences.

# Arguments
- `base_lens_version`: The base version of the lens.
- `lens_alias`:

"""
get_lens_version_difference(BaseLensVersion, LensAlias; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/lenses/$(LensAlias)/versionDifference", Dict{String, Any}("BaseLensVersion"=>BaseLensVersion); aws_config=aws_config)
get_lens_version_difference(BaseLensVersion, LensAlias, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/lenses/$(LensAlias)/versionDifference", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("BaseLensVersion"=>BaseLensVersion), params)); aws_config=aws_config)

"""
    get_milestone(milestone_number, workload_id)
    get_milestone(milestone_number, workload_id, params::Dict{String,<:Any})

Get a milestone for an existing workload.

# Arguments
- `milestone_number`:
- `workload_id`:

"""
get_milestone(MilestoneNumber, WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/workloads/$(WorkloadId)/milestones/$(MilestoneNumber)"; aws_config=aws_config)
get_milestone(MilestoneNumber, WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/workloads/$(WorkloadId)/milestones/$(MilestoneNumber)", params; aws_config=aws_config)

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

Get an existing workload.

# Arguments
- `workload_id`:

"""
get_workload(WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/workloads/$(WorkloadId)"; aws_config=aws_config)
get_workload(WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/workloads/$(WorkloadId)", params; aws_config=aws_config)

"""
    list_answers(lens_alias, workload_id)
    list_answers(lens_alias, workload_id, params::Dict{String,<:Any})

List of answers.

# Arguments
- `lens_alias`:
- `workload_id`:

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of results to return for this request.
- `"MilestoneNumber"`:
- `"NextToken"`:
- `"PillarId"`:
"""
list_answers(LensAlias, WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/workloads/$(WorkloadId)/lensReviews/$(LensAlias)/answers"; aws_config=aws_config)
list_answers(LensAlias, WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/workloads/$(WorkloadId)/lensReviews/$(LensAlias)/answers", params; aws_config=aws_config)

"""
    list_lens_review_improvements(lens_alias, workload_id)
    list_lens_review_improvements(lens_alias, workload_id, params::Dict{String,<:Any})

List lens review improvements.

# Arguments
- `lens_alias`:
- `workload_id`:

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of results to return for this request.
- `"MilestoneNumber"`:
- `"NextToken"`:
- `"PillarId"`:
"""
list_lens_review_improvements(LensAlias, WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/workloads/$(WorkloadId)/lensReviews/$(LensAlias)/improvements"; aws_config=aws_config)
list_lens_review_improvements(LensAlias, WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/workloads/$(WorkloadId)/lensReviews/$(LensAlias)/improvements", params; aws_config=aws_config)

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

List lens reviews.

# Arguments
- `workload_id`:

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`:
- `"MilestoneNumber"`:
- `"NextToken"`:
"""
list_lens_reviews(WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/workloads/$(WorkloadId)/lensReviews"; aws_config=aws_config)
list_lens_reviews(WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/workloads/$(WorkloadId)/lensReviews", params; aws_config=aws_config)

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

List the available lenses.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`:
- `"NextToken"`:
"""
list_lenses(; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/lenses"; aws_config=aws_config)
list_lenses(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/lenses", params; aws_config=aws_config)

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

List all milestones for an existing workload.

# Arguments
- `workload_id`:

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`:
- `"NextToken"`:
"""
list_milestones(WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("POST", "/workloads/$(WorkloadId)/milestonesSummaries"; aws_config=aws_config)
list_milestones(WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("POST", "/workloads/$(WorkloadId)/milestonesSummaries", params; aws_config=aws_config)

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

List lens notifications.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of results to return for this request.
- `"NextToken"`:
- `"WorkloadId"`:
"""
list_notifications(; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("POST", "/notifications"; aws_config=aws_config)
list_notifications(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("POST", "/notifications", params; aws_config=aws_config)

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

List the workload invitations.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of results to return for this request.
- `"NextToken"`:
- `"WorkloadNamePrefix"`:
"""
list_share_invitations(; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/shareInvitations"; aws_config=aws_config)
list_share_invitations(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/shareInvitations", params; aws_config=aws_config)

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

List the tags for a resource.

# Arguments
- `workload_arn`:

"""
list_tags_for_resource(WorkloadArn; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/tags/$(WorkloadArn)"; aws_config=aws_config)
list_tags_for_resource(WorkloadArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/tags/$(WorkloadArn)", params; aws_config=aws_config)

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

List the workload shares associated with the workload.

# Arguments
- `workload_id`:

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of results to return for this request.
- `"NextToken"`:
- `"SharedWithPrefix"`: The AWS account ID or IAM role with which the workload is shared.
"""
list_workload_shares(WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/workloads/$(WorkloadId)/shares"; aws_config=aws_config)
list_workload_shares(WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("GET", "/workloads/$(WorkloadId)/shares", params; aws_config=aws_config)

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

List workloads. Paginated.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of results to return for this request.
- `"NextToken"`:
- `"WorkloadNamePrefix"`:
"""
list_workloads(; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("POST", "/workloadsSummaries"; aws_config=aws_config)
list_workloads(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("POST", "/workloadsSummaries", params; aws_config=aws_config)

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

Adds one or more tags to the specified resource.

# Arguments
- `tags`: The tags for the resource.
- `workload_arn`:

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

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

Deletes specified tags from a resource. To specify multiple tags, use separate tagKeys
parameters, for example:  DELETE /tags/WorkloadArn?tagKeys=key1&tagKeys=key2

# Arguments
- `workload_arn`:
- `tag_keys`: A list of tag keys. Existing tags of the resource whose keys are members of
  this list are removed from the resource.

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

"""
    update_answer(lens_alias, question_id, workload_id)
    update_answer(lens_alias, question_id, workload_id, params::Dict{String,<:Any})

Update the answer to a specific question in a workload review.

# Arguments
- `lens_alias`:
- `question_id`:
- `workload_id`:

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"ChoiceUpdates"`: A list of choices to update on a question in your workload. The String
  key corresponds to the choice ID to be updated.
- `"IsApplicable"`:
- `"Notes"`:
- `"Reason"`: The reason why a question is not applicable to your workload.
- `"SelectedChoices"`:
"""
update_answer(LensAlias, QuestionId, WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("PATCH", "/workloads/$(WorkloadId)/lensReviews/$(LensAlias)/answers/$(QuestionId)"; aws_config=aws_config)
update_answer(LensAlias, QuestionId, WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("PATCH", "/workloads/$(WorkloadId)/lensReviews/$(LensAlias)/answers/$(QuestionId)", params; aws_config=aws_config)

"""
    update_lens_review(lens_alias, workload_id)
    update_lens_review(lens_alias, workload_id, params::Dict{String,<:Any})

Update lens review.

# Arguments
- `lens_alias`:
- `workload_id`:

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"LensNotes"`:
- `"PillarNotes"`:
"""
update_lens_review(LensAlias, WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("PATCH", "/workloads/$(WorkloadId)/lensReviews/$(LensAlias)"; aws_config=aws_config)
update_lens_review(LensAlias, WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("PATCH", "/workloads/$(WorkloadId)/lensReviews/$(LensAlias)", params; aws_config=aws_config)

"""
    update_share_invitation(share_invitation_action, share_invitation_id)
    update_share_invitation(share_invitation_action, share_invitation_id, params::Dict{String,<:Any})

Update a workload invitation.

# Arguments
- `share_invitation_action`:
- `share_invitation_id`: The ID assigned to the share invitation.

"""
update_share_invitation(ShareInvitationAction, ShareInvitationId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("PATCH", "/shareInvitations/$(ShareInvitationId)", Dict{String, Any}("ShareInvitationAction"=>ShareInvitationAction); aws_config=aws_config)
update_share_invitation(ShareInvitationAction, ShareInvitationId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("PATCH", "/shareInvitations/$(ShareInvitationId)", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ShareInvitationAction"=>ShareInvitationAction), params)); aws_config=aws_config)

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

Update an existing workload.

# Arguments
- `workload_id`:

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"AccountIds"`:
- `"ArchitecturalDesign"`:
- `"AwsRegions"`:
- `"Description"`:
- `"Environment"`:
- `"ImprovementStatus"`:
- `"Industry"`:
- `"IndustryType"`:
- `"IsReviewOwnerUpdateAcknowledged"`: Flag indicating whether the workload owner has
  acknowledged that the Review owner field is required. If a Review owner is not added to the
  workload within 60 days of acknowledgement, access to the workload is restricted until an
  owner is added.
- `"NonAwsRegions"`:
- `"Notes"`:
- `"PillarPriorities"`:
- `"ReviewOwner"`:
- `"WorkloadName"`:
"""
update_workload(WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("PATCH", "/workloads/$(WorkloadId)"; aws_config=aws_config)
update_workload(WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("PATCH", "/workloads/$(WorkloadId)", params; aws_config=aws_config)

"""
    update_workload_share(permission_type, share_id, workload_id)
    update_workload_share(permission_type, share_id, workload_id, params::Dict{String,<:Any})

Update a workload share.

# Arguments
- `permission_type`:
- `share_id`:
- `workload_id`:

"""
update_workload_share(PermissionType, ShareId, WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("PATCH", "/workloads/$(WorkloadId)/shares/$(ShareId)", Dict{String, Any}("PermissionType"=>PermissionType); aws_config=aws_config)
update_workload_share(PermissionType, ShareId, WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("PATCH", "/workloads/$(WorkloadId)/shares/$(ShareId)", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("PermissionType"=>PermissionType), params)); aws_config=aws_config)

"""
    upgrade_lens_review(lens_alias, milestone_name, workload_id)
    upgrade_lens_review(lens_alias, milestone_name, workload_id, params::Dict{String,<:Any})

Upgrade lens review.

# Arguments
- `lens_alias`:
- `milestone_name`:
- `workload_id`:

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"ClientRequestToken"`:
"""
upgrade_lens_review(LensAlias, MilestoneName, WorkloadId; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("PUT", "/workloads/$(WorkloadId)/lensReviews/$(LensAlias)/upgrade", Dict{String, Any}("MilestoneName"=>MilestoneName); aws_config=aws_config)
upgrade_lens_review(LensAlias, MilestoneName, WorkloadId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = wellarchitected("PUT", "/workloads/$(WorkloadId)/lensReviews/$(LensAlias)/upgrade", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("MilestoneName"=>MilestoneName), params)); aws_config=aws_config)


text:
using BinaryRecordReader
using Test

BRR = BinaryRecordReader # A convinet shortcut
# First we declare some simple structures

@testset "Isbits reader" begin
    struct Boo
        x::Int64
        y::Float16
    end

    struct TinyStruct
        b::Int
    end

    struct MinorStruct
        a::Int
        c::TinyStruct
    end

    struct MajorStruct
        long::Float32
        lat::Float32
        speed::Int16
        COG::UInt16
        time::Int32
        more::MinorStruct
    end

    @test_logs (:warn, "Attempt to create a reader for plain data type Boo") BRR.construct_reader_exp(Boo, NamedTuple())
    @test_logs (:warn, "Attempt to create a reader for plain data type TinyStruct") BRR.construct_reader_exp(TinyStruct, NamedTuple())
    @test_logs (:warn, "Attempt to create a reader for plain data type MinorStruct") BRR.construct_reader_exp(MinorStruct, NamedTuple())
    @test_logs (:warn, "Attempt to create a reader for plain data type MajorStruct") BRR.construct_reader_exp(MajorStruct, NamedTuple())
    @test_logs (:warn, "Attempt to create a reader for plain data type Boo") construct_reader_deep(Boo, NamedTuple())
    @test_logs (:warn, "Attempt to create a reader for plain data type TinyStruct") construct_reader_deep(TinyStruct, NamedTuple())
    @test_logs (:warn, "Attempt to create a reader for plain data type MajorStruct") construct_reader_deep(MajorStruct, NamedTuple())
    @test_logs (:warn, "Attempt to create a reader for plain data type MinorStruct") construct_reader_deep(MinorStruct, NamedTuple())
end;

struct RecHeaderExtended
    long::Float32
    lat::Float32
    speed::Int16
    COG::UInt16
    time::Int32
    data::Matrix{Int32}
end

@testset "Single Level Reader " begin
    simple_file = tempname()
    n_rec = 1000
    open(simple_file, "w") do io
        for i = 1:n_rec
            if i == 500 # Special write
                write(io, Float32(5), Float32(6), Int16(7), UInt16(8), Int32(9), Int32(4) * ones(Int32, 6, 600))
            else
                write(io, rand(Float32), rand(Float32), rand(Int16), rand(UInt16), rand(Int32), rand(Int32, 6, 600))
            end
        end
    end

    @construct_reader RecHeaderExtended (data = (6, 600),)
    my_data = Vector{RecHeaderExtended}(undef, n_rec)
    read!(simple_file, my_data);
    @test my_data[500].long == 5
    @test my_data[500].lat == 6
    @test my_data[500].speed == 7
    @test my_data[500].COG == 8
    @test my_data[500].time == 9
    @test my_data[500].data == 4 * ones(Int32, 6, 600)
    @test_throws TypeError BRR.construct_reader_exp(RecHeaderExtended, (long = (6, 600),))
end;

struct SimpleRec
    lat::Float32
    time::Int32
end

struct CompoundRec
    long::Float32
    COG::UInt16
    data::Matrix{SimpleRec}
end

@testset "Nested Structure Reader " begin
    simple_file = tempname()
    n_rec = 1000
    open(simple_file, "w") do io
        for i = 1:n_rec
            if i == 500 # Special write
                write(io, Float32(5), UInt16(8), [SimpleRec(5, 5) for i = 1:6, y = 1:600])
            else
                write(io, rand(Float32), rand(UInt16), [SimpleRec(rand(Float32), rand(Int32)) for i = 1:6, y = 1:600])
            end
        end
    end

    @construct_reader CompoundRec (data = (6, 600),)
    my_data = Vector{CompoundRec}(undef, n_rec)
    read!(simple_file, my_data);
    @test my_data[500].long == 5
    @test my_data[500].COG == 8
    @test all([x == SimpleRec(5, 5) for x in my_data[500].data])
end;

struct SimpleRecMat
    lat::Float32
    time::Matrix{Int32}
end

struct AnotherSimpleRecMat
    fun::UInt8
    funMat::Matrix{UInt16}
end

struct CompoundRecComplex
    long::Float32
    COG::UInt16
    funky::AnotherSimpleRecMat
    data::Matrix{SimpleRecMat}
end

@testset "Nested Structure Reader with none isbits matrix" begin
    simple_file = tempname()
    n_rec = 1000
    open(simple_file, "w") do io
        for i = 1:n_rec
            if i == 500 # Special write
                write(io, Float32(5), UInt16(8))
                write(io, UInt8(19), UInt16(20) * ones(UInt16, 2, 2))
                for x in 1:6, y in 1:600
                    write(io, Float32(5))
                    write(io, Int32(5) * ones(Int32, 5, 5))
                end
            else
                write(io, rand(Float32), rand(UInt16))
                write(io, rand(UInt8), rand(UInt16, 2, 2))
                for x in 1:6, y in 1:600
                    write(io, rand(Float32))
                    write(io, rand(Int32, 5, 5))
                end
            end
        end
    end

    @test_throws ArgumentError BRR.construct_reader_exp(CompoundRecComplex, (data = (6, 600),))
    @test AnotherSimpleRecMat ∉ BRR.def_reads
    eval(:(@construct_reader AnotherSimpleRecMat (funMat = (2, 2),)))
    @test AnotherSimpleRecMat ∈ BRR.def_reads
    @test SimpleRecMat  ∉ BRR.def_reads
    @test_throws ArgumentError BRR.construct_reader_exp(CompoundRecComplex, (data = (6, 600),))
    eval(:(@construct_reader SimpleRecMat  (time = (5, 5),)))
    @test SimpleRecMat ∈ BRR.def_reads
    @test_nowarn BRR.construct_reader_exp(CompoundRecComplex, (data = (6, 600),))
    eval(:(@construct_reader CompoundRecComplex (data = (6, 600),)))
    my_data = Vector{CompoundRecComplex}(undef, n_rec)
    read!(simple_file, my_data);
    @test my_data[500].long == 5
    @test my_data[500].COG == 8
    @test my_data[500].funky.fun == 19
    @test all(my_data[500].funky.funMat .== 20)
    @test all([x.lat == 5 && all(x.time .== 5) for x in my_data[500].data])
end;

struct C
    lat::Float32
    time::Matrix{Int32}
end

struct B
    fun::UInt8
    funMat::Matrix{UInt16}
end

struct A
    long::Float32
    COG::UInt16
    funky::B
    data::Matrix{C}
end

@testset "Nested Structure Reader we internal methods" begin
    simple_file = tempname()
    n_rec = 1000
    open(simple_file, "w") do io
        for i = 1:n_rec
            if i == 500 # Special write
                write(io, Float32(5), UInt16(8))
                write(io, UInt8(19), UInt16(20) * ones(UInt16, 2, 2))
                for x in 1:6, y in 1:600
                    write(io, Float32(5))
                    write(io, Int32(5) * ones(Int32, 5, 5))
                end
            else
                write(io, rand(Float32), rand(UInt16))
                write(io, rand(UInt8), rand(UInt16, 2, 2))
                for x in 1:6, y in 1:600
                    write(io, rand(Float32))
                    write(io, rand(Int32, 5, 5))
                end
            end
        end
    end
    # strip array test
    @test BRR.strip_array_specs(A,(data=(5,5), B__funMat=(2,2), C__time =(3,3))) == (Dict(:data => (5,5)), [:B, :C])
    @test BRR.strip_array_specs(B,(data=(5,5), B__funMat=(2,2), C__time =(3,3))) == (Dict(:funMat => (2,2), :data => (5,5)), [:C])
    @test BRR.strip_array_specs(C,(data=(5,5), B__funMat=(2,2), C__time =(3,3))) == (Dict(:data => (5,5), :time=>(3,3)),  [:B])
    @test_throws ArgumentError construct_reader_shallow(A, (data = (6, 600),))
    @test B ∉ BRR.def_reads
    @test C ∉ BRR.def_reads
    @test_throws ArgumentError construct_reader_deep(A, (data = (6, 600),))
    @test_throws ArgumentError construct_reader_deep(A, (data = (6, 600),))
    @test_throws TypeError construct_reader_deep(A, (long = (6, 600),))
    @test_nowarn construct_reader_shallow(C,(time =(2,2),))
    @test_nowarn construct_reader_deep(A,(data=(6,600), B__funMat=(2,2), C__time =(5,5)))
    my_data = Vector{A}(undef, n_rec)
    read!(simple_file, my_data);
    @test my_data[500].long == 5
    @test my_data[500].COG == 8
    @test my_data[500].funky.fun == 19
    @test all(my_data[500].funky.funMat .== 20)
    @test all([x.lat == 5 && all(x.time .== 5) for x in my_data[500].data])
end;

ext: jl


text:
function foo1()
    foo2()
end

function foo2()
    foo3()
end

function foo3()
    throw(ErrorException("bad things happened"))
end

foo1()
#=
julia> foo1()
ERROR: bad things happened
Stacktrace:
 [1] foo3() at ./REPL[99]:2
 [2] foo2() at ./REPL[96]:2
 [3] foo1() at ./REPL[95]:2
 [4] top-level scope at none:0
=#

function pretty_print_stacktrace(trace)
    for (i,v) in enumerate(trace)
        println(i, " => ", v)
    end
end

# handling error
function foo1()
    try
        foo2()
    catch
        println("handling error gracefully")
        pretty_print_stacktrace(stacktrace())
    end
end

foo1()
#=
julia> foo1()
handling error gracefully
1 => foo1() at REPL[107]:6
2 => top-level scope at none:0
3 => eval(::Module, ::Any) at boot.jl:328
4 => eval_user_input(::Any, ::REPL.REPLBackend) at REPL.jl:85
5 => macro expansion at REPL.jl:117 [inlined]
6 => (::getfield(REPL, Symbol("##26#27")){REPL.REPLBackend})() at task.jl:259
=#

function foo1()
    try
        foo2()
    catch
        println("handling error gracefully")
        pretty_print_stacktrace(stacktrace(catch_backtrace()))
    end
end

foo1()
#=
julia> foo1()
handling error gracefully
1 => foo3() at REPL[106]:2
2 => foo2() at REPL[96]:2
3 => foo1() at REPL[109]:3
4 => top-level scope at none:0
5 => eval(::Module, ::Any) at boot.jl:328
6 => eval_user_input(::Any, ::REPL.REPLBackend) at REPL.jl:85
7 => macro expansion at REPL.jl:117 [inlined]
8 => (::getfield(REPL, Symbol("##26#27")){REPL.REPLBackend})() at task.jl:259
=#


text:
using TMMOptics

include("testSingleLayer.jl")


text:
@recipe function f(cm::ConeMantle; n_arc = 40, subn = 10, n_vert_lines = 2)
    seriestype --> :mesh3d
    @series begin
        label --> "Cone Mantle"
        if haskey(plotattributes, :seriestype) && plotattributes[:seriestype] == :mesh3d
            mesh(cm, n_arc)
        else
            mesh(cm, n_arc, n_vert_lines)
        end
    end
    if haskey(plotattributes, :show_normal) && plotattributes[:show_normal]
        @series begin
            label := nothing
            seriestype := :vector
            nφ = isnothing(cm.φ) ? 0 : cm.φ/2
            T = typeof(cm.hZ)
            npt_obj = CartesianPoint(CylindricalPoint{T}(radius_at_z(cm, zero(T)), nφ, zero(T)))
            npt = _transform_into_global_coordinate_system(npt_obj, cm)
            npt, normal(cm, npt)/3
        end
    end
end


text:
### SliceSampler holds the fields of the slice sampler

immutable SliceSampler <: MCSampler
  widths::Vector{Float64} # Step sizes for initially expanding the slice
  stepout::Bool # Protects against the case of passing in small widths

  function SliceSampler(widths::Vector{Float64}, stepout::Bool)
    for x = widths
    @assert x > 0 "Widths should be positive."
    end
    new(widths, stepout)
  end
end

SliceSampler(widths::Vector{Float64}) = SliceSampler(widths, true)
SliceSampler(stepout::Bool) = SliceSampler(Float64[], stepout)

SliceSampler(; widths::Vector{Float64}=Float64[], stepout::Bool=true) = SliceSampler(widths, stepout)

### SliceSamplerHeap type holds the internal state ("local variables") of the slice sampler

type SliceSamplerHeap <: MCHeap{MCBaseSample}
  state::MCState{MCBaseSample} # Monte Carlo state used internally by the sampler
  count::Int # Current number of iterations
  widths::Vector{Float64} # Step sizes for expanding the slice for the current Monte Carlo iteration
  xl::Vector{Float64}
  xr::Vector{Float64}
  xprime::Vector{Float64}
  loguprime::Float64
  runiform::Float64
end

SliceSamplerHeap() =
  SliceSamplerHeap(MCState(MCBaseSample(), MCBaseSample()), 0, Float64[], Float64[], Float64[], Float64[], NaN, NaN)

SliceSamplerHeap(l::Int) =
  SliceSamplerHeap(MCState(MCBaseSample(l), MCBaseSample(l)), 0, fill(NaN, l), fill(NaN, l), fill(NaN, l), fill(NaN, l), NaN, NaN)

### Initialize slice sampler

function initialize_heap(m::MCModel, s::SliceSampler, r::MCRunner, t::MCTuner)
  heap::SliceSamplerHeap = SliceSamplerHeap(m.size)

  heap.state.successive = MCBaseSample(copy(m.init))
  logtarget!(heap.state.successive, m.eval)
  @assert isfinite(heap.state.successive.logtarget) "Initial values out of model support."

  if length(s.widths) == 0
    heap.widths = ones(m.size)
  else
    @assert length(s.widths) == m.size "Length of step sizes in widths must be equal to model size."
    heap.widths = s.widths
  end

  heap.count = 1

  heap
end

function reset!(heap::SliceSamplerHeap, x::Vector{Float64}, m::MCModel)
  heap.state.successive = MCBaseSample(copy(x))
  logtarget!(heap.state.successive, m.eval)
end

function initialize_task!(heap::SliceSamplerHeap, m::MCModel, s::SliceSampler, r::MCRunner, t::MCTuner)
  # Hook inside Task to allow remote resetting
  task_local_storage(:reset, (x::Vector{Float64})->reset!(heap, x, m))

  while true
    iterate!(heap, m, s, r, t, produce)
  end
end

### Perform iteration for slice sampler

function iterate!(heap::SliceSamplerHeap, m::MCModel, s::SliceSampler, r::MCRunner, t::MCTuner, send::Function)
  for j = 1:m.size
    heap.loguprime = log(rand())+heap.state.successive.logtarget
    heap.xl = copy(heap.state.successive.sample)
    heap.xr = copy(heap.state.successive.sample)
    heap.xprime = copy(heap.state.successive.sample)

    # Create a horizontal interval (heap.xl, heap.xr) enclosing xx
    heap.runiform = rand()
    heap.xl[j] = heap.state.successive.sample[j]-heap.runiform*heap.widths[j]
    heap.xr[j] = heap.state.successive.sample[j]+(1-heap.runiform)*heap.widths[j]
    if s.stepout
      while m.eval(heap.xl) > heap.loguprime
        heap.xl[j] -= heap.widths[j]
      end
      while m.eval(heap.xr) > heap.loguprime
        heap.xr[j] += heap.widths[j]
      end
    end

    # Inner loop: propose xprimes and shrink interval until good one is found
    while true
      heap.xprime[j] = rand()*(heap.xr[j]-heap.xl[j])+heap.xl[j]
      heap.state.successive.logtarget = m.eval(heap.xprime)
      if heap.state.successive.logtarget > heap.loguprime
        break
      else
        if (heap.xprime[j] > heap.state.successive.sample[j])
          heap.xr[j] = heap.xprime[j]
        elseif (heap.xprime[j] < heap.state.successive.sample[j])
          heap.xl[j] = heap.xprime[j]
        else
          @assert false "Shrunk to current position and still not acceptable."
        end
      end
    end

    heap.state.successive.sample[j] = heap.xprime[j]
  end

  heap.count += 1

  send(MCState(heap.state.successive, MCBaseSample(), Dict()))
end


text:
@testset "Path Normalization" begin
    mixed_path = ".\\\\path///to\\a\\place/..\\///"
    norm_path = "path/to/a"
    @test Zarr.normalize_path(mixed_path) == norm_path
    @test Zarr.DirectoryStore(mixed_path).folder == norm_path
    @test Zarr.normalize_path("/") == "/"
    @test Zarr.normalize_path("/a/") == "/a"
    @test Zarr.normalize_path("/path/to/a") == "/path/to/a"
end

"""
Function to test the interface of AbstractStore. Every complete implementation should pass this test.
"""
function test_store_common(ds)
  @test !Zarr.is_zgroup(ds,"")
  ds[".zgroup"]=rand(UInt8,50)
  @test haskey(ds,".zgroup")

  @test Zarr.is_zgroup(ds,"")
  @test !Zarr.is_zarray(ds,"")

  @test isempty(Zarr.subdirs(ds,""))
  @test sort(collect(Zarr.subkeys(ds,"")))==[".zgroup"]

  #Create a subgroup
  @test !Zarr.is_zarray(ds,"bar")
  ds["bar/.zarray"] = rand(UInt8,50)

  @test Zarr.is_zarray(ds,"bar")
  @test Zarr.subdirs(ds,"") == ["bar"]
  @test Zarr.subdirs(ds,"bar") == String[]
  #Test getindex and setindex
  data = rand(UInt8,50)
  ds["bar/0.0.0"] = data
  @test ds["bar/0.0.0"]==data
  @test Zarr.storagesize(ds,"bar")==50
  @test Zarr.isinitialized(ds,"bar/0.0.0")
  @test !Zarr.isinitialized(ds,"bar/0.0.1")
  Zarr.writeattrs(ds,"bar",Dict("a"=>"b"))
  @test Zarr.getattrs(ds,"bar")==Dict("a"=>"b")
  delete!(ds,"bar/0.0.0")
  @test !Zarr.isinitialized(ds,"bar",CartesianIndex((0,0,0)))
  @test !Zarr.isinitialized(ds,"bar/0.0.0")
  ds["bar/0.0.0"] = data
end

@testset "DirectoryStore" begin
  A = fill(1.0, 30, 20)
  chunks = (5,10)
  metadata = Zarr.Metadata(A, chunks; fill_value=-1.5)
  p = tempname()
  mkpath(joinpath(p,"foo"))
  ds = Zarr.DirectoryStore(joinpath(p,"foo"))
  test_store_common(ds)
  @test isdir(joinpath(p,"foo"))
  @test isfile(joinpath(p,"foo",".zgroup"))
  @test isdir(joinpath(p,"foo","bar"))
  @test isfile(joinpath(p,"foo","bar","0.0.0"))
  @test isfile(joinpath(p,"foo","bar",".zarray"))
  #Test that error is thrown when path does not exist and no folder is created
  @test_throws ArgumentError zopen("thisfolderdoesnotexist")
  @test !isdir("thisfolderdoesnotexist")
end

@testset "DictStore" begin
  A = fill(1.0, 30, 20)
  chunks = (5,10)
  metadata = Zarr.Metadata(A, chunks; fill_value=-1.5)
  ds = Zarr.DictStore()
  test_store_common(ds)
  @test haskey(ds.a,".zgroup")
  @test ds.a["bar/.zattrs"]==UInt8[0x7b, 0x22, 0x61, 0x22, 0x3a, 0x22, 0x62, 0x22, 0x7d]
  @test sort(collect(keys(ds.a)))==[".zgroup","bar/.zarray", "bar/.zattrs", "bar/0.0.0"]
end

@testset "LRU" begin
  p = tempname()
  g = zgroup(p)
  a = zcreate(Float64,g,"foo",  1000,1000, chunks=(1000,10), fill_value=NaN)
  a[1:500000] = 1:500000
  g2 = zopen(p,"w",lru = 5)
  newstore = g2.storage
  @test newstore isa Zarr.LRUStore
  a2 = g2["foo"]
  @test isempty(keys(newstore.lru))
  #Read some data to fill cache
  @test a2[1:10,1] == 1:10
  @test haskey(newstore.lru,"foo/0.0")
  @test newstore.lru["foo/0.0"] == reshape(1:10000,1000,10)
  # Now we modify the lru store to test that data is actually read from there
  newstore.lru["foo/0.0"] .= 0
  @test all(iszero,a2[1:10,1])
  @test_throws ErrorException a2[1,1] = 5
  @test_throws ErrorException delete!(newstore,"foo/0.0")
  @test isequal(a2[1,1000], missing)
  @test storagesize(a2) == 83002
end

@testset "Minio S3 storage" begin
  A = fill(1.0, 30, 20)
  chunks = (5,10)
  metadata = Zarr.Metadata(A, chunks; fill_value=-1.5)
  using Minio
  s = Minio.Server(joinpath("./",tempname()), address="localhost:9001")
  run(s, wait=false)
  cfg = MinioConfig("http://localhost:9001")
  Zarr.AWS.global_aws_config(cfg)
  Zarr.S3.create_bucket("zarrdata")
  ds = S3Store("zarrdata")
  test_store_common(ds)
  @test sprint(show, ds) == "S3 Object Storage"
  kill(s)
end

@testset "AWS S3 Storage" begin
  Zarr.AWS.global_aws_config(Zarr.AWS.AWSConfig(creds=nothing, region="eu-west-2"))
  S3,p = Zarr.storefromstring("s3://zarr-demo/store/foo")
  @test storagesize(S3,p) == 0
  @test Zarr.is_zgroup(S3,p) == true
  S3group = zopen(S3,path=p)
  S3Array = S3group.groups["bar"].arrays["baz"]
  @test eltype(S3Array) == Zarr.ASCIIChar
  @test storagesize(S3Array) == 69
  @test String(S3Array[:]) == "Hello from the cloud!"
end

@testset "GCS S3 Storage" begin
  cmip6,p = Zarr.storefromstring("gs://cmip6/CMIP6/HighResMIP/CMCC/CMCC-CM2-HR4/highresSST-present/r1i1p1f1/6hrPlev/psl/gn/v20170706/")
  @test storagesize(cmip6,p) == 16098
  g = zopen(cmip6,path=p)
  arr = g["psl"]
  @test size(arr) == (288, 192, 97820)
  @test eltype(arr) == Union{Missing, Float32}
  lat = g["lat"]
  @test size(lat) == (192,)
  @test eltype(lat) == Union{Missing, Float64}
  @test lat[1:4] == [-90.0,-89.05759162303664,-88.1151832460733,-87.17277486910994]
end

@testset "HTTP Storage" begin
  s = Zarr.DictStore()
  g = zgroup(s, attrs = Dict("groupatt"=>5))
  a = zcreate(Int,g,"a1",10,20,chunks=(5,5),attrs=Dict("arratt"=>2.5))
  a .= reshape(1:200,10,20)
  using Zarr.HTTP, Sockets
  server = Sockets.listen(0)
  ip,port = getsockname(server)
  @async HTTP.serve(g,ip,port,server=server)
  g2 = zopen("http://$ip:$port")
  @test g2.attrs == Dict("groupatt"=>5)
  @test g2["a1"].attrs == Dict("arratt"=>2.5)
  @test g2["a1"][:,:] == reshape(1:200,10,20)
  close(server)
end


text:
# Step 3: OAuth callback.
function callback(r::HTTP.Request)
    state = getcookie(r, "state")
    (isempty(state) || state != getquery(r, "state")) && return html(400, "Invalid state")

    pkey = getquery(r, "provider")
    provider = get(PROVIDERS, pkey, nothing)
    provider === nothing && return html(400, "Invalid callback URL")

    query = Dict(
        :client_id => provider.client_id,
        :client_secret => provider.client_secret,
        :redirect_uri => callback_url(provider),
        :code => getquery(r, "code"),
        :grant_type => "authorization_code",
    )
    provider.include_state && (query[:state] = state)

    resp = HTTP.post(
        provider.token_url;
        headers=["Accept" => "application/json", "User-Agent" => "Registrator.jl"],
        query=query,
    )
    token = JSON.parse(String(resp.body))["access_token"]

    client = typeof(provider.client)(;
        url=GitForge.base_url(provider.client),
        token=provider.token_type(token),
        has_rate_limits=GitForge.has_rate_limits(provider.client, identity),
    )
    USERS[state] = User(@gf(get_user(client)), client)

    return HTTP.Response(308, ["Location" => ROUTES[:SELECT]])
end


text:
function integrator_problem(
    m::AbstractMetricParams{T},
    pos::StaticVector{S,T},
    vel::StaticVector{S,T},
    time_domain
) where {S,T}
    SecondOrderODEProblem{false}(vel, pos, time_domain, m) do v, u, p, λ
        SVector(geodesic_eq(p, u, v)...)
    end
end

function integrator_problem(
    m::AbstractMetricParams{T},
    pos::AbstractVector{T},
    vel::AbstractVector{T},
    time_domain
) where {T}
    SecondOrderODEProblem{true}(vel, pos, time_domain, m) do dv, v, u, p, λ
        dv .= geodesic_eq(p, u, v)
    end
end


text:
################################################################################
#
#  Base case for dot products
#
################################################################################

dot(x::fmpz, y::nf_elem) = x*y

dot(x::nf_elem, y::fmpz) = x*y

function dot(a::Array{nf_elem, 1}, b::Array{fmpz, 1})
  d = zero(parent(a[1]))
  t = zero(d)
  for i=1:length(a)
    mul!(t, a[i], b[i])
    add!(d, d, t)
  end
  return d
end

################################################################################
#
#  Copy
#
################################################################################

Base.copy(d::nf_elem) = deepcopy(d)

################################################################################
#
#  Is rational?
#
################################################################################

function israt(a::nf_elem)
  if degree(parent(a))==1
    return true
  end
  @assert degree(parent(a))>2 ## fails for 2 due to efficiency
  return a.elem_length<2
end

################################################################################
#
#  Random elements from arrays of nf_elem
#
################################################################################

doc"""
***
    rand(b::Array{nf_elem,1}, r::UnitRange)

A random linear combination of elements in `b` with coefficients in `r`.
"""
function rand(b::Array{nf_elem,1}, r::UnitRange)
  length(b) == 0 && error("Array must not be empty")
  s = zero(parent(b[1]))
  rand!(s, b, r)
  return s
end

doc"""
***
    rand(b::Array{nf_elem,1}, r::UnitRange, terms::Int) -> nf_elem

A random linear combination (with repetitions) of \code{terms} elements of `b`
with coefficients in `r`.
"""
function rand(b::Array{nf_elem,1}, r::UnitRange, terms::Int)
  length(b) == 0 && error("Array must not be empty")
  s = zero(parent(b[1]))
  rand!(s, b, r, terms)
  return s
end

function rand!(c::nf_elem, b::Array{nf_elem,1}, r::UnitRange, terms::Int)
  length(b) == 0 && error("Array must not be empty")
  (terms<=0 || terms > length(b)) && error("Number of terms should be at least 1 and cannot exceed the length of the array")

  t = zero(parent(b[1]))

  terms = min(terms, length(b))
  mul!(c, rand(b), rand(r))
  for i = 2:terms
    mul!(t, rand(b), rand(r))
    add!(c, t, c)
  end

  return c
end

function rand!(c::nf_elem, b::Array{nf_elem,1}, r::UnitRange)
  length(b) == 0 && error("Array must not be empty")

  mul!(c, b[1], rand(r))
  t = zero(b[1].parent)

  for i = 2:length(b)
    mul!(t, b[i], rand(r))
    add!(c, t, c)
  end

  return c
end

################################################################################
#
#  Basis matrix
#
################################################################################

function basis_mat(A::Array{T, 1}) where {T <: Union{nf_elem, NfAbsNSElem}}
  @assert length(A) > 0
  n = length(A)
  d = degree(parent(A[1]))

  if T === NfAbsNSElem
    MM = zero_matrix(FlintQQ, n, d)
    for i in 1:n
      elem_to_mat_row!(MM, i, A[i])
    end
    return FakeFmpqMat(MM)
  end

  M = zero_matrix(FlintZZ, n, d)

  deno = one(FlintZZ)
  dummy = one(FlintZZ)

  for i in 1:n
    deno = lcm(deno, denominator(A[i]))
  end

  for i in 1:n
    elem_to_mat_row!(M, i, dummy, A[i])
    temp_den = divexact(deno, dummy)
    for j in 1:d
      M[i, j] = mul!(M[i, j], M[i, j], temp_den)
    end
  end
  return FakeFmpqMat(M, deno)
end

################################################################################
#
#  Characteristic polynomial
#
################################################################################

doc"""
***
    charpoly(a::nf_elem) -> fmpq_poly

The characteristic polynomial of a.
"""
function charpoly(a::nf_elem, Qx::FmpqPolyRing = parent(parent(a).pol))
  f = charpoly(Qx, representation_matrix(a))
  return f
end

################################################################################
#
#  Minimal polynomial
#
################################################################################

doc"""
***
  minpoly(a::nf_elem) -> fmpq_poly

> The minimal polynomial of a.
"""
function minpoly(a::nf_elem, Qx::FmpqPolyRing = parent(parent(a).pol))
  f = minpoly(Qx, representation_matrix(a))
  return f
end

################################################################################
#
#  Powering with fmpz
#
################################################################################

function ^(x::nf_elem, y::fmpz)
  # TODO: try to coerce y to UInt
  if y < 0
    return inv(x)^(-y)
  elseif y == 0
    return parent(x)(1)
  elseif y == 1
    return deepcopy(x)
  elseif mod(y, 2) == 0
    z = x^(div(y, 2))
    return z*z
  elseif mod(y, 2) == 1
    return x^(y-1) * x
  end
end

################################################################################
#
#  Unsafe operations
#
################################################################################

function sub!(a::nf_elem, b::nf_elem, c::nf_elem)
   ccall((:nf_elem_sub, :libantic), Void,
         (Ref{nf_elem}, Ref{nf_elem}, Ref{nf_elem}, Ref{AnticNumberField}),
         a, b, c, a.parent)
end

function set_den!(a::nf_elem, d::fmpz)
  ccall((:nf_elem_set_den, :libflint), Void,
        (Ref{nf_elem}, Ref{fmpz}, Ref{AnticNumberField}),
        a, d, parent(a))
end

function divexact!(z::nf_elem, x::nf_elem, y::fmpz)
  ccall((:nf_elem_scalar_div_fmpz, :libantic), Void,
        (Ref{nf_elem}, Ref{nf_elem}, Ref{fmpz}, Ref{AnticNumberField}),
        z, x, y, parent(x))
  return z
end

function gen!(r::nf_elem)
   a = parent(r)
   ccall((:nf_elem_gen, :libantic), Void,
         (Ptr{nf_elem}, Ptr{AnticNumberField}), &r, &a)
   return r
end

function one!(r::nf_elem)
   a = parent(r)
   ccall((:nf_elem_one, :libantic), Void,
         (Ptr{nf_elem}, Ptr{AnticNumberField}), &r, &a)
   return r
end

function one(r::nf_elem)
   a = parent(r)
   return one(a)
end

function zero(r::nf_elem)
   return zero(parent(r))
end

################################################################################
#
#  Ad hoc operations
#
################################################################################

# TODO: Remove this once we use Nemo >0.8.6
*(a::nf_elem, b::Integer) = a * fmpz(b)

################################################################################
#
#  Norm div
#
################################################################################

doc"""
***
   norm_div(a::nf_elem, d::fmpz, nb::Int) -> fmpz

Computes divexact(norm(a), d) provided the result has at most `nb` bits.
Typically, $a$ is in some ideal and $d$ is the norm of the ideal.
"""
function norm_div(a::nf_elem, d::fmpz, nb::Int)
   z = fmpq()
   # TODO:
   #CF the resultant code has trouble with denominators,
   #   this "solves" the problem, but it should probably be
   #   adressed in c
   @assert nb > 0
   de = denominator(a)
   n = degree(parent(a))
   ccall((:nf_elem_norm_div, :libantic), Void,
         (Ref{fmpq}, Ref{nf_elem}, Ref{AnticNumberField}, Ref{fmpz}, UInt),
         z, (a*de), a.parent, (d*de^n), UInt(nb))
   return z
end

################################################################################
#
#  Numerator
#
################################################################################

function numerator(a::nf_elem)
   const _one = one(FlintZZ)
   z = deepcopy(a)
   ccall((:nf_elem_set_den, :libantic), Void,
         (Ref{nf_elem}, Ref{fmpz}, Ref{AnticNumberField}),
         z, _one, a.parent)
   return z
end

################################################################################
#
#  Chinese remaindering
#
################################################################################

function induce_crt(a::nf_elem, p::fmpz, b::nf_elem, q::fmpz, signed::Bool = false)
  c = parent(a)()
  pi = invmod(p, q)
  mul!(pi, pi, p)
  pq = p*q
  if signed
    pq2 = div(pq, 2)
  else
    pq2 = fmpz(0)
  end
  return induce_inner_crt(a, b, pi, pq, pq2), pq
end

function inner_crt(a::fmpz, b::fmpz, up::fmpz, pq::fmpz, pq2::fmpz = fmpz(0))
  #1 = gcd(p, q) = up + vq
  # then u = modinv(p, q)
  # vq = 1-up. i is up here
  #crt: x = a (p), x = b(q) => x = avq + bup = a(1-up) + bup
  #                              = (b-a)up + a
  if !iszero(pq2)
    r = mod(((b-a)*up + a), pq)
    if r > pq2
      return r-pq
    else
      return r
    end
  else
    return mod(((b-a)*up + a), pq)
  end
end

function induce_inner_crt(a::nf_elem, b::nf_elem, pi::fmpz, pq::fmpz, pq2::fmpz = fmpz(0))
  c = parent(a)()
  ca = fmpz()
  cb = fmpz()
  for i=0:degree(parent(a))-1
    Nemo.num_coeff!(ca, a, i)
    Nemo.num_coeff!(cb, b, i)
    Hecke._num_setcoeff!(c, i, inner_crt(ca, cb, pi, pq, pq2))
  end
  return c
end

################################################################################
#
#  Norm
#
################################################################################

doc"""
    norm(f::PolyElem{nf_elem}) -> fmpq_poly

The norm of $f$, that is, the product of all conjugates of $f$ taken
coefficientwise.
"""
function norm(f::PolyElem{nf_elem})
  Kx = parent(f)
  K = base_ring(f)
  if degree(f) > 10 # TODO: find a good cross-over
    P = polynomial_to_power_sums(f, degree(f)*degree(K))
    PQ = [trace(x) for x=P]
    return power_sums_to_polynomial(PQ)
  end

  Qy = parent(K.pol)
  y = gen(Qy)
  Qyx, x = PolynomialRing(Qy, "x", cached = false)

  Qx = PolynomialRing(FlintQQ, "x")[1]
  Qxy = PolynomialRing(Qx, "y", cached = false)[1]

  T = evaluate(K.pol, gen(Qxy))
  h = nf_poly_to_xy(f, gen(Qxy), gen(Qx))
  return resultant(T, h)
end

function norm(f::PolyElem{T}) where T <: NfRelElem
  Kx = parent(f)
  K = base_ring(f)

  P = polynomial_to_power_sums(f, degree(f)*degree(K))
  PQ = [trace(x) for x=P]
  return power_sums_to_polynomial(PQ)
end

################################################################################
#
#  Factorization
#
################################################################################

doc"""
  factor(f::fmpz_poly, K::NumberField) -> Fac{Generic.Poly{nf_elem}}
  factor(f::fmpq_poly, K::NumberField) -> Fac{Generic.Poly{nf_elem}}

> The factorisation of f over K (using Trager's method).
"""
function factor(f::fmpq_poly, K::AnticNumberField)
  Ky, y = PolynomialRing(K, cached = false)
  return factor(evaluate(f, y))
end

function factor(f::fmpz_poly, K::AnticNumberField)
  Ky, y = PolynomialRing(K, cached = false)
  Qz, z = PolynomialRing(FlintQQ)
  return factor(evaluate(Qz(f), y))
end

doc"""
  factor(f::PolyElem{nf_elem}) -> Fac{Generic.Poly{nf_elem}}

> The factorisation of f (using Trager's method).
"""
function factor(f::PolyElem{nf_elem})
  Kx = parent(f)
  K = base_ring(f)
  f == 0 && error("poly is zero")
  f_orig = deepcopy(f)
  @vprint :PolyFactor 1 "Factoring $f\n"
  @vtime :PolyFactor 2 g = gcd(f, derivative(f'))
  if degree(g) > 0
    f = div(f, g)
  end

  f = f*(1//lead(f))

  k = 0
  g = f
  N = 0

  while true
    @vtime :PolyFactor 2 N = norm(g)

    if !isconstant(N) && issquarefree(N)
      break
    end

    k = k + 1

    g = compose(f, gen(Kx) - k*gen(K))
  end

  @vtime :PolyFactor 2 fac = factor(N)

  res = Dict{PolyElem{nf_elem}, Int64}()

  for i in keys(fac.fac)
    t = zero(Kx)
    for j in 0:degree(i)
      t = t + K(coeff(i, j))*gen(Kx)^j
    end
    t = compose(t, gen(Kx) + k*gen(K))
    @vtime :PolyFactor 2 t = gcd(f, t)
    res[t] = 1
  end

  r = Fac{typeof(f)}()
  r.fac = res
  r.unit = Kx(1)

  if f != f_orig
    global p_start
    p = p_start
    @vtime :PolyFactor 2 while true
      p = next_prime(p)
      me = modular_init(K, p, max_split=1)
      fp = modular_proj(f, me)[1]
      if issquarefree(fp)
        fp = deepcopy(modular_proj(f_orig, me)[1])
        for k in keys(res)
          gp = modular_proj(k, me)[1]
          res[k] = valuation(fp, gp)
        end
        r.fac = res
        # adjust the unit of the factorization
        r.unit = one(Kx) * lead(f_orig)//prod((lead(p) for (p, e) in r))
        return r
      end
    end
  end
  r.unit = one(Kx)* lead(f_orig)//prod((lead(p) for (p, e) in r))
  return r
end

################################################################################
#
#  Roots
#
################################################################################

doc"""
***
    roots(f::fmpz_poly, K::AnticNumberField) -> Array{nf_elem, 1}
    roots(f::fmpq_poly, K::AnticNumberField) -> Array{nf_elem, 1}

> Computes all roots in $K$ of a polynomial $f$. It is assumed that $f$ is is non-zero,
> squarefree and monic.
"""
function roots(f::fmpz_poly, K::AnticNumberField, max_roots::Int = degree(f))
  Ky, y = PolynomialRing(K, cached = false)
  return roots(evaluate(f, y), max_roots)
end

function roots(f::fmpq_poly, K::AnticNumberField, max_roots::Int = degree(f))
  Ky, y = PolynomialRing(K, cached = false)
  return roots(evaluate(f, y), max_roots)
end

function elem_in_nf(a::nf_elem)
  Base.show_backtrace(STDOUT, Base.backtrace())
  return a
end

doc"""
***
    roots(f::Generic.Poly{nf_elem}) -> Array{nf_elem, 1}

> Computes all roots of a polynomial $f$. It is assumed that $f$ is is non-zero,
> squarefree and monic.
"""
function roots(f::Generic.Poly{nf_elem}, max_roots::Int = degree(f); do_lll::Bool = false, do_max_ord::Bool = true)
  @assert issquarefree(f)

  #TODO: implement for equation order....
  #TODO: use max_roots

  if degree(f) == 1
    return [-trailing_coefficient(f)//lead(f)]
  end

  get_d = x -> denominator(x)
  if do_max_ord
    O = maximal_order(base_ring(f))
    if do_lll
      O = lll(O)
    end
    get_d = x-> denominator(x, O)
  end

  d = degree(f)

  deno = get_d(coeff(f, d))
  for i in (d-1):-1:0
    ai = coeff(f, i)
    if !iszero(ai)
      deno = lcm(deno, get_d(ai))
    end
  end

  g = deno*f

  if do_max_ord
    Ox, x = PolynomialRing(O, "x", cached = false)
    goverO = Ox([ O(coeff(g, i)) for i in 0:d])
  else
    goverO = g
  end

  if !isone(lead(goverO))
    deg = degree(f)
    a = lead(goverO)
    b = one(O)
    for i in deg-1:-1:0
      setcoeff!(goverO, i, b*coeff(goverO, i))
      b = b*a
    end
    setcoeff!(goverO, deg, one(O))
    r = _roots_hensel(goverO, max_roots)
    return [ divexact(elem_in_nf(y), elem_in_nf(a)) for y in r ]
  end

  A = _roots_hensel(goverO, max_roots)

  return [ elem_in_nf(y) for y in A ]
end

################################################################################
#
#  Roots
#
################################################################################

doc"""
***
    ispower(a::nf_elem, n::Int) -> Bool, nf_elem

> Determines whether $a$ has an $n$-th root. If this is the case,
> the root is returned.
"""
function ispower(a::nf_elem, n::Int)
  #println("Compute $(n)th root of $a")

  @assert n>0
  if n==1
    return true, a
  end
  if iszero(a)
    return true, a
  end

  d = denominator(a)
  rt = _roots_hensel(a*d^n, n, 1)

  if length(rt)>0
    return true, rt[1]//d
  else
    return false, zero(a)
  end
end

doc"""
***
    root(a::nf_elem, n::Int) -> nf_elem

> Computes the $n$-th root of $a$. Throws an error if this is not possible.
"""
function root(a::nf_elem, n::Int)
  fl, rt = ispower(a, n)
  if fl
    return rt
  end

  error("$a has no $n-th root")
end

doc"""
    roots(a::nf_elem, n::Int) -> Array{nf_elem, 1}
> Compute all $n$-th roots of $a$, possibly none.
"""
function roots(a::nf_elem, n::Int)
  #println("Compute $(n)th root of $a")

  @assert n>0
  if n==1
    return [a]
  end
  if iszero(a)
    return [a]
  end

  d = denominator(a)
  rt = _roots_hensel(a*d^n, n)

  return [x//d for x = rt]
end

function root(a::NfOrdElem, n::Int)
  fl, rt = ispower(a.elem_in_nf, n)
  if fl
    O = parent(a)
    if denominator(a, O) == 1
      return O(rt)
    end
  end

  error("$a has no $n-th root")
end

################################################################################
#
#  Inversion via lifting
#
################################################################################

function inv_lift_recon(a::nf_elem)  # not competitive....reconstruction is too slow
  p = next_prime(2^60)
  K = parent(a)
  me = modular_init(K, p)
  ap = Hecke.modular_proj(a, me)
  bp = Hecke.modular_lift([inv(x) for x = ap], me)
  pp = fmpz(p)

  fl, b = Hecke.rational_reconstruction(bp, pp)
  t = K()
  while !fl
#    @assert mod_sym(a*bp - 1, pp) == 0
    mul!(pp, pp, pp)
    mul!(t, a, bp)
    rem!(bp, pp)
    sub!(t, 2, t)
    mul!(bp, bp, t)
    rem!(bp, pp)
#    @assert mod_sym(a*bp - 1, pp) == 0
    fl, b = rational_reconstruction(bp, pp)
    if fl
      if b*a == 1
        return b
      end
      fl = false
    end
  end
  return b
end

function inv_lift(a::nf_elem)  # better, but not enough
  p = next_prime(2^60)
  K = parent(a)
  me = modular_init(K, p)
  ap = modular_proj(a, me)
  bp = modular_lift([inv(x) for x = ap], me)
  pp = fmpz(p)
  fl, b = Hecke.rational_reconstruction(bp, pp)
  t = K()
  n = norm(a)
  while !fl
    Hecke.mul!(t, a, bp)
    Hecke.mul!(pp, pp, pp)
    rem!(t, pp)
    Hecke.sub!(t, 2, t)
    Hecke.mul!(bp, bp, t)
    rem!(t, pp)
    mul!(t, bp, n)
    mod_sym!(t, pp)
    if t*a == n
      return t//n
    end
  end
  return b
end

################################################################################
#
#  Modular reduction
#
################################################################################

import Hecke.mod_sym!, Hecke.rem!, Hecke.mod!, Hecke.mod, Hecke.rem

function mod_sym!(a::nf_elem, b::fmpz)
  mod_sym!(a, b, div(b, 2))
end

function mod_sym!(a::nf_elem, b::fmpz, b2::fmpz)
  Base.show_backtrace(STDOUT, Base.backtrace()[1:2])
  z = fmpz()
  for i=0:a.elem_length-1
    Nemo.num_coeff!(z, a, i)
    rem!(z, z, b)
    if z >= b2
      sub!(z, z, b)
    end
    _num_setcoeff!(a, i, z)
  end
end

function mod!(z::fmpz, x::fmpz, y::fmpz)
  ccall((:fmpz_mod, :libflint), Void, (Ptr{fmpz}, Ptr{fmpz}, Ptr{fmpz}), &z, &x, &y)
  return z
end

function mod!(a::nf_elem, b::fmpz)
  z = fmpz()
  d = degree(parent(a))
  if d == 1
    Nemo.num_coeff!(z, a, 0)
    mod!(z, z, b)
    _num_setcoeff!(a, 0, z)
  elseif d == 2
    Nemo.num_coeff!(z, a, 0)
    mod!(z, z, b)
    _num_setcoeff!(a, 0, z)
    Nemo.num_coeff!(z, a, 1)
    mod!(z, z, b)
    _num_setcoeff!(a, 1, z)
  else
    for i=0:a.elem_length-1
      Nemo.num_coeff!(z, a, i)
      mod!(z, z, b)
      _num_setcoeff!(a, i, z)
    end
  end
end

function mod(a::nf_elem, b::fmpz)
  c = deepcopy(a)
  mod!(c, b)
  return c
end

function rem!(a::nf_elem, b::fmpz)
  z = fmpz()
  for i=0:a.elem_length-1
    Nemo.num_coeff!(z, a, i)
    rem!(z, z, b)
    _num_setcoeff!(a, i, z)
  end
end

function rem(a::nf_elem, b::fmpz)
  c = deepcopy(a)
  rem!(c, b)
  return c
end

function mod_sym(a::nf_elem, b::fmpz)
  return mod_sym(a, b, div(b, 2))
end

function mod_sym(a::nf_elem, b::fmpz, b2::fmpz)
  c = deepcopy(a)
  mod_sym!(c, b, b2)
  return c
end

################################################################################
#
#  Conversion to nmod_poly and fmpz_mod_poly
#
################################################################################

function nf_elem_to_nmod_poly!(r::nmod_poly, a::nf_elem, useden::Bool = true)
  ccall((:nf_elem_get_nmod_poly_den, :libantic), Void,
        (Ref{nmod_poly}, Ref{nf_elem}, Ref{AnticNumberField}, Cint),
        r, a, a.parent, Cint(useden))
  return nothing
end

function (R::Nemo.NmodPolyRing)(a::nf_elem)
  r = R()
  nf_elem_to_nmod_poly!(r, a)
  return r
end

function nf_elem_to_fmpz_mod_poly(r::fmpz_mod_poly, a::nf_elem, useden::Bool = true)
  ccall((:nf_elem_get_fmpz_mod_poly_den, :libantic), Void,
        (Ref{nmod_poly}, Ref{nf_elem}, Ref{AnticNumberField}, Cint),
        r, a, a.parent, Cint(useden))
  return nothing
end

function (R::Nemo.FmpzModPolyRing)(a::nf_elem)
  r = R()
  nf_elem_to_fmpz_mod_poly!(r, a)
  return r
end

################################################################################
#
#  Alternative norm computation
#
################################################################################

#TODO: This seems to be abandoned

mutable struct NormCtx
  me::Array{modular_env, 1}
  nb::Int
  K::AnticNumberField
  ce::crt_env{fmpz}
  ln::Array{fmpz, 1}

  function NormCtx(K::AnticNumberField, nb::Int, deg_one::Bool = false)
    p = p_start
    me = Array{modular_env,1}()

    r = new()
    r.K = K
    r.nb = nb

    lp = fmpz[]

    while nb > 0
      local m
      while true
        p = next_prime(p)
        m = modular_init(K, p)
        if deg_one && length(m.rp) < degree(K)
          continue
        end
        break
      end
      push!(lp, fmpz(p))
      push!(me, m)
      nb = nb - nbits(p)
    end
    r.me = me
    r.ce = crt_env(lp)
    r.ln = Array{fmpz, 1}()
    for i = me
      push!(r.ln, fmpz(0))
    end
    return r
  end
end

function show(io::IO, a::NormCtx)
  println(io, "NormCtx for $(a.K) for $(a.nb) bits, using $(length(a.me)) primes")
end

function norm(a::nf_elem, N::NormCtx, div::fmpz = fmpz(1))
  ln = N.ln
  i = 1
  for m = N.me
    np = UInt(invmod(div, m.p))
    ap = modular_proj(a, m)
    for j=1:length(ap)
      # problem: norm costs memory (in fmpz formally, then new fq_nmod is created)
      np = mulmod(np, coeff(norm(ap[j]), 0), m.rp[1].mod_n, m.rp[1].mod_ninv)
    end
    N.ln[i] = np # problem: np is UInt, ln is not...
    i += 1
  end
  return crt_signed(N.ln, N.ce)
end


text:
using JuMP, EAGO

                     m = Model()

                     EAGO.register_eago_operators!(m)

                     @variable(m, -1 <= x[i=1:5] <= 1)

                     @variable(m, -9.734460520574642 <= q <= 2.116911729869532)

                     add_NL_constraint(m, :(1/(1 + exp(-(-0.8046949419530325 + -0.2278494590955038*1/(1 + exp(-(0.1770285029406451 + -0.5067338360802731*1/(1 + exp(-(-0.7998422425711689 + 0.5883237869246916*1/(1 + exp(-(-0.6653700708895021 + 0.6185402094345611*$(x[1]) + 0.05069108137655398*$(x[2]) + 0.9466113725109135*$(x[3]) + 0.06805104680691931*$(x[4]) + -0.30203159362192356*$(x[5])))) + 0.47235910506966317*1/(1 + exp(-(-0.04665405044600712 + -0.8840756438370558*$(x[1]) + -0.20571795637475754*$(x[2]) + 0.8733859112268667*$(x[3]) + -0.5065045210605232*$(x[4]) + -0.7647800565294718*$(x[5]))))))) + -0.09889031570146667*1/(1 + exp(-(-0.7622628423532047 + 0.6518912481623378*1/(1 + exp(-(-0.6653700708895021 + 0.6185402094345611*$(x[1]) + 0.05069108137655398*$(x[2]) + 0.9466113725109135*$(x[3]) + 0.06805104680691931*$(x[4]) + -0.30203159362192356*$(x[5])))) + 0.4006903724184485*1/(1 + exp(-(-0.04665405044600712 + -0.8840756438370558*$(x[1]) + -0.20571795637475754*$(x[2]) + 0.8733859112268667*$(x[3]) + -0.5065045210605232*$(x[4]) + -0.7647800565294718*$(x[5])))))))))) + -0.18111143847071443*1/(1 + exp(-(-0.12446319977672715 + 0.7018706953017659*1/(1 + exp(-(-0.7998422425711689 + 0.5883237869246916*1/(1 + exp(-(-0.6653700708895021 + 0.6185402094345611*$(x[1]) + 0.05069108137655398*$(x[2]) + 0.9466113725109135*$(x[3]) + 0.06805104680691931*$(x[4]) + -0.30203159362192356*$(x[5])))) + 0.47235910506966317*1/(1 + exp(-(-0.04665405044600712 + -0.8840756438370558*$(x[1]) + -0.20571795637475754*$(x[2]) + 0.8733859112268667*$(x[3]) + -0.5065045210605232*$(x[4]) + -0.7647800565294718*$(x[5]))))))) + 0.5275006439747312*1/(1 + exp(-(-0.7622628423532047 + 0.6518912481623378*1/(1 + exp(-(-0.6653700708895021 + 0.6185402094345611*$(x[1]) + 0.05069108137655398*$(x[2]) + 0.9466113725109135*$(x[3]) + 0.06805104680691931*$(x[4]) + -0.30203159362192356*$(x[5])))) + 0.4006903724184485*1/(1 + exp(-(-0.04665405044600712 + -0.8840756438370558*$(x[1]) + -0.20571795637475754*$(x[2]) + 0.8733859112268667*$(x[3]) + -0.5065045210605232*$(x[4]) + -0.7647800565294718*$(x[5]))))))))))))) + 1/(1 + exp(-(-0.4025778812055263 + 0.08853333939955377*1/(1 + exp(-(0.1770285029406451 + -0.5067338360802731*1/(1 + exp(-(-0.7998422425711689 + 0.5883237869246916*1/(1 + exp(-(-0.6653700708895021 + 0.6185402094345611*$(x[1]) + 0.05069108137655398*$(x[2]) + 0.9466113725109135*$(x[3]) + 0.06805104680691931*$(x[4]) + -0.30203159362192356*$(x[5])))) + 0.47235910506966317*1/(1 + exp(-(-0.04665405044600712 + -0.8840756438370558*$(x[1]) + -0.20571795637475754*$(x[2]) + 0.8733859112268667*$(x[3]) + -0.5065045210605232*$(x[4]) + -0.7647800565294718*$(x[5]))))))) + -0.09889031570146667*1/(1 + exp(-(-0.7622628423532047 + 0.6518912481623378*1/(1 + exp(-(-0.6653700708895021 + 0.6185402094345611*$(x[1]) + 0.05069108137655398*$(x[2]) + 0.9466113725109135*$(x[3]) + 0.06805104680691931*$(x[4]) + -0.30203159362192356*$(x[5])))) + 0.4006903724184485*1/(1 + exp(-(-0.04665405044600712 + -0.8840756438370558*$(x[1]) + -0.20571795637475754*$(x[2]) + 0.8733859112268667*$(x[3]) + -0.5065045210605232*$(x[4]) + -0.7647800565294718*$(x[5])))))))))) + -0.4269192713141794*1/(1 + exp(-(-0.12446319977672715 + 0.7018706953017659*1/(1 + exp(-(-0.7998422425711689 + 0.5883237869246916*1/(1 + exp(-(-0.6653700708895021 + 0.6185402094345611*$(x[1]) + 0.05069108137655398*$(x[2]) + 0.9466113725109135*$(x[3]) + 0.06805104680691931*$(x[4]) + -0.30203159362192356*$(x[5])))) + 0.47235910506966317*1/(1 + exp(-(-0.04665405044600712 + -0.8840756438370558*$(x[1]) + -0.20571795637475754*$(x[2]) + 0.8733859112268667*$(x[3]) + -0.5065045210605232*$(x[4]) + -0.7647800565294718*$(x[5]))))))) + 0.5275006439747312*1/(1 + exp(-(-0.7622628423532047 + 0.6518912481623378*1/(1 + exp(-(-0.6653700708895021 + 0.6185402094345611*$(x[1]) + 0.05069108137655398*$(x[2]) + 0.9466113725109135*$(x[3]) + 0.06805104680691931*$(x[4]) + -0.30203159362192356*$(x[5])))) + 0.4006903724184485*1/(1 + exp(-(-0.04665405044600712 + -0.8840756438370558*$(x[1]) + -0.20571795637475754*$(x[2]) + 0.8733859112268667*$(x[3]) + -0.5065045210605232*$(x[4]) + -0.7647800565294718*$(x[5]))))))))))))) - $q <= 0.0))

                     @objective(m, Min, q)

                     return m

max_stars_repo_name: PSORLab/RSActivationFunctions

max_issues_repo_name: PSORLab/RSActivationFunctions

max_forks_repo_name: PSORLab/RSActivationFunctions


text:
module TestDoctest

import StopWatchesTests
using Documenter: doctest
using Test

function test_doctest()
    doctest(StopWatchesTests; manual = false)
end

end  # module


text:
mutable struct MountainCarCMAXPlanner <: Planner
    planner::MountainCarRTAAPlanner
    discrepancy_sets::Dict{MountainCarAction,Set{MountainCarDiscState}}
end

function MountainCarCMAXPlanner(
    mountaincar::MountainCar,
    num_expansions::Int64,
    params::MountainCarParameters,
)
    planner = MountainCarRTAAPlanner(mountaincar, num_expansions, params)
    discrepancy_sets = Dict{MountainCarAction,Set{MountainCarDiscState}}()
    for action in planner.actions
        discrepancy_sets[action] = Set{MountainCarDiscState}()
    end
    MountainCarCMAXPlanner(planner, discrepancy_sets)
end

function generateHeuristic!(cmax_planner::MountainCarCMAXPlanner; max_steps = 1e4)
    generateHeuristic!(cmax_planner.planner, max_steps = max_steps)
end

function generateHeuristic!(planners::Vector{MountainCarCMAXPlanner}; max_steps = 1e4)
    for planner in planners
        generateHeuristic!(planner, max_steps = max_steps)
    end
end

function clearResiduals!(cmax_planner::MountainCarCMAXPlanner)
    clearResiduals!(cmax_planner.planner)
end

function clearResiduals!(planners::Vector{MountainCarCMAXPlanner})
    for planner in planners
        clearResiduals!(planner)
    end
end

function getHeuristic(cmax_planner::MountainCarCMAXPlanner, state::MountainCarDiscState)
    getHeuristic(cmax_planner.planner, state)
end

function getSuccessors(
    cmax_planner::MountainCarCMAXPlanner,
    state::MountainCarDiscState,
    action::MountainCarAction,
)
    next_disc_state, cost = getSuccessors(cmax_planner.planner, state, action)
    if state ∈ cmax_planner.discrepancy_sets[action]
        cost = inflated_cost
    end
    next_disc_state, cost
end

function checkGoal(cmax_planner::MountainCarCMAXPlanner, state::MountainCarDiscState)
    checkGoal(cmax_planner.planner, state)
end

function getActions(cmax_planner::MountainCarCMAXPlanner, state::MountainCarDiscState)
    getActions(cmax_planner.planner, state)
end

function act(cmax_planner::MountainCarCMAXPlanner, state::MountainCarDiscState)
    best_action, info = astar(cmax_planner, cmax_planner.planner.num_expansions, state)
    return best_action, info
end

function updateResiduals!(cmax_planner::MountainCarCMAXPlanner, info::Dict)
    updateResiduals!(cmax_planner.planner, info)
end

function addDiscrepancy!(
    cmax_planner::MountainCarCMAXPlanner,
    state::MountainCarDiscState,
    action::MountainCarAction,
)
    push!(cmax_planner.discrepancy_sets[action], state)
end


text:
######################################################################
# c_interface.jl
######################################################################

# internal pointer for ccall stuff
mutable struct rtlsdr_dev
end

mutable struct RTLSDRError <: Exception
    message::String
end

# returns a pointer to
function rtlsdr_open()
	index = 0
	rd = Array{Ptr{rtlsdr_dev},1}(undef,1)
	ret = ccall( (:rtlsdr_open, "librtlsdr"), Cint, (Ptr{Ptr{rtlsdr_dev}}, UInt32), rd, index)

	if ret != 0; throw(RTLSDRError("RTLSDR.jl reports: Error opening device.")); end

	rf = rd[1]

	# resetting buffers is critical to reading bytes
    rtlsdr_reset_buffer(rf)

	return rf
end

function rtlsdr_reset_buffer(rf::Ref{rtlsdr_dev})
	ret = ccall( (:rtlsdr_reset_buffer, "librtlsdr"), Cint, (Ref{rtlsdr_dev},), rf)
	if ret != 0; throw(RTLSDRError("RTLSDR.jl reports: Error resetting buffer (error code $ret).")); end
end

function rtlsdr_close(rf::Ref{rtlsdr_dev})
	ret = ccall( (:rtlsdr_close, "librtlsdr"), Cint, (Ref{rtlsdr_dev},), rf)
	if ret != 0; throw(RTLSDRError("RTLSDR.jl reports: Error closing device (error code $ret).")); end
end

# center frequency
function rtlsdr_set_center_freq(rf::Ref{rtlsdr_dev}, freq)
	ret = ccall( (:rtlsdr_set_center_freq, "librtlsdr"), Cint, (Ref{rtlsdr_dev}, UInt32), rf, Cint(freq))
	if ret != 0; throw(RTLSDRError("RTLSDR.jl reports: Error setting center frequency (error code $ret).")); end
end

function rtlsdr_get_center_freq(rf::Ref{rtlsdr_dev})
	ret = ccall( (:rtlsdr_get_center_freq, "librtlsdr"), UInt32, (Ref{rtlsdr_dev},), rf)
	if ret != 0; throw(RTLSDRError("RTLSDR.jl reports: Error getting center frequency (error code $ret).")); end
end

# sample rate
function rtlsdr_get_sample_rate(rf::Ref{rtlsdr_dev})
	ret = ccall( (:rtlsdr_get_sample_rate, "librtlsdr"), UInt32, (Ref{rtlsdr_dev},), rf)
	if ret != 0; throw(RTLSDRError("RTLSDR.jl reports: Error getting sample rate (error code $ret).")); end
end

function rtlsdr_set_sample_rate(rf::Ref{rtlsdr_dev}, sample_rate)
	ret = ccall( (:rtlsdr_set_sample_rate, "librtlsdr"), Cint, (Ref{rtlsdr_dev},UInt32), rf, sample_rate)
	if ret != 0; throw(RTLSDRError("RTLSDR.jl reports: Error satting sample rate (error code $ret).")); end
end

# gain
function rtlsdr_set_agc_mode(rf::Ref{rtlsdr_dev}, on)
	ret = ccall( (:rtlsdr_set_tuner_gain, "librtlsdr"), Cint, (Ref{rtlsdr_dev},Cint), rf, on)
	if ret != 0; throw(RTLSDRError("RTLSDR.jl reports: Error setting AGC mode (error code $ret).")); end
end

function rtlsdr_set_tuner_gain_mode(rf::Ref{rtlsdr_dev}, manual)
	ret = ccall( (:rtlsdr_set_tuner_gain_mode, "librtlsdr"), Cint, (Ref{rtlsdr_dev},Cint), rf, manual)
	if ret != 0; throw(RTLSDRError("RTLSDR.jl reports: Error setting tuner gain mode (error code $ret).")); end
end

function rtlsdr_set_tuner_gain(rf::Ref{rtlsdr_dev}, gain)
	ret = ccall( (:rtlsdr_set_tuner_gain, "librtlsdr"), Cint, (Ref{rtlsdr_dev},Cint), rf, gain)
	if ret != 0; throw(RTLSDRError("RTLSDR.jl reports: Error setting tuner gain (error code $ret).")); end
end

function rtlsdr_get_tuner_gain(rf::Ref{rtlsdr_dev})
	gain = Array{Cint,1}(undef,1)
	ret = ccall( (:rtlsdr_get_tuner_gain, "librtlsdr"), Cint, (Ref{rtlsdr_dev},Ptr{Cint}), rf, gain)
	if ret != 0; throw(RTLSDRError("RTLSDR.jl reports: Error getting tuner gain (error code $ret).")); end
    return gain[1]
end

# Some I/O stuff
function read_bytes(rf::Ref{rtlsdr_dev}, num_bytes)

	buf = Vector{Cuchar}(undef,num_bytes)
	bytes_read = Ref{Cint}(0)
	#println("a was ", bytes_read[])
	ret = ccall( (:rtlsdr_read_sync, "librtlsdr"), Int32, (Ref{rtlsdr_dev}, Ref{Cuchar}, Cint, Ref{Cint}), rf, buf, num_bytes, bytes_read)
	#println("ret was: ", ret); println("a is ", bytes_read[])
	if ret != 0; throw(RTLSDRError("RTLSDR.jl reports: Error while reading from device (error code $ret).")); end

	return buf
end


text:
module SfBlackHole

using Unitful

import PhysicalConstants.CODATA2018: G, ħ, c_0, k_B

export spaghettification_tensile_force, schwarzschild_radius, hawking_temperature, bekenstein_hawking_luminosity, hawking_evaporation

spaghettification_tensile_force(m_parent::Unitful.Mass, m::Unitful.Mass, l::Unitful.Length, r::Unitful.Length) = (G*m_parent*l*m)/4r^3 |> u"N"

"""
    schwarzschild_radius(m::Unitful.Mass)

Radius of a Schwarzschild black hole of mass `m`.
"""
schwarzschild_radius(m::Unitful.Mass) = 2G*m / c_0^2 |> u"m"

"""
    hawking_temperature(m::Unitful.Mass)

Black body temperature of a Schwarzschild black hole of mass `m`.
"""
hawking_temperature(m::Unitful.Mass) = (ħ * c_0^3)/(8π * G * m * k_B) |> u"K"

"""
    bekenstein_hawking_luminosity(m::Unitful.Mass)

Pure photon luminosity of a Schwarzschild black hole of mass `m`.

This approximation will break down as the temperature of the hole increases to the point where particle emission is possible.
"""
bekenstein_hawking_luminosity(m::Unitful.Mass) = upreferred((ħ * c_0^6)/(15360π * G^2 * m^2))

"""
    hawking_evaporation(m::Unitful.Mass)

Time for a Schwarzschild black hole of initial mass `m` to evaporate via Hawking radiation.
"""
hawking_evaporation(m::Unitful.Mass) = upreferred((5120π * G^2 * m^3)/(ħ * c_0^4))

end

max_stars_repo_name: icantbelieveitsnotphysics/SfPhysics

max_issues_repo_name: icantbelieveitsnotphysics/SfPhysics

max_forks_repo_name: icantbelieveitsnotphysics/SfPhysics


text:
# Invertible HINT network from Kruse et. al (2020)
# Author: Gabrio Rizzuti, rizzuti.gabrio@gatech.edu
# Date: August 2020

export NetworkHINT1D, clear_grad!, get_params

"""
    H = NetworkHINT1D(nx, ny, n_in, batchsize, n_hidden, depth; k1=3, k2=3, p1=1, p2=1, s1=1, s2=1)
 Create a HINT network for data-driven generative modeling based
 on the change of variables formula.
 *Input*:
 - `nx`, `ny`, `n_in`, `batchsize`: spatial dimensions, number of channels and batchsize of input tensors `X`
 - `n_hidden`: number of hidden units in residual blocks
 - `depth`: number network layers
 - `k1`, `k2`: kernel size for first and third residual layer (`k1`) and second layer (`k2`)
 - `p1`, `p2`: respective padding sizes for residual block layers
 - `s1`, `s2`: respective strides for residual block layers
 *Output*:
 - `H`: HINT network
 *Usage:*
 - Forward mode: `Z, logdet = H.forward(X)`
 - Inverse mode: `X = H.inverse(Z)`
 - Backward mode: `ΔX, X = H.backward(ΔZ, Z)`
 *Trainable parameters:*
 - None in `H` itself
 - Trainable parameters in activation normalizations `H.AN[i]`, and in coupling layers `H.CL[i]`, where `i` ranges from `1` to `depth`.
 See also: [`ActNorm`](@ref), [`CouplingLayerHINT`](@ref), [`get_params`](@ref), [`clear_grad!`](@ref)
"""
mutable struct NetworkHINT1D <: InvertibleNetwork
    AN::AbstractArray{ActNorm, 1}
    CL::AbstractArray{CouplingLayerHINT, 1}
    logdet::Bool
    is_reversed::Bool
end

@Flux.functor NetworkHINT1D

# Constructor
function NetworkHINT1D(n_in::Int64, batchsize::Int64, n_hidden::Int64, depth::Int64; logdet=true, permute="none")

    AN = Array{ActNorm}(undef, depth+1)
    CL = Array{CouplingLayerHINT}(undef, depth)

    # Create layers
    for j=1:depth
        AN[j] = ActNorm(n_in; logdet=logdet)
        CL[j] = CouplingLayerHINT(1, 1, n_in, n_hidden, batchsize; permute=permute, k1=1, k2=1, p1=0, p2=0, logdet=logdet)
    end
    AN[depth+1] = ActNorm(n_in; logdet=logdet)

    return NetworkHINT1D(AN, CL, logdet, false)
end

# Forward pass and compute logdet
function forward(X, H::NetworkHINT1D; logdet=nothing)
    isnothing(logdet) ? logdet = (H.logdet && ~H.is_reversed) : logdet = logdet

    depth = length(H.CL)
    logdet_ = 0f0
    for j=1:depth
        logdet ? (X_, logdet_an) = H.AN[j].forward(X) : X_ = H.AN[j].forward(X)
        logdet ? (X, logdet_cl) = H.CL[j].forward(X_) : X = H.CL[j].forward(X_)
        logdet && (logdet_ += (logdet_an + logdet_cl))
    end
    logdet ? (X, logdet_an) = H.AN[depth+1].forward(X) : X = H.AN[depth+1].forward(X)
    logdet ? (return X, logdet_) : (return X)
end

# Inverse pass and compute gradients
function inverse(Z, H::NetworkHINT1D; logdet=nothing)
    isnothing(logdet) ? logdet = (H.logdet && H.is_reversed) : logdet = logdet

    depth = length(H.CL)
    logdet_ = 0f0
    logdet ? (Z, logdet_an) = H.AN[depth+1].inverse(Z; logdet=true) : Z = H.AN[depth+1].inverse(Z; logdet=false)
    logdet && (logdet_ += logdet_an)
    for j=depth:-1:1
        logdet ? (Z_, logdet_an) = H.CL[j].inverse(Z; logdet=true) : Z_ = H.CL[j].inverse(Z; logdet=false)
        logdet ? (Z, logdet_cl) = H.AN[j].inverse(Z_; logdet=true) : Z = H.AN[j].inverse(Z_; logdet=false)
        logdet && (logdet_ += (logdet_an + logdet_cl))
    end
    logdet ? (return Z, logdet_) : (return Z)
end

# Backward pass and compute gradients
function backward(ΔZ, Z, H::NetworkHINT1D)
    depth = length(H.CL)
    ΔZ, Z = H.AN[depth+1].backward(ΔZ, Z)
    for j=depth:-1:1
        ΔZ_, Z_ = H.CL[j].backward(ΔZ, Z)
        ΔZ, Z = H.AN[j].backward(ΔZ_, Z_)
    end
    return ΔZ, Z
end

# Clear gradients
function clear_grad!(H::NetworkHINT1D)
    depth = length(H.CL)
    for j=1:depth
        clear_grad!(H.AN[j])
        clear_grad!(H.CL[j])
    end
    clear_grad!(H.AN[depth+1])
end

# Get parameters
function get_params(H::NetworkHINT1D)
    depth = length(H.CL)
    p = []
    for j=1:depth
        p = cat(p, get_params(H.AN[j]); dims=1)
        p = cat(p, get_params(H.CL[j]); dims=1)
    end
    p = cat(p, get_params(H.AN[depth+1]); dims=1)
    return p
end

# Set is_reversed flag in full network tree
function tag_as_reversed!(H::NetworkHINT1D, tag::Bool)
    depth = length(H.CL)
    H.is_reversed = tag
    for j=1:depth
        tag_as_reversed!(H.AN[j], tag)
        tag_as_reversed!(H.CL[j], tag)
    end
    tag_as_reversed!(H.AN[depth+1], tag)
    return H
end


text:
#!/usr/bin/env julia

# Tests with a 3D Taylor-Green velocity field.
# https://en.wikipedia.org/wiki/Taylor%E2%80%93Green_vortex

using PencilFFTs

import MPI

using BenchmarkTools
using Test

BenchmarkTools.DEFAULT_PARAMETERS.seconds = 0.1

include("include/FourierOperations.jl")
using .FourierOperations
import .FourierOperations: VectorField

include("include/MPITools.jl")
using .MPITools

const SAVE_VTK = false

if SAVE_VTK
    using WriteVTK
end

const DATA_DIMS = (16, 8, 16)
const GEOMETRY = ((0.0, 4pi), (0.0, 2pi), (0.0, 2pi))

const TG_U0 = 3.0
const TG_K0 = 2.0

# Initialise TG flow (global view version).
function taylor_green!(u_local::VectorField, g::PhysicalGrid, u0=TG_U0, k0=TG_K0)
    u = map(global_view, u_local)

    @inbounds for (n, I) in enumerate(CartesianIndices(u[1]))
        x, y, z = g[I]
        u[1][n] =  u0 * sin(k0 * x) * cos(k0 * y) * cos(k0 * z)
        u[2][n] = -u0 * cos(k0 * x) * sin(k0 * y) * cos(k0 * z)
        u[3][n] = 0
    end

    u_local
end

# Initialise TG flow (local grid version).
function taylor_green!(u::VectorField, g::PhysicalGridIterator, u0=TG_U0, k0=TG_K0)
    @assert size_local(u[1]) === size(g)

    @inbounds for (i, (x, y, z)) in enumerate(g)
        u[1][i] =  u0 * sin(k0 * x) * cos(k0 * y) * cos(k0 * z)
        u[2][i] = -u0 * cos(k0 * x) * sin(k0 * y) * cos(k0 * z)
        u[3][i] = 0
    end

    u
end

# Verify vorticity of Taylor-Green flow.
function check_vorticity_TG(ω::VectorField{T}, g::PhysicalGridIterator, comm,
                            u0=TG_U0, k0=TG_K0) where {T}
    diff2 = zero(T)

    @inbounds for (i, (x, y, z)) in enumerate(g)
        ω_TG = (
            -u0 * k0 * cos(k0 * x) * sin(k0 * y) * sin(k0 * z),
            -u0 * k0 * sin(k0 * x) * cos(k0 * y) * sin(k0 * z),
            2u0 * k0 * sin(k0 * x) * sin(k0 * y) * cos(k0 * z),
        )
        for n = 1:3
            diff2 += (ω[n][i] - ω_TG[n])^2
        end
    end

    MPI.Allreduce(diff2, +, comm)
end

function fields_to_vtk(g::PhysicalGridIterator, basename, fields::Vararg{Pair})
    isempty(fields) && return

    # This works but it's heavier, since g.data is a dense array:
    # xyz = g.data
    # It would generate a structured grid (.vts) file, instead of rectilinear
    # (.vtr).

    xyz = ntuple(n -> g.grid[n][g.range[n]], Val(3))

    vtk_grid(basename, xyz) do vtk
        for p in fields
            name = p.first
            u = p.second
            vtk_point_data(vtk, u, name)
        end
    end
end

function main()
    size_in = DATA_DIMS
    comm = MPI.COMM_WORLD
    Nproc = MPI.Comm_size(comm)
    rank = MPI.Comm_rank(comm)

    silence_stdout(comm)

    pdims_2d = let pdims = zeros(Int, 2)
        MPI.Dims_create!(Nproc, pdims)
        pdims[1], pdims[2]
    end

    plan = PencilFFTPlan(size_in, Transforms.RFFT(), pdims_2d, comm,
                         permute_dims=Val(true))
    u = allocate_input(plan, Val(3))  # allocate vector field

    g_global = PhysicalGrid(GEOMETRY, size_in, permutation(u))
    g_local = LocalGridIterator(g_global, u)
    taylor_green!(u, g_local)   # initialise TG velocity field

    uF = plan * u  # apply 3D FFT

    gF_global = FourierGrid(GEOMETRY, size_in, permutation(uF))
    gF_local = LocalGridIterator(gF_global, uF)
    ωF = similar.(uF)

    @testset "Taylor-Green" begin
        let u_glob = similar.(u)
            # Compare with initialisation using global indices
            taylor_green!(u_glob, g_global)
            @test all(u .≈ u_glob)
        end

        div2 = divergence(uF, gF_local)

        # Compare local and global versions of divergence
        @test div2 == divergence(uF, gF_global)

        print("divergence local...  ")
        @btime divergence($uF, $gF_local)

        print("divergence global... ")
        @btime divergence($uF, $gF_global)

        div2_mean = MPI.Allreduce(div2, +, comm) / prod(size_in)
        @test div2_mean ≈ 0 atol=1e-16

        curl!(ωF, uF, gF_local)
        ω = plan \ ωF

        # Test global version of curl
        ωF_glob = similar.(ωF)
        curl!(ωF_glob, uF, gF_global)
        @test all(ωF_glob .== ωF)

        print("curl! local...       ")
        @btime curl!($ωF, $uF, $gF_local)

        print("curl! global...      ")
        @btime curl!($ωF_glob, $uF, $gF_global)

        ω_err = check_vorticity_TG(ω, g_local, comm)
        @test ω_err ≈ 0 atol=1e-16
    end

    if SAVE_VTK
        fields_to_vtk(g_local, "TG_proc_$(rank + 1)of$(Nproc)",
                      "u" => u, "ω" => ω)
    end

    nothing
end

MPI.Init()
main()


text:
#a few patches that make the builtin lu factorization possible.

#taken from base/LinAlg/generic.jl

if VERSION <= v"0.6.0"
    #apparently these issues have been fixed in MASTER past v0.6.0

function Base.LinAlg.istril(A::AbstractMatrix)
    m, n = size(A)
    for j = 2:n, i = 1:min(j-1,m)
        if A[i,j] != zero(eltype(A))
            return false
        end
    end
    return true
end

function Base.LinAlg.istriu(A::AbstractMatrix)
    m, n = size(A)
    for j = 1:min(n,m-1), i = j+1:m
        if A[i,j] != zero(eltype(A))
            return false
        end
    end
    return true
end

#taken from base/LinAlg/lu.jl
function Base.LinAlg.generic_lufact!(A::StridedMatrix{T}, ::Type{Val{Pivot}} = Val{true}) where {T,Pivot}
    m, n = size(A)
    minmn = min(m,n)
    info = 0
    ipiv = Vector{Base.LinAlg.BlasInt}(minmn)
    @inbounds begin
        for k = 1:minmn
            # find index max
            kp = k
            if Pivot
                amax = real(zero(T))
                for i = k:m
                    absi = abs(A[i,k])
                    if absi > amax
                        kp = i
                        amax = absi
                    end
                end
            end
            ipiv[k] = kp
            if A[kp,k] != zero(T)
                if k != kp
                    # Interchange
                    for i = 1:n
                        tmp = A[k,i]
                        A[k,i] = A[kp,i]
                        A[kp,i] = tmp
                    end
                end
                # Scale first column
                Akkinv = inv(A[k,k])
                for i = k+1:m
                    A[i,k] *= Akkinv
                end
            elseif info == 0
                info = k
            end
            # Update the rest
            for j = k+1:n
                for i = k+1:m
                    A[i,j] -= A[i,k]*A[k,j]
                end
            end
        end
    end
    Base.LinAlg.LU{T,typeof(A)}(A, ipiv, convert(Base.LinAlg.BlasInt, info))
end

end

max_stars_repo_name: ityonemo/SigmoidNumbers

max_issues_repo_name: ityonemo/SigmoidNumbers

max_forks_repo_name: ityonemo/SigmoidNumbers


text:
function direct_solve_poisson2d(problem::FDPoisson2DProblem)
    u = problem.A\problem.rhs;
    return u
end


text:
using NumericalMethodsforEngineers

a = [16. 4. 8.; 4. 5. -4.; 8. -4. 22.]
b = [16., 18., -22.]

a = sparse(a)

F = cholfact(a)
upper = F[:U]
upper |> display

lower = F[:L]
lower |> display

y = lower \ b

c = upper \ y
println("Solution Vector: \n $c")

@test c == a \ b


text:
module PiSMC

using Distributed

include("naive.jl")
include("singlethread.jl")
include("multithread.jl")
include("distributed.jl")

end # module


text:
function tensorise(xs::Array...)
  xs = promote(xs...)
  T = eltype(xs[1])

  m = length(xs)
  N = prod(x->length(x), xs)
  X = Array{T}(m,N)
  nk = 1
  for d=1:m
    k = 1
    rk = 0
    for i=1:N
      X[d, i] = xs[d][k]
      rk += 1
      if rk==nk
        k = k<length(xs[d]) ? k+1 : 1
        rk = 0
      end
    end
    nk = nk * length(xs[d])
  end
  X
end

colvec{T}(x::Vector{T}) = reshape(x, (length(x), 1))::Matrix{T}
rowvec{T}(x::Vector{T}) = reshape(x, (1, length(x)))::Matrix{T}

export
  tensorise,
  colvec,
  rowvec


text:
# Make sure that arguments are only evaluated once
@testset "one-time argument evaluation" begin
    function counter()
        i = 0
        count() = i += 1
        return count
    end

    p = @patch string(x) = "$x"

    # Check code path where we execute a patch
    c = counter()
    apply(p) do
        @test (@mock string(c())) == "1"
    end

    # Check code path where we fallback to the original function
    c = counter()
    apply(Patch[]) do
        @test (@mock string(c())) == "1"
    end
end