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

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

Describes recommendation export jobs created in the last seven days. Use the
ExportAutoScalingGroupRecommendations or ExportEC2InstanceRecommendations actions to
request an export of your recommendations. Then use the DescribeRecommendationExportJobs
action to view your export jobs.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"filters"`: An array of objects that describe a filter to return a more specific list of
  export jobs.
- `"jobIds"`: The identification numbers of the export jobs to return. An export job ID is
  returned when you create an export using the ExportAutoScalingGroupRecommendations or
  ExportEC2InstanceRecommendations actions. All export jobs created in the last seven days
  are returned if this parameter is omitted.
- `"maxResults"`: The maximum number of export jobs to return with a single request. To
  retrieve the remaining results, make another request with the returned NextToken value.
- `"nextToken"`: The token to advance to the next page of export jobs.
"""
describe_recommendation_export_jobs(; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("DescribeRecommendationExportJobs"; aws_config=aws_config)
describe_recommendation_export_jobs(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("DescribeRecommendationExportJobs", params; aws_config=aws_config)

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

Exports optimization recommendations for Auto Scaling groups. Recommendations are exported
in a comma-separated values (.csv) file, and its metadata in a JavaScript Object Notation
(.json) file, to an existing Amazon Simple Storage Service (Amazon S3) bucket that you
specify. For more information, see Exporting Recommendations in the Compute Optimizer User
Guide. You can have only one Auto Scaling group export job in progress per AWS Region.

# Arguments
- `s3_destination_config`: An object to specify the destination Amazon Simple Storage
  Service (Amazon S3) bucket name and key prefix for the export job. You must create the
  destination Amazon S3 bucket for your recommendations export before you create the export
  job. Compute Optimizer does not create the S3 bucket for you. After you create the S3
  bucket, ensure that it has the required permission policy to allow Compute Optimizer to
  write the export file to it. If you plan to specify an object prefix when you create the
  export job, you must include the object prefix in the policy that you add to the S3 bucket.
  For more information, see Amazon S3 Bucket Policy for Compute Optimizer in the Compute
  Optimizer user guide.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"accountIds"`: The IDs of the AWS accounts for which to export Auto Scaling group
  recommendations. If your account is the management account of an organization, use this
  parameter to specify the member account for which you want to export recommendations. This
  parameter cannot be specified together with the include member accounts parameter. The
  parameters are mutually exclusive. Recommendations for member accounts are not included in
  the export if this parameter, or the include member accounts parameter, is omitted. You can
  specify multiple account IDs per request.
- `"fieldsToExport"`: The recommendations data to include in the export file. For more
  information about the fields that can be exported, see Exported files in the Compute
  Optimizer User Guide.
- `"fileFormat"`: The format of the export file. The only export file format currently
  supported is Csv.
- `"filters"`: An array of objects that describe a filter to export a more specific set of
  Auto Scaling group recommendations.
- `"includeMemberAccounts"`: Indicates whether to include recommendations for resources in
  all member accounts of the organization if your account is the management account of an
  organization. The member accounts must also be opted in to Compute Optimizer, and trusted
  access for Compute Optimizer must be enabled in the organization account. For more
  information, see Compute Optimizer and AWS Organizations trusted access in the AWS Compute
  Optimizer User Guide. Recommendations for member accounts of the organization are not
  included in the export file if this parameter is omitted. This parameter cannot be
  specified together with the account IDs parameter. The parameters are mutually exclusive.
  Recommendations for member accounts are not included in the export if this parameter, or
  the account IDs parameter, is omitted.
"""
export_auto_scaling_group_recommendations(s3DestinationConfig; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("ExportAutoScalingGroupRecommendations", Dict{String, Any}("s3DestinationConfig"=>s3DestinationConfig); aws_config=aws_config)
export_auto_scaling_group_recommendations(s3DestinationConfig, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("ExportAutoScalingGroupRecommendations", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("s3DestinationConfig"=>s3DestinationConfig), params)); aws_config=aws_config)

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

Exports optimization recommendations for Amazon EBS volumes. Recommendations are exported
in a comma-separated values (.csv) file, and its metadata in a JavaScript Object Notation
(.json) file, to an existing Amazon Simple Storage Service (Amazon S3) bucket that you
specify. For more information, see Exporting Recommendations in the Compute Optimizer User
Guide. You can have only one Amazon EBS volume export job in progress per AWS Region.

# Arguments
- `s3_destination_config`:

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"accountIds"`: The IDs of the AWS accounts for which to export Amazon EBS volume
  recommendations. If your account is the management account of an organization, use this
  parameter to specify the member account for which you want to export recommendations. This
  parameter cannot be specified together with the include member accounts parameter. The
  parameters are mutually exclusive. Recommendations for member accounts are not included in
  the export if this parameter, or the include member accounts parameter, is omitted. You can
  specify multiple account IDs per request.
- `"fieldsToExport"`: The recommendations data to include in the export file. For more
  information about the fields that can be exported, see Exported files in the Compute
  Optimizer User Guide.
- `"fileFormat"`: The format of the export file. The only export file format currently
  supported is Csv.
- `"filters"`: An array of objects that describe a filter to export a more specific set of
  Amazon EBS volume recommendations.
- `"includeMemberAccounts"`: Indicates whether to include recommendations for resources in
  all member accounts of the organization if your account is the management account of an
  organization. The member accounts must also be opted in to Compute Optimizer, and trusted
  access for Compute Optimizer must be enabled in the organization account. For more
  information, see Compute Optimizer and AWS Organizations trusted access in the AWS Compute
  Optimizer User Guide. Recommendations for member accounts of the organization are not
  included in the export file if this parameter is omitted. This parameter cannot be
  specified together with the account IDs parameter. The parameters are mutually exclusive.
  Recommendations for member accounts are not included in the export if this parameter, or
  the account IDs parameter, is omitted.
"""
export_ebsvolume_recommendations(s3DestinationConfig; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("ExportEBSVolumeRecommendations", Dict{String, Any}("s3DestinationConfig"=>s3DestinationConfig); aws_config=aws_config)
export_ebsvolume_recommendations(s3DestinationConfig, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("ExportEBSVolumeRecommendations", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("s3DestinationConfig"=>s3DestinationConfig), params)); aws_config=aws_config)

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

Exports optimization recommendations for Amazon EC2 instances. Recommendations are exported
in a comma-separated values (.csv) file, and its metadata in a JavaScript Object Notation
(.json) file, to an existing Amazon Simple Storage Service (Amazon S3) bucket that you
specify. For more information, see Exporting Recommendations in the Compute Optimizer User
Guide. You can have only one Amazon EC2 instance export job in progress per AWS Region.

# Arguments
- `s3_destination_config`: An object to specify the destination Amazon Simple Storage
  Service (Amazon S3) bucket name and key prefix for the export job. You must create the
  destination Amazon S3 bucket for your recommendations export before you create the export
  job. Compute Optimizer does not create the S3 bucket for you. After you create the S3
  bucket, ensure that it has the required permission policy to allow Compute Optimizer to
  write the export file to it. If you plan to specify an object prefix when you create the
  export job, you must include the object prefix in the policy that you add to the S3 bucket.
  For more information, see Amazon S3 Bucket Policy for Compute Optimizer in the Compute
  Optimizer user guide.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"accountIds"`: The IDs of the AWS accounts for which to export instance recommendations.
  If your account is the management account of an organization, use this parameter to specify
  the member account for which you want to export recommendations. This parameter cannot be
  specified together with the include member accounts parameter. The parameters are mutually
  exclusive. Recommendations for member accounts are not included in the export if this
  parameter, or the include member accounts parameter, is omitted. You can specify multiple
  account IDs per request.
- `"fieldsToExport"`: The recommendations data to include in the export file. For more
  information about the fields that can be exported, see Exported files in the Compute
  Optimizer User Guide.
- `"fileFormat"`: The format of the export file. The only export file format currently
  supported is Csv.
- `"filters"`: An array of objects that describe a filter to export a more specific set of
  instance recommendations.
- `"includeMemberAccounts"`: Indicates whether to include recommendations for resources in
  all member accounts of the organization if your account is the management account of an
  organization. The member accounts must also be opted in to Compute Optimizer, and trusted
  access for Compute Optimizer must be enabled in the organization account. For more
  information, see Compute Optimizer and AWS Organizations trusted access in the AWS Compute
  Optimizer User Guide. Recommendations for member accounts of the organization are not
  included in the export file if this parameter is omitted. Recommendations for member
  accounts are not included in the export if this parameter, or the account IDs parameter, is
  omitted.
"""
export_ec2_instance_recommendations(s3DestinationConfig; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("ExportEC2InstanceRecommendations", Dict{String, Any}("s3DestinationConfig"=>s3DestinationConfig); aws_config=aws_config)
export_ec2_instance_recommendations(s3DestinationConfig, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("ExportEC2InstanceRecommendations", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("s3DestinationConfig"=>s3DestinationConfig), params)); aws_config=aws_config)

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

Exports optimization recommendations for AWS Lambda functions. Recommendations are exported
in a comma-separated values (.csv) file, and its metadata in a JavaScript Object Notation
(.json) file, to an existing Amazon Simple Storage Service (Amazon S3) bucket that you
specify. For more information, see Exporting Recommendations in the Compute Optimizer User
Guide. You can have only one Lambda function export job in progress per AWS Region.

# Arguments
- `s3_destination_config`:

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"accountIds"`: The IDs of the AWS accounts for which to export Lambda function
  recommendations. If your account is the management account of an organization, use this
  parameter to specify the member account for which you want to export recommendations. This
  parameter cannot be specified together with the include member accounts parameter. The
  parameters are mutually exclusive. Recommendations for member accounts are not included in
  the export if this parameter, or the include member accounts parameter, is omitted. You can
  specify multiple account IDs per request.
- `"fieldsToExport"`: The recommendations data to include in the export file. For more
  information about the fields that can be exported, see Exported files in the Compute
  Optimizer User Guide.
- `"fileFormat"`: The format of the export file. The only export file format currently
  supported is Csv.
- `"filters"`: An array of objects that describe a filter to export a more specific set of
  Lambda function recommendations.
- `"includeMemberAccounts"`: Indicates whether to include recommendations for resources in
  all member accounts of the organization if your account is the management account of an
  organization. The member accounts must also be opted in to Compute Optimizer, and trusted
  access for Compute Optimizer must be enabled in the organization account. For more
  information, see Compute Optimizer and AWS Organizations trusted access in the AWS Compute
  Optimizer User Guide. Recommendations for member accounts of the organization are not
  included in the export file if this parameter is omitted. This parameter cannot be
  specified together with the account IDs parameter. The parameters are mutually exclusive.
  Recommendations for member accounts are not included in the export if this parameter, or
  the account IDs parameter, is omitted.
"""
export_lambda_function_recommendations(s3DestinationConfig; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("ExportLambdaFunctionRecommendations", Dict{String, Any}("s3DestinationConfig"=>s3DestinationConfig); aws_config=aws_config)
export_lambda_function_recommendations(s3DestinationConfig, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("ExportLambdaFunctionRecommendations", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("s3DestinationConfig"=>s3DestinationConfig), params)); aws_config=aws_config)

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

Returns Auto Scaling group recommendations. AWS Compute Optimizer generates recommendations
for Amazon EC2 Auto Scaling groups that meet a specific set of requirements. For more
information, see the Supported resources and requirements in the AWS Compute Optimizer User
Guide.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"accountIds"`: The ID of the AWS account for which to return Auto Scaling group
  recommendations. If your account is the management account of an organization, use this
  parameter to specify the member account for which you want to return Auto Scaling group
  recommendations. Only one account ID can be specified per request.
- `"autoScalingGroupArns"`: The Amazon Resource Name (ARN) of the Auto Scaling groups for
  which to return recommendations.
- `"filters"`: An array of objects that describe a filter that returns a more specific list
  of Auto Scaling group recommendations.
- `"maxResults"`: The maximum number of Auto Scaling group recommendations to return with a
  single request. To retrieve the remaining results, make another request with the returned
  NextToken value.
- `"nextToken"`: The token to advance to the next page of Auto Scaling group
  recommendations.
"""
get_auto_scaling_group_recommendations(; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("GetAutoScalingGroupRecommendations"; aws_config=aws_config)
get_auto_scaling_group_recommendations(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("GetAutoScalingGroupRecommendations", params; aws_config=aws_config)

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

Returns Amazon Elastic Block Store (Amazon EBS) volume recommendations. AWS Compute
Optimizer generates recommendations for Amazon EBS volumes that meet a specific set of
requirements. For more information, see the Supported resources and requirements in the AWS
Compute Optimizer User Guide.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"accountIds"`: The ID of the AWS account for which to return volume recommendations. If
  your account is the management account of an organization, use this parameter to specify
  the member account for which you want to return volume recommendations. Only one account ID
  can be specified per request.
- `"filters"`: An array of objects that describe a filter that returns a more specific list
  of volume recommendations.
- `"maxResults"`: The maximum number of volume recommendations to return with a single
  request. To retrieve the remaining results, make another request with the returned
  NextToken value.
- `"nextToken"`: The token to advance to the next page of volume recommendations.
- `"volumeArns"`: The Amazon Resource Name (ARN) of the volumes for which to return
  recommendations.
"""
get_ebsvolume_recommendations(; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("GetEBSVolumeRecommendations"; aws_config=aws_config)
get_ebsvolume_recommendations(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("GetEBSVolumeRecommendations", params; aws_config=aws_config)

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

Returns Amazon EC2 instance recommendations. AWS Compute Optimizer generates
recommendations for Amazon Elastic Compute Cloud (Amazon EC2) instances that meet a
specific set of requirements. For more information, see the Supported resources and
requirements in the AWS Compute Optimizer User Guide.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"accountIds"`: The ID of the AWS account for which to return instance recommendations.
  If your account is the management account of an organization, use this parameter to specify
  the member account for which you want to return instance recommendations. Only one account
  ID can be specified per request.
- `"filters"`: An array of objects that describe a filter that returns a more specific list
  of instance recommendations.
- `"instanceArns"`: The Amazon Resource Name (ARN) of the instances for which to return
  recommendations.
- `"maxResults"`: The maximum number of instance recommendations to return with a single
  request. To retrieve the remaining results, make another request with the returned
  NextToken value.
- `"nextToken"`: The token to advance to the next page of instance recommendations.
"""
get_ec2_instance_recommendations(; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("GetEC2InstanceRecommendations"; aws_config=aws_config)
get_ec2_instance_recommendations(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("GetEC2InstanceRecommendations", params; aws_config=aws_config)

"""
    get_ec2_recommendation_projected_metrics(end_time, instance_arn, period, start_time, stat)
    get_ec2_recommendation_projected_metrics(end_time, instance_arn, period, start_time, stat, params::Dict{String,<:Any})

Returns the projected utilization metrics of Amazon EC2 instance recommendations.  The Cpu
and Memory metrics are the only projected utilization metrics returned when you run this
action. Additionally, the Memory metric is returned only for resources that have the
unified CloudWatch agent installed on them. For more information, see Enabling Memory
Utilization with the CloudWatch Agent.

# Arguments
- `end_time`: The time stamp of the last projected metrics data point to return.
- `instance_arn`: The Amazon Resource Name (ARN) of the instances for which to return
  recommendation projected metrics.
- `period`: The granularity, in seconds, of the projected metrics data points.
- `start_time`: The time stamp of the first projected metrics data point to return.
- `stat`: The statistic of the projected metrics.

"""
get_ec2_recommendation_projected_metrics(endTime, instanceArn, period, startTime, stat; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("GetEC2RecommendationProjectedMetrics", Dict{String, Any}("endTime"=>endTime, "instanceArn"=>instanceArn, "period"=>period, "startTime"=>startTime, "stat"=>stat); aws_config=aws_config)
get_ec2_recommendation_projected_metrics(endTime, instanceArn, period, startTime, stat, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("GetEC2RecommendationProjectedMetrics", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("endTime"=>endTime, "instanceArn"=>instanceArn, "period"=>period, "startTime"=>startTime, "stat"=>stat), params)); aws_config=aws_config)

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

Returns the enrollment (opt in) status of an account to the AWS Compute Optimizer service.
If the account is the management account of an organization, this action also confirms the
enrollment status of member accounts within the organization.

"""
get_enrollment_status(; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("GetEnrollmentStatus"; aws_config=aws_config)
get_enrollment_status(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("GetEnrollmentStatus", params; aws_config=aws_config)

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

Returns AWS Lambda function recommendations. AWS Compute Optimizer generates
recommendations for functions that meet a specific set of requirements. For more
information, see the Supported resources and requirements in the AWS Compute Optimizer User
Guide.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"accountIds"`: The ID of the AWS account for which to return function recommendations.
  If your account is the management account of an organization, use this parameter to specify
  the member account for which you want to return function recommendations. Only one account
  ID can be specified per request.
- `"filters"`: An array of objects that describe a filter that returns a more specific list
  of function recommendations.
- `"functionArns"`: The Amazon Resource Name (ARN) of the functions for which to return
  recommendations. You can specify a qualified or unqualified ARN. If you specify an
  unqualified ARN without a function version suffix, Compute Optimizer will return
  recommendations for the latest (LATEST) version of the function. If you specify a qualified
  ARN with a version suffix, Compute Optimizer will return recommendations for the specified
  function version. For more information about using function versions, see Using versions in
  the AWS Lambda Developer Guide.
- `"maxResults"`: The maximum number of function recommendations to return with a single
  request. To retrieve the remaining results, make another request with the returned
  NextToken value.
- `"nextToken"`: The token to advance to the next page of function recommendations.
"""
get_lambda_function_recommendations(; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("GetLambdaFunctionRecommendations"; aws_config=aws_config)
get_lambda_function_recommendations(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("GetLambdaFunctionRecommendations", params; aws_config=aws_config)

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

Returns the optimization findings for an account. It returns the number of:   Amazon EC2
instances in an account that are Underprovisioned, Overprovisioned, or Optimized.   Auto
Scaling groups in an account that are NotOptimized, or Optimized.   Amazon EBS volumes in
an account that are NotOptimized, or Optimized.   Lambda functions in an account that are
NotOptimized, or Optimized.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"accountIds"`: The ID of the AWS account for which to return recommendation summaries.
  If your account is the management account of an organization, use this parameter to specify
  the member account for which you want to return recommendation summaries. Only one account
  ID can be specified per request.
- `"maxResults"`: The maximum number of recommendation summaries to return with a single
  request. To retrieve the remaining results, make another request with the returned
  NextToken value.
- `"nextToken"`: The token to advance to the next page of recommendation summaries.
"""
get_recommendation_summaries(; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("GetRecommendationSummaries"; aws_config=aws_config)
get_recommendation_summaries(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("GetRecommendationSummaries", params; aws_config=aws_config)

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

Updates the enrollment (opt in and opt out) status of an account to the AWS Compute
Optimizer service. If the account is a management account of an organization, this action
can also be used to enroll member accounts within the organization. You must have the
appropriate permissions to opt in to Compute Optimizer, to view its recommendations, and to
opt out. For more information, see Controlling access with AWS Identity and Access
Management in the AWS Compute Optimizer User Guide. When you opt in, Compute Optimizer
automatically creates a Service-Linked Role in your account to access its data. For more
information, see Using Service-Linked Roles for AWS Compute Optimizer in the AWS Compute
Optimizer User Guide.

# Arguments
- `status`: The new enrollment status of the account. The following status options are
  available:    Active - Opts in your account to the Compute Optimizer service. Compute
  Optimizer begins analyzing the configuration and utilization metrics of your AWS resources
  after you opt in. For more information, see Metrics analyzed by AWS Compute Optimizer in
  the AWS Compute Optimizer User Guide.    Inactive - Opts out your account from the Compute
  Optimizer service. Your account's recommendations and related metrics data will be deleted
  from Compute Optimizer after you opt out.    The Pending and Failed options cannot be used
  to update the enrollment status of an account. They are returned in the response of a
  request to update the enrollment status of an account.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"includeMemberAccounts"`: Indicates whether to enroll member accounts of the
  organization if the account is the management account of an organization.
"""
update_enrollment_status(status; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("UpdateEnrollmentStatus", Dict{String, Any}("status"=>status); aws_config=aws_config)
update_enrollment_status(status, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = compute_optimizer("UpdateEnrollmentStatus", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("status"=>status), params)); aws_config=aws_config)


text:
#!/usr/bin/env python
# -*- coding: utf-8 -*-

#from __future__ import division, print_function

using Optim
include("transit_model_sampled.jl")
include("transit_orb.jl")
include("occultquad.jl")
include("kepler.jl")
#import os
#import sys
#import corner
#import emcee3
#import pickle
#import fitsio
using FITSIO
#import numpy as np
#import matplotlib.pyplot as plt
#from scipy.optimize import minimize

#using celerite
include("../src/compile_matrix_symm.jl")
include("../src/compute_likelihood.jl")
using PyPlot
#from plot_setup import setup, get_figsize
#from transit_model import RotationTerm, TransitModel

#setup()
#np.random.seed(42)

fname= "data/kplr001430163-2013011073258_llc.fits"
fits_data = FITS(fname);
t_tmp = float(read(fits_data[2],"TIME"))
sapq = read(fits_data[2],"SAP_QUALITY")
y_tmp = float(read(fits_data[2],"PDCSAP_FLUX"))
yerr_tmp = float(read(fits_data[2],"PDCSAP_FLUX_ERR"))
nt = size(t_tmp)[1]
# See how many "good" data points there are:
good = falses(nt)
good_count = 0
for i=1:nt
  if isfinite(t_tmp[i]) && isfinite(y_tmp[i]) && sapq[i] == 0
    good[i] = true
    good_count += 1
  end
end
# Now, make arrays to store the good data:
N =  1000
t = zeros(N)
y = zeros(N)
yerr = zeros(N)
count = 1
for i=1:nt
  if isfinite(t_tmp[i]) && isfinite(y_tmp[i]) && sapq[i] == 0 && count <= N
    t[count]=t_tmp[i]
    y[count]=y_tmp[i]
    yerr[count]=yerr_tmp[i]
    count +=1
  end
end
dtmax = 0.0
for i=2:N
  if t[i]-t[i-1] > dtmax
    dtmax = t[i]-t[i-1]
  end
end
# The final number of data points we have is count:
# Shift the zero-point of time to be the middle of the dataset:
t -= 0.5*(minimum(t)+maximum(t))
println("Time range: ",minimum(t)," ",maximum(t))
hdr = read_header(fits_data[2]);

#data, hdr = fitsio.read("data/kplr001430163-2013011073258_llc.fits",
#                        header=True)

texp = float(hdr["INT_TIME"] * hdr["NUM_FRM"]) / 60. / 60. / 24.

#N = 1000
#m = data["SAP_QUALITY"] == 0
#m &= np.isfinite(data["TIME"])
#m &= np.isfinite(data["PDCSAP_FLUX"])
#t = np.ascontiguousarray(data["TIME"][m], dtype=np.float64)[:N]
#y = np.ascontiguousarray(data["PDCSAP_FLUX"][m], dtype=np.float64)[:N]
#yerr = np.ascontiguousarray(data["PDCSAP_FLUX_ERR"][m], dtype=np.float64)[:N]
#t -= 0.5 * (t.min() + t.max())

true_params = [
    0.0,         # mean flux
    log(8.0),    # period
    log(0.015),  # Rp / Rs
    log(0.5),    # duration
    0.0,            # t_0
    0.5,            # impact
    0.5,            # q_1
    0.5,            # q_2
]

println("Calling transit model")
true_model = transit_model_sampled(t,true_params)
#u1 = 2.*sqrt(true_params[8])*true_params[9]
#u2 = sqrt(true_params[8])*(1.-2.*true_params[9])
#x = 1.-sqrt(1.-true_params[7]^2)
#depth = exp(2.*true_params[4])*(1.-u1*x-u2*x^2)/(1.-u1/3.-u2/6.)
#print("Depth [ppt]: ",depth*1e3)
plot(t,true_model)
println("Called transit model")
# Build the true model
#true_model = TransitModel(
#    texp,
#    0.0,
#    np.log(8.0),    # period
#    np.log(0.015),  # Rp / Rs
#    np.log(0.5),    # duration
#    0.0,            # t_0
#    0.5,            # impact
#    0.5,            # q_1
#    0.5,            # q_2
#)
#true_params = np.array(true_model.get_parameter_vector())

# Inject the transit into the data
true_transit = 1e-3*true_model + 1.0
y = y.*true_transit
println("Range of y: ",minimum(y)," ",maximum(y))
# Normalize the data
med = median(y)
y = (y./ med - 1.0).* 1e3
yerr *= 1e3 / med

read(STDIN,Char)
# Set up the GP model
#mean = TransitModel(
#    texp,
#    0.0,
#    np.log(8.0),
#    np.log(0.015),
#    np.log(0.5),
#    0.0,
#    0.5,
#    0.5,
#    0.5,
#    bounds=[
#        (-0.5, 0.5),
#        np.log([7.9, 8.1]),
#        (np.log(0.005), np.log(0.1)),
#        (np.log(0.4), np.log(0.6)),
#        (-0.1, 0.1),
#        (0, 1.0), (1e-5, 1-1e-5), (1e-5, 1-1e-5)
#    ]
#)
var = std(y)^2
pname = ["mean flux","log(period [d])","log(R_p/R_*)","log(T [d])","t_0 [d]","b","q1","q2","log(sig^2)","log(amplitude)","log(tau)","log(Pstar)","log(f)"]
gpp = [2.*log(minimum(yerr)*0.5),log(var),log(0.5*maximum(t)),log(4.5),0.0]
#minp = [-0.5,log(7.9),log(.005),log(0.4),-.1,0,  1e-5,  1e-5, log(var*0.01), log(var*0.01), log(dtmax)                ,  -8.0   ]
#maxp = [ 0.5, log(8.1), log(.100), log(0.6), .1, 1.0, 1-1e-5, 1-1e-5, log(var*100.), log(var*100.), log(maximum(t)-minimum(t)), log(5.0)]
lower = [-0.5, log(7.9), log(.005), log(0.4),-.1, 0.0,   1e-5,   1e-5, -12.0, log(var*0.01), log(dtmax)                ,               3.0*log(texp),   -8.0  ]
upper = [ 0.5, log(8.1), log(.100), log(0.6), .1, 1.0, 1-1e-5, 1-1e-5,   2.0, log(var*100.), log(maximum(t)-minimum(t)), 0.5*(maximum(t)-minimum(t)), log(5.0)]
sigma = [1e-4, 1e-4, 1e-3, 1e-3, 1e-3, 0.1, 0.1, 0.1, 0.01, 0.01, 0.1, 0.1, 0.1]

# To do:
# 1).  Add in bounds on parameters. [x]
# 2).  Write a function that calls transit calculation & calls likelihood computation. [ ]
# 3).  Compute the mean GP "prediction". [ ]
# 4).  Run MCMC. [ ]
# 5).  Make plots of lightcurve & results. [ ]

# Likelihood function

# Define width, nex.
p0 = 1
p = 2
m1 = 2(p-p0)+p0+2
width = 2m1+1
nex = (4(p-p0)+2p0+1)*(N-1)+1
aex = zeros(width,nex)
al_small= zeros(m1,nex)
indx = collect(1:nex)
bex = zeros(nex)

param = [true_params;gpp]
println("Initial parameters: ",param)
println("Lower bounds:  ",lower)
println("Upper bounds:  ",upper)

function neg_log_like(param)
# Transiting planet parameters:
ptrans = param[1:8]
# Compute the transit model:
trans_model = transit_model_sampled(t,ptrans)
# Gaussian process rotation kernel parameters:
gpp = param[9:13]
alpha_real = zeros(p)
alpha_imag = zeros(p)
beta_real = zeros(p)
beta_imag = zeros(p)
# Convert from Rotation kernel parameters to celerite kernel parameters:
f = exp(gpp[5])
# Define alpha_real, alpha_imag, beta_real, beta_imag
alpha_real[1] = exp(gpp[2])*(1.+f)/(2.+f)
alpha_real[2] = exp(gpp[2])/(2.+f)
beta_real[1] = exp(-gpp[3])
beta_real[2] = exp(-gpp[3])
beta_imag[2] = 2pi*exp(-gpp[4])
# White noise component:
#w0 = zeros(N)+exp(gpp[1])
w0 = yerr.^2+exp(gpp[1])
# Compute the banded extended matrix:
logdeta = compile_matrix_symm(alpha_real,alpha_imag,beta_real,beta_imag,w0,t,nex,aex,al_small,indx)
# Subtract the mean before computing the likelihood:
#println("y range: ",minimum(y)," ",maximum(y))
#println("tr mod : ",minimum(trans_model)," ",maximum(trans_model))
resid = y-trans_model
# Use banded LU decomposition to compute the log likelihood:
#println("aex range: ",minimum(aex)," ",maximum(aex))
#println("al range: ",minimum(al_small)," ",maximum(al_small))
#println("indx range: ",minimum(indx)," ",maximum(indx))
for i=1:nex
  bex[i]=0.0
end
log_like = compute_likelihood(p,p0,resid,aex,al_small,indx,logdeta,bex)
#println("log det a: ",logdeta)
#println("bex range: ",minimum(bex)," ",maximum(bex))
#println(param)
#println("-log(like): ",-log_like)
return -log_like
end

# Optimize the likelihood:
tic()
println("Initial log-likelihood: ",neg_log_like(param))
println("Optimizing log likelihood")
xdiff = param
result = optimize(DifferentiableFunction(neg_log_like), xdiff, lower, upper, Fminbox(), optimizer=LBFGS, optimizer_o= Optim.Options(autodiff = true))
#result = optimize(DifferentiableFunction(neg_log_like), xdiff, lower, upper, Fminbox())
#result = optimize(neg_log_like, xdiff)

toq()

#kernel = RotationTerm(
#    np.log(np.var(y)), np.log(0.5*t.max()), np.log(4.5), 0.0,
#    bounds=[
#        np.log(np.var(y) * np.array([0.01, 100])),
#        np.log([np.max(np.diff(t)), (t.max() - t.min())]),
#        np.log([3*np.median(np.diff(t)), 0.5*(t.max() - t.min())]),
#        [-8.0, np.log(5.0)],
#    ]
#)

#gp = celerite.GP(kernel, mean=mean, fit_mean=True,
#                 log_white_noise=2*np.log(0.5*yerr.min()),
#                 fit_white_noise=True)
#gp.compute(t, yerr)

param = Optim.minimizer(result)

#println("Initial log-likelihood: ",Optim.minimum(result))
println("Initial log-likelihood: ",neg_log_like(param))
#println("Initial log-likelihood: ",neg_log_like(param))
#println(Optim.minimizer(result))

read(STDIN,Char)

# Now, run a markov chain:

include("aff_inv_mcmc.jl")

# Define the model
def neg_log_like(params, y, gp):
    gp.set_parameter_vector(params)
    return -gp.log_likelihood(y)

# Optimize with random restarts
p0 = gp.get_parameter_vector()
bounds = gp.get_parameter_bounds()
r = minimize(neg_log_like, p0, method="L-BFGS-B", bounds=bounds, args=(y, gp))
gp.set_parameter_vector(r.x)
ml_params = np.array(r.x)
print("Maximum log-likelihood: {0}".format(gp.log_likelihood(y)))

# Compute the maximum likelihood predictions
x = np.linspace(t.min(), t.max(), 5000)
trend = gp.predict(y, t, return_cov=False)
trend -= gp.mean.get_value(t) - gp.mean.mean_flux
mu, var = gp.predict(y, x, return_var=True)
std = np.sqrt(var)
mean_mu = gp.mean.get_value(x)
mu -= mean_mu
wn = np.exp(gp.log_white_noise.value)
ml_yerr = np.sqrt(yerr**2 + wn)

# Plot the maximum likelihood predictions
fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, figsize=get_figsize(1, 2))
ax1.errorbar(t - t.min(), y, yerr=ml_yerr, fmt=".k", capsize=0)
ax1.plot(x - t.min(), mu)
ax1.set_ylim(-0.72, 0.72)
ax1.yaxis.set_major_locator(plt.MaxNLocator(5))
ax1.set_ylabel("raw [ppt]")

ax2.errorbar(t - t.min(), y-trend, yerr=ml_yerr, fmt=".k", capsize=0)
ax2.plot(x - t.min(), mean_mu - gp.mean.mean_flux)
ax2.set_xlim(0, t.max()-t.min())
ax2.set_ylim(-0.41, 0.1)
ax2.yaxis.set_major_locator(plt.MaxNLocator(5))
ax2.set_ylabel("de-trended [ppt]")
ax2.set_xlabel("time [days]")
fig.savefig("transit-ml.pdf")

# Save the current state of the GP and data
with open("transit.pkl", "wb") as f:
    pickle.dump((gp, y), f, -1)

if os.path.exists("transit.h5"):
    result = input("MCMC save file exists. Overwrite? (type 'yes'): ")
    if result.lower() != "yes":
        sys.exit(0)

# Do the MCMC
def log_prob(params):
    gp.set_parameter_vector(params)
    lp = gp.log_prior()
    if not np.isfinite(lp):
        return -np.inf
    return gp.log_likelihood(y) + lp

# Initialize
print("Running MCMC sampling...")
ndim = len(ml_params)
nwalkers = 32
pos = ml_params + 1e-5 * np.random.randn(nwalkers, ndim)
lp = np.array(list(map(log_prob, pos)))
m = ~np.isfinite(lp)
while np.any(m):
    pos[m] = ml_params + 1e-5 * np.random.randn(m.sum(), ndim)
    lp[m] = np.array(list(map(log_prob, pos[m])))
    m = ~np.isfinite(lp)

# Sample
sampler = emcee3.Sampler(backend=emcee3.backends.HDFBackend("transit.h5"))
with emcee3.pools.InterruptiblePool() as pool:
    ensemble = emcee3.Ensemble(emcee3.SimpleModel(log_prob), pos, pool=pool)
    sampler.run(ensemble, 15000, progress=True)

# Plot the parameter constraints
samples = np.array(sampler.get_coords(discard=5000, flat=True, thin=13))
samples = samples[:, 1:5]
samples[:, :3] = np.exp(samples[:, :3])
truths = np.array(true_params[1:5])
truths[:3] = np.exp(truths[:3])
fig = corner.corner(samples, truths=truths,
                    labels=[r"period", r"$R_\mathrm{P}/R_\star$", r"duration",
                            r"$t_0$"])
fig.savefig("transit-corner.pdf")

ext: jl


text:
#!/usr/bin/env julia

using Luxor, Colors, Test, Random

Random.seed!(42)

function spirals()
    gsave()
    scale(.3)
    r = 200
    setcolor("gray")
    for i in 0:pi/8:2pi
        gsave()
        translate(r * cos(i), r * sin(i))
        rotate(i)
        julialogo()
        grestore()
    end
    grestore()
    juliacircles(20)
end

function expandingspirals()
    gsave()
    scale(.3)
    r = 200
    for i in pi:pi/12:6pi
        gsave()
        translate(i/3 * r * cos(i), i/3 * r * sin(i))
        scale(0.8)
        rotate(i)
        julialogo()
        grestore()
    end
    grestore()
end

function dropshadow()
    steps=20
    # white-gray ramp
    gramp = range(colorant"white", stop=colorant"gray60", length=steps)
    gsave()
    r = 200
    sethue("purple")
    rect(O, 5, 10, :stroke)
    setopacity(0.1)
    for i in 1:steps
        translate(-0.6, -0.5)
        julialogo(bodycolor=gramp[i], color=false)
    end
    julialogo()
    grestore()
end

function colorgrid()
    #cols = colormap("RdBu", 5; mid=0.5, logscale=false)
    #cols = sequential_palette(rand(10:360), 5, b=0.1)
    cols = distinguishable_colors(25)
    gsave()

    pagetiles = Tiler(500, 400, 5, 5)
    for (pos, n) in pagetiles
      gsave()
      setcolor(color(cols[n]))
      translate(pos)
      scale(0.3)
      julialogo(color=false)
      grestore()
    end
    grestore()
end

function boxes_and_rectangles(pt::Point)
    for i in 1:20
        randomhue()
        poly(box(pt + i, 10i, 10i, vertices=true), :stroke, close=true)
    end
    for i in 40:10:150
        randomhue()
        translate(i, 0)
        poly(squircle(O, 30, 30, vertices=true), :stroke)
    end
end

function draw_julia_logos(fname)
    Drawing(1600, 1600, fname)
    origin()
    background("white")

    translate(-500, -200)
    spirals()

    translate(750, 0)
    expandingspirals()

    translate(-1000, 500)
    dropshadow()

    translate(800, 50)
    colorgrid()

    translate(-700, 300)
    boxes_and_rectangles(O)

    @test finish() == true
    println("...finished test: output in $(fname)")
end
draw_julia_logos("julia-logo-draw.png")

# requires Luxor >= 2.0
function julialogodims(fname)
      Drawing(1600, 1600, fname)
      origin()
      background("white")
      sethue("black")
      julialogo(action=:path, centered=true)
      p = pathtopoly()
      lox, hix = extrema(first.(collect(Iterators.flatten(p))))
      loy, hiy = extrema(getfield.(collect(Iterators.flatten(p)), :y))
      bbx  = BoundingBox(Point(lox, loy), Point(hix, hiy))
      sethue("grey58")
      box(bbx, :stroke)
      rule(boxmiddlecenter(bbx), boundingbox=bbx)
      rule(boxmiddlecenter(bbx), π/2, boundingbox=bbx)
      dimension(boxtopleft(bbx),
         format = (d) -> string(round(d)),
         boxtopright(bbx),
         offset=-50,
         textgap=0,
         textrotation=-π/2,
         texthorizontaloffset=20)
      dimension(boxtopleft(bbx),
         format = (d) -> string(round(d)),
         boxbottomleft(bbx),
         textrotation=π,
         offset=30,
         texthorizontaloffset=20)
         julialogo(centered=true)
      @test finish() == true
      println("...finished test: output in $(fname)")
    end

julialogodims("julia-logo-dims.png")


text:
function issingular_convert!(A)
    rows, columns = size(A)
    for k in 1:columns
        imax = findMaxAbsInColumn(A, k)
        column_to_zeroes!(A, k, imax)
        if A[k, k] == 0
            return false
        end
    end
    return true
end

function det(A)
    isntDegenerate = issingular_convert!(A)
    if isntDegenerate == false
        return eltype(A)(0)
    else
        det = eltype(A)(1)
        for i in 1:lastindex(A, 1)
            det *= A[i, i]
        end
        return det
    end
end


text:
@testset ExtendedTestSet "checkerboard" begin
    @testset ExtendedTestSet "checkerboard" begin
        answer = [
            0.0 0.0 0.0 0.0 0.0
            0.0 0.3454915028125263 0.5590169943749475 0.5590169943749475 0.3454915028125263
            0.0 0.5590169943749475 0.9045084971874736 0.9045084971874736 0.5590169943749475
            0.0 0.5590169943749475 0.9045084971874736 0.9045084971874736 0.5590169943749475
            0.0 0.3454915028125263 0.5590169943749475 0.5590169943749475 0.3454915028125263
        ]
        test = checkerboard((5, 5))
        @test test ≈ answer
    end
end

@testset ExtendedTestSet "disk" begin
    @testset ExtendedTestSet "disk" begin
        answer = [
            0.2928932188134524 0.5 0.2928932188134524 -0.1180339887498949 -0.5811388300841898
            0.5 1.0 0.5 0.0 -0.5
            0.2928932188134524 0.5 0.2928932188134524 -0.1180339887498949 -0.5811388300841898
            -0.1180339887498949 0.0 -0.1180339887498949 -0.41421356237309515 -0.8027756377319946
            -0.5811388300841898 -0.5 -0.5811388300841898 -0.8027756377319946 -1.1213203435596424
        ]
        test = disk((5, 5); factor=1)
        @test test ≈ answer
    end

    @testset ExtendedTestSet "disk" begin
        answer = [
            -0.41421356237309515 0.0 -0.41421356237309515 -1.2360679774997898 -2.1622776601683795
            0.0 1.0 0.0 -1.0 -2.0
            -0.41421356237309515 0.0 -0.41421356237309515 -1.2360679774997898 -2.1622776601683795
            -1.2360679774997898 -1.0 -1.2360679774997898 -1.8284271247461903 -2.605551275463989
            -2.1622776601683795 -2.0 -2.1622776601683795 -2.605551275463989 -3.2426406871192848
        ]
        test = disk((5, 5); factor=2)
        @test test ≈ answer
    end
end


text:
mutable struct MobiusTransform{T <: Real} <: AbstractConformalTransform
    a::Complex{T}
    b::Complex{T}
    c::Complex{T}
    d::Complex{T}
end

function addequals(mobius::MobiusTransform{T}, sv::SArray{Tuple{4},Complex{Float64},1,4}) where {T <: Real}
    mobius.a += sv[1]
    mobius.b += sv[2]
    mobius.c += sv[3]
    mobius.d += sv[4]
    mobius
end

function identity_mobius()
    MobiusTransform{Float64}(1, 0, 0, 1)
end

@inline function transform(mobius::MobiusTransform{T}, point::Complex{T})::Complex{T} where {T <: Real}
    (point * mobius.a + mobius.b) / (point * mobius.c + mobius.d)
end

@inline function inversetransform(mobius::MobiusTransform{T}, point::Complex{T})::Complex{T} where {T <: Real}
    (point * mobius.d - mobius.b) / (-point * mobius.c + mobius.a)
end

struct ComplexRational{T <: Real, N} <: AbstractConformalTransform
    numerator::SArray{Tuple{N},Complex{T},1,N}
    denominator::SArray{Tuple{N},Complex{T},1,N}
end

function identity_rational()
    num = @SVector ComplexF64[0, 1]
    den = @SVector ComplexF64[1, 0]
    ComplexRational{Float64, 2}(num, den)
end

function basic_rational()
    num = @SVector ComplexF64[0, 1, 1 + 0.1im, 0.1im]
    den = @SVector ComplexF64[1, 0.1 - 0.1im, 0.2, 0.01]
    ComplexRational(num, den)
end

function basic_rational(n)
    num = @SVector ComplexF64[0:n]
    den = @SVector ComplexF64[1, 0.1 - 0.1im, 0.2, 0.01]
    ComplexRational(num, den)
end

function addequals(rational::ComplexRational{T, N}, num::SArray{Tuple{N},Complex{T},1,N}, den::SArray{Tuple{N},Complex{T},1,N}) where {T <: Real, N}
    mobius.a += sv[1]
    mobius.b += sv[2]
    mobius.c += sv[3]
    mobius.d += sv[4]
    mobius
end

@inline function transform(rational::ComplexRational{T, N}, point::Complex{T})::Complex{T} where {T <: Real, N}
    num = evalpoly(point, rational.numerator)
    den = evalpoly(point, rational.denominator)
    num / den
end

@inline function inversetransform(rational::ComplexRational{T, N}, point::Complex{T}, preimage_start::Complex{T})::Complex{T} where {T <: Real, N}
    # need to do the math in vector-of-real space instead of complex space for Optim's sake
    preimage_arr = [real(preimage_start), imag(preimage_start)]
    distinvfunc = preimage -> complexdistsq(transform(rational, Complex(preimage[1], preimage[2])), point)
    graddistinv = preimage -> gradient(distinvfunc, preimage)[1]
    optim_results = optimize(distinvfunc, graddistinv, preimage_arr, LBFGS(); inplace=false)
    preimage_final_complex = Complex(Optim.minimizer(optim_results)...)
end

max_stars_repo_name: zoemcc/fractrixzeta

max_issues_repo_name: zoemcc/fractrixzeta

max_forks_repo_name: zoemcc/fractrixzeta


text:
version = v"6.2.0"

include("../common.jl")

# Build the tarballs
build_tarballs(ARGS, configure(version)...;
               preferred_gcc_version=v"6", julia_compat="1.6")

max_stars_repo_name: waralex/Yggdrasil

max_issues_repo_name: waralex/Yggdrasil

max_forks_repo_name: waralex/Yggdrasil


text:
"""
            Functions to write snapshots.

    Author: Ludwig Böss
    Contact: lboess@usm.lmu.de
    Created: 2018-12-12

"""

function write_format2_block_header(f::IOStream, blockname::String)

    # fill blockname to 4 characters
    if length(blockname) < 4
        padding = 4 - length(blockname)
        for i=1:padding
            blockname = blockname * " "
        end
    end

    # transform the name into an array of charcters.
    # Since Julia uses 2 byte chars and C uses 1 byte I have to take
    # a different approach and use Int8s.
    write_name =  Int8.(collect(blockname))

    @info "Writing block: $blockname"

    # write blocksite (8 bytes)
    write(f, UInt32(8))

    # write block name
    write(f, write_name)

    return f
end

"""
    write_block(f::IOStream, data,
                blockname::String="";
                snap_format::Integer=2)

Write `data` to a block to an opened file `f`.
"""
function write_block(f::IOStream, data,
                     blockname::String="";
                     snap_format::Integer=2)

    # get total number of particles to write
    N = size(data, ndims(data))

    # write blocksize
    dtype = typeof(data[1,1])
    dims = ndims(data)
    # for a Matrix the real dimension to write is the column length
    if dims == 2
        dims = size(data,1)
    end

    blocksize_test = N * sizeof(dtype) * dims

    # check for integer overflow
    if blocksize_test <= typemax(UInt32)
        blocksize = UInt32(blocksize_test)
    else
        # avoid integer overflow
        blocksize = UInt32(blocksize_test - 4294967296)
    end

    if snap_format == 2

        # break if blockname not specified
        if blockname == ""
            error("Please specify blockname!")
        end

        # write header
        f = write_format2_block_header(f, blockname)

        # write end if name header, namely:
        # size to skip from directly after the block name and size of
        # the format 2 block header
        write(f, UInt32(blocksize + UInt32(8)))
        write(f, UInt32(8))
    end

    # write blocksize
    write(f, blocksize)

    # write the block
    write(f, data)

    @info "Writing block done."

    write(f, blocksize)
end

"""
    write_header(f::IOStream, h::SnapshotHeader; snap_format::Integer=2)

Writes the header block to an opened file `f`.
"""
function write_header(f::IOStream, h::SnapshotHeader; snap_format::Integer=2)

    if snap_format == 2
        f = write_format2_block_header(f, "HEAD")
        write(f, UInt32(264))
        write(f, UInt32(8))
    end

    # write blocksize
    write(f, UInt32(256))

    # write header to file
    for fields in fieldnames(SnapshotHeader)
        write(f, getfield(h, fields))
    end

    # write blocksize
    write(f, UInt32(256))
end

"""
    convert_string_to_int8(name::String)

Converts a string to an array of Int8 to write to file.
"""
convert_string_to_int8(name::String) = [Int8(Char(name[i])) for i = 1:length(name)]

"""
    function get_datatype_name(dt::DataType, dim::Integer)

Convert the datatype into a string and then to a vector of 8bit integers to match name in Gadget.
"""
function get_datatype_name(dt::DataType, dim::Int32)

    # convert datatype into string
    if dt == Float32
        name = "FLOAT"
    elseif dt == Float64
        name = "DOUBLE"
    elseif dt == UInt32
        name = "LONG"
    elseif dt == UInt64
        name = "LLONG"
    end

    # add N if 3D
    if dim == 3
        name *= "N"
    end

    # pad to 8 characters
    for _ = length(name):7
        name *= " "
    end

    # return the datatype string as 8bit integers
    return convert_string_to_int8(name)
end

"""
    get_int8_blockname(info::InfoLine)

Pad the stored block name with spaces and convert to Array of Int8.
"""
function get_int8_blockname(info_line::InfoLine)

    block_name = info_line.block_name

    # pad block name with spaces
    while length(block_name) < 4
        block_name *= " "
    end

    return convert_string_to_int8(block_name)
end

"""
    write_info_block(f::IOStream, info::Vector{InfoLine}; snap_format::Integer=2)

Writes the info block to an opened file `f`.
"""
function write_info_block(f::IOStream, info::Vector{InfoLine}; snap_format::Integer=2)

    # every info line takes up 40 bits
    blocksize = UInt32(40 * length(info) )

    if snap_format == 2
        f = write_format2_block_header(f, "INFO")
        write(f, UInt32(blocksize+8))
        write(f, UInt32(8))
    end

    write(f, UInt32(blocksize))

    for i = 1:length(info)

        # get the block name in the correct format
        block_name = get_int8_blockname( info[i] )

        # get the datatype name in the correct format
        datatype_name = get_datatype_name( info[i].data_type, info[i].n_dim )

        # write the data
        write(f, block_name)
        write(f, datatype_name)
        write(f, info[i].n_dim)
        write(f, info[i].is_present)

    end

    write(f, UInt32(blocksize))
end


text:
function get_init_values_for_comparison(sim::Simulation)
    bus_size = LITS.get_bus_count(sim.system)
    V_R = Vector{Float64}(undef, bus_size)
    V_I = Vector{Float64}(undef, bus_size)
    Vm = Vector{Float64}(undef, bus_size)
    θ = Vector{Float64}(undef, bus_size)
    for bus in PSY.get_components(PSY.Bus, sim.system)
        bus_n = PSY.get_number(bus)
        bus_ix = PSY.get_ext(sim.system)[LITS.LOOKUP][bus_n]
        V_R[bus_ix] = sim.x0_init[bus_ix]
        V_I[bus_ix] = sim.x0_init[bus_ix + bus_size]
        Vm[bus_ix] = sqrt(V_R[bus_ix]^2 + V_I[bus_ix]^2)
        θ[bus_ix] = angle(V_R[bus_ix] + V_I[bus_ix] * 1im)
    end
    results =
        Dict{String, Vector{Float64}}("V_R" => V_R, "V_I" => V_I, "Vm" => Vm, "θ" => θ)
    for device in PSY.get_components(PSY.DynamicInjection, sim.system)
        states = PSY.get_states(device)
        name = PSY.get_name(device)
        global_index = PSY.get_ext(sim.system)[LITS.GLOBAL_INDEX][name]
        x0_device = Vector{Float64}(undef, length(states))
        for (i, s) in enumerate(states)
            x0_device[i] = sim.x0_init[global_index[s]]
        end
        results[name] = x0_device
    end
    dyn_branches = PSY.get_components(PSY.DynamicBranch, sim.system)
    if !isempty(dyn_branches)
        for br in dyn_branches
            states = PSY.get_states(br)
            name = PSY.get_name(br)
            global_index = PSY.get_ext(sim.system)[LITS.GLOBAL_INDEX][name]
            x0_br = Vector{Float64}(undef, length(states))
            for (i, s) in enumerate(states)
                x0_br[i] = sim.x0_init[global_index[s]]
            end
            printed_name = "Line " * name
            results[printed_name] = x0_br
        end
    end
    return results
end


text:
"""
    predict_incidence_and_prev(;pred_incidence::Vector{Float64},
                                        pred_hospitalisations::Vector{Float64},
                                        pred_deaths::Vector{Float64},
										symptomaticrate::Float64,
										prop_critical::Float64,
										p_IS::Vector{Float64},
										Q_R::Vector{Float64},
                                        Q_ICUH::Vector{Float64},
                                        Q_HR::Vector{Float64},
                                        Q_ICUR::Vector{Float64},
										F_R::Vector{Float64})

Augment a prediction of incidence of infection, hospitalisation and death in an area with predictions of symptomatic/asymptomatic incidence, critical care (ICU) incidence

                                        # Arguments
- `pred_incidence::Vector{Float64}`: Daily predictions of new infections
- `pred_hospitalisations::Vector{Float64}`: Daily predictions of new hospitalisations.
- `pred_deaths::Vector{Float64}`: Daily predictions of new deaths.
- `symptomaticrate::Float64`: Broad population symptomatic rate.
- `prop_critical::Float64`: Proportion of hospitalised cases that require ICU treatment
- `p_IS::Vector{Float64}`: Distribution of days between infection and symptoms (for symptomatic cases).
- `Q_R::Vector{Float64}`: Upper tail function for days between infection and recovery
- `Q_ICUH::Vector{Float64}`: Upper tail function for days between arriving in ICU, surviving, and returning to less specialist wards
- `Q_HR::Vector{Float64}`: Upper tail function for days between arriving at hospital, remaining severe but not critical and then getting discharged
- `Q_ICUR::Vector{Float64}`: Upper tail function for days between arriving in ICU, surviving, returning to less specialist wards and then discharge
- `F_R::Vector{Float64}`: Distribution function for days until recovery from infection
"""
function predict_incidence_and_prev(;pred_incidence::Vector{Float64},
                                        pred_hospitalisations::Vector{Float64},
                                        pred_deaths::Vector{Float64},
										symptomaticrate::Float64,
										prop_critical::Float64,
										p_IS::Vector{Float64},
										Q_R::Vector{Float64},
                                        Q_ICUH::Vector{Float64},
                                        Q_HR::Vector{Float64},
                                        Q_ICUR::Vector{Float64},
										F_R::Vector{Float64})
	asymp_incidence = (1 - symptomaticrate) * simple_conv(pred_incidence, p_IS)
	symp_incidence = symptomaticrate * simple_conv(pred_incidence, p_IS)
	severe_incidence = (1 - prop_critical) * pred_hospitalisations
	crit_incidence = prop_critical * pred_hospitalisations
	death_incidence = pred_deaths
	asymp_prev = simple_conv(asymp_incidence, Q_R)
	critical_prev = simple_conv(crit_incidence, Q_ICUH)
	severe_prev = simple_conv(severe_incidence, Q_HR) .+ simple_conv(crit_incidence, Q_ICUR) .- critical_prev
	mild_prev = simple_conv(symp_incidence, Q_R) .- severe_prev .- critical_prev
	recovered_prev = simple_conv(asymp_incidence .+ symp_incidence, F_R)
	return (asymp_incidence = asymp_incidence,
            symp_incidence = symp_incidence,
            severe_incidence = severe_incidence,
            crit_incidence = crit_incidence,
            death_incidence = death_incidence,
            asymp_prev = asymp_prev,
            critical_prev = critical_prev,
            severe_prev = severe_prev,
            mild_prev = mild_prev,
            recovered_prev = recovered_prev)
end

"""
    predict_incidence_and_prev(modelfit;
                                    pred_incidence::Vector{Float64},
                                    pred_hospitalisations::Vector{Float64},
                                    pred_deaths::Vector{Float64},
                                    symptomaticrate::Float64,
                                    prop_critical::Float64,
                                    p_IS::Vector{Float64},
                                    Q_R::Vector{Float64},
                                    Q_ICUH::Vector{Float64},
                                    Q_HR::Vector{Float64},
                                    Q_ICUR::Vector{Float64},
                                    F_R::Vector{Float64})

Convert a collected modelfit element into a hospitalisation prediction
"""
function predict_incidence_and_prev(modelfit;
                                    symptomaticrate::Float64,
                                    prop_critical::Float64,
                                    p_IS::Vector{Float64},
                                    Q_R::Vector{Float64},
                                    Q_ICUH::Vector{Float64},
                                    Q_HR::Vector{Float64},
                                    Q_ICUR::Vector{Float64},
                                    F_R::Vector{Float64})
	incidence = modelfit.mean_pred_incidence
	hospitalisations = modelfit.pred_hosps_ftc
	deaths = modelfit.pred_deaths_ftc
    name = modelfit.area
    prediction = predict_incidence_and_prev(pred_incidence=incidence,
                                        pred_hospitalisations=hospitalisations,
                                        pred_deaths=deaths,
                                        symptomaticrate=symptomaticrate,
                                        prop_critical=prop_critical,
                                        p_IS=p_IS,
                                        Q_R=Q_R,
                                        Q_ICUH=Q_ICUH,
                                        Q_HR=Q_HR,
                                        Q_ICUR=Q_ICUR,
                                        F_R=F_R)
	return prediction, name
end

"""
    predict_incidence_and_prev(incidence_array,p_IH,p_ID,days;
                                    symptomaticrate::Float64,
                                    prop_critical::Float64,
                                    p_IS::Vector{Float64},
                                    Q_R::Vector{Float64},
                                    Q_ICUH::Vector{Float64},
                                    Q_HR::Vector{Float64},
                                    Q_ICUR::Vector{Float64},
                                    F_R::Vector{Float64})

Apply outcome predictions to each of a set of posterior draws for the incidence curves.
"""
function predict_incidence_and_prev(incidence_array,p_IH,p_ID,days;
                                    symptomaticrate::Float64,
                                    prop_critical::Float64,
                                    p_IS::Vector{Float64},
                                    Q_R::Vector{Float64},
                                    Q_ICUH::Vector{Float64},
                                    Q_HR::Vector{Float64},
                                    Q_ICUR::Vector{Float64},
                                    F_R::Vector{Float64})
        asymp_incidence = zeros(days,size(incidence_array,2))
        symp_incidence = similar(asymp_incidence)
        severe_incidence =similar(asymp_incidence)
        crit_incidence = similar(asymp_incidence)
        death_incidence = similar(asymp_incidence)
        asymp_prev = similar(asymp_incidence)
        critical_prev = similar(asymp_incidence)
        severe_prev = similar(asymp_incidence)
        mild_prev = similar(asymp_incidence)
        recovered_prev = similar(asymp_incidence)
        for k = 1:size(incidence_array,2)
                incidence = incidence_array[:,k]
                hospitalisations = KenyaSerology.simple_conv(incidence,0.001*p_IH)
                deaths = KenyaSerology.simple_conv(incidence,0.001*p_ID)
                prediction = KenyaSerology.predict_incidence_and_prev(pred_incidence=incidence,
                                        pred_hospitalisations=hospitalisations,
                                        pred_deaths=deaths,
                                        symptomaticrate=symptomaticrate,
                                        prop_critical=prop_critical,
                                        p_IS=p_IS,
                                        Q_R=Q_R,
                                        Q_ICUH=Q_ICUH,
                                        Q_HR=Q_HR,
                                        Q_ICUR=Q_ICUR,
                                        F_R=F_R)
                asymp_incidence[:,k] = prediction.asymp_incidence
                symp_incidence[:,k]  = prediction.symp_incidence
                severe_incidence[:,k]  = prediction.severe_incidence
                crit_incidence[:,k]  = prediction.crit_incidence
                death_incidence[:,k]  = prediction.death_incidence
                asymp_prev[:,k]  = prediction.asymp_prev
                critical_prev[:,k]  = prediction.critical_prev
                severe_prev[:,k]  = prediction.severe_prev
                mild_prev[:,k]  = prediction.mild_prev
                recovered_prev[:,k]  = prediction.recovered_prev
        end
        return (asymp_incidence = asymp_incidence,
            symp_incidence = symp_incidence,
            severe_incidence = severe_incidence,
            crit_incidence = crit_incidence,
            death_incidence = death_incidence,
            asymp_prev = asymp_prev,
            critical_prev = critical_prev,
            severe_prev = severe_prev,
            mild_prev = mild_prev,
            recovered_prev = recovered_prev)
end

"""
	predict_incidence_and_prev(model::KenyaSerology.CoVAreaModel;
                                    proj_date::Date,
                                    cum_deaths::Integer,cum_deaths_date::Date,
                                    cum_hosps::Integer,cum_hosps_date::Date,
                                    symptomaticrate::Float64,
                                    prop_critical::Float64,
                                    p_IH,p_ID,
                                    d_incubation = LogNormal(1.644,0.363),#Lauer estimate
                                    d_duration_in_hosp = Weibull(1.572,17.819),#Haw et al
                                    d_ICUstay = Gamma(2.66,3.42),#Fit to IQR
                                    d_recovery = Exponential(2.4))

Output projections for relevant outcomes from a `KenyaSerology.CoVAreaModel` object.
"""
function predict_incidence_and_prev(model::KenyaSerology.CoVAreaModel;
                                    proj_date::Date,
                                    cum_deaths::Integer,cum_deaths_date::Date,
                                    cum_hosps::Integer,cum_hosps_date::Date,
                                    symptomaticrate::Float64,
                                    prop_critical::Float64,
                                    p_IH,p_ID,
                                    d_incubation = LogNormal(1.644,0.363),#Lauer estimate
                                    d_duration_in_hosp = Weibull(1.572,17.819),#Haw et al
                                    d_ICUstay = Gamma(2.66,3.42),#Fit to IQR
                                    d_recovery = Exponential(2.4))
    #Calculate lag Distributions
    #lag distributions
    p_IS = [cdf(d_incubation,t) - cdf(d_incubation,t-1) for t = 1:100]#infection to symptoms
    p_ICU = [cdf(d_ICUstay,t) - cdf(d_ICUstay,t-1) for t = 1:100]#ICU to leave ICU
    p_HR = [cdf(d_duration_in_hosp,t) - cdf(d_duration_in_hosp,t-1) for t = 1:100]#Hospital to discharge
    p_ICUR = KenyaSerology.simple_conv(p_ICU,p_HR)#ICU to discharge assuming its the sum of the two
    p_SH = [0.2 for t = 1:5] #Moghadas et al uniform 1-5 day estimate
    p_R = [cdf(d_recovery,t) - cdf(d_recovery,t-1) for t = 1:1000]
    #Upper tail functions
    Q_HR = vcat([1.],[1 - cumsum(p_HR)[t] for t = 1:100])
    Q_ICUH = vcat([1.],[1 - cumsum(p_ICU)[t] for t = 1:100])
    Q_ICUR = vcat([1.],[1 - cumsum(p_ICUR)[t] for t = 1:100])
    Q_R = vcat([1.],[1 - cumsum(p_R)[t] for t = 1:1000])
    F_R = 1 .- Q_R
    #Calculate fitted posterior mean daily incidence
    inc = KenyaSerology.incidence_across_samples(model,(proj_date-Date(2020,2,20)).value)
    incidence = KenyaSerology.create_credible_intervals(inc.true_incidence).mean_pred
    #Calculate unnormalised hosp and death prediction
    hospitalisations = KenyaSerology.simple_conv(incidence,p_IH)
    deaths = KenyaSerology.simple_conv(incidence,p_ID)
    #Calculate crude probability of hosp and death
    prob_hosp = cum_hosps/sum(hospitalisations[1:(cum_hosps_date - Date(2020,2,20)).value])
    prob_deaths = cum_deaths/sum(deaths[1:(cum_deaths_date - Date(2020,2,20)).value])

    hospitalisations .= prob_hosp.*hospitalisations
	deaths .= prob_deaths.*deaths
    name = model.areaname
    prediction = KenyaSerology.predict_incidence_and_prev(pred_incidence=incidence,
                                        pred_hospitalisations=hospitalisations,
                                        pred_deaths=deaths,
                                        symptomaticrate=symptomaticrate,
                                        prop_critical=prop_critical,
                                        p_IS=p_IS,
                                        Q_R=Q_R,
                                        Q_ICUH=Q_ICUH,
                                        Q_HR=Q_HR,
                                        Q_ICUR=Q_ICUR,
                                        F_R=F_R)
	return prediction, name
end

function predict_incidence_and_prev(incidence::Vector;
                                    proj_date::Date,
                                    cum_deaths::Integer,cum_deaths_date::Date,
                                    cum_hosps::Integer,cum_hosps_date::Date,
                                    symptomaticrate::Float64,
                                    prop_critical::Float64,
                                    p_IH,p_ID,
                                    d_incubation = LogNormal(1.644,0.363),#Lauer estimate
                                    d_duration_in_hosp = Weibull(1.572,17.819),#Haw et al
                                    d_ICUstay = Gamma(2.66,3.42),#Fit to IQR
                                    d_recovery = Exponential(2.4))
    #Calculate lag Distributions
    #lag distributions
    p_IS = [cdf(d_incubation,t) - cdf(d_incubation,t-1) for t = 1:100]#infection to symptoms
    p_ICU = [cdf(d_ICUstay,t) - cdf(d_ICUstay,t-1) for t = 1:100]#ICU to leave ICU
    p_HR = [cdf(d_duration_in_hosp,t) - cdf(d_duration_in_hosp,t-1) for t = 1:100]#Hospital to discharge
    p_ICUR = KenyaSerology.simple_conv(p_ICU,p_HR)#ICU to discharge assuming its the sum of the two
    p_SH = [0.2 for t = 1:5] #Moghadas et al uniform 1-5 day estimate
    p_R = [cdf(d_recovery,t) - cdf(d_recovery,t-1) for t = 1:1000]
    #Upper tail functions
    Q_HR = vcat([1.],[1 - cumsum(p_HR)[t] for t = 1:100])
    Q_ICUH = vcat([1.],[1 - cumsum(p_ICU)[t] for t = 1:100])
    Q_ICUR = vcat([1.],[1 - cumsum(p_ICUR)[t] for t = 1:100])
    Q_R = vcat([1.],[1 - cumsum(p_R)[t] for t = 1:1000])
    F_R = 1 .- Q_R

    #Calculate unnormalised hosp and death prediction
    hospitalisations = KenyaSerology.simple_conv(incidence,p_IH)
    deaths = KenyaSerology.simple_conv(incidence,p_ID)
    #Calculate crude probability of hosp and death
    prob_hosp = cum_hosps/sum(hospitalisations[1:(cum_hosps_date - Date(2020,2,20)).value])
    prob_deaths = cum_deaths/sum(deaths[1:(cum_deaths_date - Date(2020,2,20)).value])

    hospitalisations .= prob_hosp.*hospitalisations
	deaths .= prob_deaths.*deaths
    prediction = KenyaSerology.predict_incidence_and_prev(pred_incidence=incidence,
                                        pred_hospitalisations=hospitalisations,
                                        pred_deaths=deaths,
                                        symptomaticrate=symptomaticrate,
                                        prop_critical=prop_critical,
                                        p_IS=p_IS,
                                        Q_R=Q_R,
                                        Q_ICUH=Q_ICUH,
                                        Q_HR=Q_HR,
                                        Q_ICUR=Q_ICUR,
                                        F_R=F_R)
	return prediction
end


text:
using Transpilers
using Test

@testset "Transpilers.jl" begin
    # Write your tests here.
end


text:
module GNSSSignals

    using
        DocStringExtensions,
        LoopVectorization,
        StructArrays,
        Statistics,
        FixedPointSinCosApproximations

    using Unitful: Hz

    export
        AbstractGNSSSystem,
        GPSL1,
        GPSL5,
        GalileoE1B,
        get_codes,
        get_code_length,
        get_secondary_code_length,
        get_center_frequency,
        get_code_frequency,
        get_code_unsafe,
        get_code,
        get_data_frequency,
        get_code_center_frequency_ratio,
        get_carrier_fast_unsafe,
        get_carrier_vfast_unsafe,
        get_quadrant_size_power,
        get_carrier_amplitude_power,
        fpcarrier_phases!,
        fpcarrier!,
        min_bits_for_code_length

    abstract type AbstractGNSSSystem end

    struct GPSL1 <: AbstractGNSSSystem end

    struct GPSL5 <: AbstractGNSSSystem end

    struct GalileoE1B <: AbstractGNSSSystem end

    """
    $(SIGNATURES)

    Reads Int8 encoded codes from a file with filename `filename` (including the path). The
    code length must be provided by `code_length` and the number of PRNs by `num_prns`.
    # Examples
    ```julia-repl
    julia> read_in_codes("/data/gpsl1codes.bin", 32, 1023)
    ```
    """
    function read_in_codes(filename, num_prns, code_length)
        code_int8 = open(filename) do file_stream
            read!(file_stream, Array{Int8}(undef, code_length, num_prns))
        end
        Int16.(code_int8)
    end

    function extend_front_and_back(codes)
        [codes[end, :]'; codes; codes[1,:]'; codes[2,:]']
    end

    include("gps_l1.jl")
    include("gps_l5.jl")
    include("galileo_e1b.jl")
    include("carrier.jl")
    include("common.jl")
end


text:
using Test
using AtomicFileWrite

mktempdir() do dir; cd(dir) do
    fname = "1"
    e = ArgumentError("msg")

    @test atomic_write(io->print(io,"write"), fname) == nothing
    @test read(fname, String) == "write"
    @test atomic_write(io->print(io,"overwrite"), fname) == nothing
    @test read(fname, String) == "overwrite"

    @test_throws e atomic_write(fname) do io
        println(io, "don't write this")
        throw(e)
    end
    @test read(fname, String) == "overwrite"

    if Sys.iswindows()
        io2 = nothing
        @test_throws Base.IOError atomic_write(fname) do io
            println(io, "don't write that")
            io2 = open(fname)  # On windows, should fail overwriting open file
        end
        @test io2 isa IOStream
        close(io2)
        @test read(fname, String) == "overwrite"
    end

    backup = "$fname.bck"
    @test atomic_write(io->print(io,"overwrite 2"), fname; backup=backup) == nothing
    @test read(fname, String) == "overwrite 2"
    @test read(backup, String) == "overwrite"

    @test_throws ArgumentError atomic_write(io->print(io,"overwrite backup"), fname; backup=backup)
    @test read(fname, String) == "overwrite 2"
    @test read(backup, String) == "overwrite"

    @test atomic_write(io->print(io,"overwrite backup"), fname;
                        backup=backup, overwrite_backup=true) == nothing
    @test read(fname, String) == "overwrite backup"
    @test read(backup, String) == "overwrite 2"
end; end


text:
using Revise
using Test
using MAT
using NNFEM
using PyCall
using PyPlot
using JLD2
using ADCME
using LinearAlgebra

tid = 4
include("Truss_Domain.jl")
idx = 1
nntype = "ae_scaled"
include("nnutil.jl")
testtype = "NeuralNetwork1D"

# kg, m,  ms
# E = 200e9 Pa / 1e6

nnname = "Data/NNLearn_$(nntype)_ite10.mat"
@show nnname
s = ae_to_code(nnname, nntype)
eval(Meta.parse(s))

s_scale = 1e6
prop = Dict("name"=> testtype, "rho"=> 8000.0, "A0"=> 0.005, "nn"=>post_nn)

nodes, EBC, g, gt, FBC, fext, ft, npoints, node_to_point = BoundaryCondition(tid)
elements = []
for i = 1:nx
    elnodes = [i, i+1]; coords = nodes[elnodes,:];
    push!(elements, FiniteStrainTruss(coords,elnodes, prop, ngp))
end

domain = Domain(nodes, elements, ndofs, EBC, g, FBC, fext)
state = zeros(domain.neqs)
∂u = zeros(domain.neqs)
globdat = GlobalData(state,zeros(domain.neqs), zeros(domain.neqs),∂u, domain.neqs, gt, ft)
assembleMassMatrix!(globdat, domain)
# need to update state in domain from globdat
updateStates!(domain, globdat)

SolverInitial!(Δt, globdat, domain)

ω = EigenMode(Δt, globdat, domain)
@show "stable time step is ", 0.8 * 2/ω, " current time step is ", Δt
for i = 1:NT
    @info i, "/" , NT
    solver = ExplicitSolver(Δt, globdat, domain)
    if i%10 == 0
        ω = EigenMode(Δt, globdat, domain)
        @show "stable time step is ", 0.8 * 2/ω, " current time step is ", Δt
    end
end

if !isdir("$(@__DIR__)/Data/")
    mkdir("$(@__DIR__)/Data/")
end

# plot
close("all")
strain = hcat(domain.history["strain"]...)
stress = hcat(domain.history["stress"]...)
sid = 4 #Gaussian point id
plot(strain[sid,:], stress[sid,:]/s_scale)
savefig("Debug/$nntype/strain-stress$(tid).png")

close("all")
ts = LinRange(0,T, NT+1)

ux = hcat(domain.history["state"]...)[1:nx+1, :]
nid = 3 #node id
plot(ts, ux[nid,:])
savefig("Debug/$nntype/disp$(tid).png")

# @save "Data/domain.jld2" domain


text:
"""
    DiffEqLinearOperator(f; isconstant=false) :: DiffEqBase.AbstractDiffEqLinearOperator

A wrapper around a function `f` that acts as a linear operator.

`isconstant=true` if `f` is time-invariant.
"""
struct DiffEqLinearOperator{T,F,isconstant} <: DiffEqBase.AbstractDiffEqLinearOperator{T}
  f::F
end
DiffEqLinearOperator{T}(f; isconstant=false) where {T} = DiffEqLinearOperator{T,typeof(f), isconst}(f)

DiffEqBase.isconstant(::DiffEqLinearOperator{F,isconstant}) where {F,isconstant} = isconstant
(op::DiffEqLinearOperator)(args...) = op.f(args...)

"""
    EulerOperator(op, γ) :: DiffEqBase.AbstractDiffEqLinearOperator

A linear operator which performs an explicit Euler step ``u + α f(u)``

, where `f!` and `op!` both operate inplace, with extra arguments passed
through, i.e.
```
op!(LQ, Q, args...)
```
is equivalent to
```
f!(dQ, Q, args...)
LQ .= Q .+ γ .* dQ
```
"""
mutable struct EulerOperator{T,F,P,tType}
    f::F
    γ::T
    p::P
    t::tType
end

function (op::EulerOperator)(LQ, Q, args...)
    op.f(LQ, Q, args...)
    @. LQ = Q + op.γ * LQ
end
DiffEqBase.isconstant(op::EulerOperator) = op.f isa DiffEqBase.AbstractDiffEqLinearOperator && DiffEqBase.isconstant(op.f)
LinearAlgebra.mul!(Y, op::EulerOperator, X) = op(Y,X,op.p,op.t)


text:
include("sqs_types.jl")
include("sqs_operations.jl")

function is_basic_type(v)
    if  isa(v, AbstractString) || isa(v, Int) || isa(v, Int32) ||
        isa(v, Int64) || isa(v, Float64) || isa(v, Bool) ||
        isa(v, DateTime) || isa(v, Vector{UInt8})

        return true
    end
    return false
end

corrections_map = Dict()

function add_to_params(params, obj, pfx)
    for m in fieldnames(typeof(obj))
        fld_val = getfield(obj, m)
        if (m != :queueUrl && fld_val != nothing)
            fld_name = string(m)
            if haskey(corrections_map, (typebasename(obj), fld_name))
                arg_name = corrections_map[(typebasename(obj), fld_name)]
            elseif endswith(fld_name, "Set")
                arg_name = fld_name[1:end-3]
            else
                arg_name = fld_name
            end

            if startswith(arg_name, "_")
                # handle field names that match julia reserved types....
                arg_name = arg_name[2:end]
            end

            #Captitalize the first letter for the argument.
            arg_name = uppercase(arg_name[1:1]) * arg_name[2:end]

            if is_basic_type(fld_val)
                push!(params, (pfx * arg_name, aws_string(fld_val)))
            elseif isa(fld_val, Array)
                for (idx, fv) in enumerate(fld_val)
                    subarg_name = "$(pfx)$(arg_name).$(idx)"
                    if is_basic_type(fv)
                        push!(params, (subarg_name, aws_string(fv)))
                    else
                        add_to_params(params, fv, subarg_name*".")
                    end
                end
            else
                # compound type
                add_to_params(params, fld_val, "$(pfx)$(arg_name).")
            end
        end
    end
end

function call_sqs(env::AWSEnv, action::AbstractString, msg=nothing, use_post=false)
    ep = nothing
    params = Array(Tuple, 0)
    if (msg != nothing)
        # make sure it is a valid type
        msg_name = typebasename(msg)
        if !haskey(ValidRqstMsgs, msg_name) error("Invalid message for request: $msg_name") end

        add_to_params(params, msg, "")

        # queueUrl becomes the endpoint, not a query parameter
        if in(:queueUrl, fieldnames(msg))
            ep = msg.queueUrl
        end
    end
    sqs_execute(env, action, ep, params, use_post)
end

typebasename(a) = split(string(typeof(a)), ".")[end]


text:
#=
   Provides calc_model_rv(theta, time)
   Computes the velocity of the star due to the perturbations of multiple planets, as the linear superposition of the Keplerian orbit induced by each planet, i.e., neglecting mutual planet-planet interactions
=#

include("kepler_eqn.jl")       # Code to solve Kepler's equation provides calc_ecc_anom(mean_anom, ecc; tol = 1.e-8)

# Calculate Keplerian velocity of star due to one planet (with parameters displaced by offset)
function calc_rv_pal_one_planet{T}( theta::Array{T,1}, time::Float64; plid::Integer = 1, tol::Real = 1.e-8 )
  #= P = extract_period(theta,offset=offset)
  K = extract_amplitude(theta,offset=offset)
  h = extract_ecosw(theta,offset=offset)   # TODO: check h & k def)
  k = extract_esinw(theta,offset=offset)
  M0 = extract_mean_anomaly_at_t0(theta,offset=offset) =#
  (P,K,h,k,M0) = extract_PKhkM(theta,plid=plid)
  ecc = sqrt(h*h+k*k)
  w = atan2(k,h)
  n = 2pi/P
  #M = mod2pi(time*n-M0)
  M = time*n-M0
  lambda = w+M
  #E = ecc_anom_bessel_series_approx(M,ecc)  # WARNING: This would calling approximate version
  #E = ecc_anom_itterative_laguerre(M,ecc,tol=tol) # WARNING: hardwired particular algorithm
  E = calc_ecc_anom(M,ecc,tol=tol)
  c = cos(lambda+ecc*sin(E))
  s = sin(lambda+ecc*sin(E))
  if ecc >= 1.0
    println("# ERROR in calc_rv_pal_one_planet: ecc>=1.0:  ",theta)
  end
  @assert(0.0<=ecc<1.0)
  j = sqrt((1.0-ecc)*(1.0+ecc))
  #p, q = (ecc == 0.0) ? fill((0.0, 0.0), length(time)) : (ecc.*sin(E), ecc.*cos(E))
  p, q = (ecc == 0.0) ? (zero(T), zero(T)) : (ecc*sin(E), ecc*cos(E))
  a = K/(n/sqrt((1.0-ecc)*(1.0+ecc)))
  zdot = a*n/(1.0-q)*( cos(lambda+p)-k*q/(1.0+j) )
end

# Calculate Keplerian velocity of star due to num_pl planets
function calc_rv_pal_multi_planet{T}( theta::Array{T,1}, time::Float64; tol::Real = 1.e-8)
  zdot = zero(T)
  for plid in 1:num_planets(theta)
      zdot += calc_rv_pal_one_planet(theta,time,plid=plid,tol=tol)
  end
  return zdot
end

# Assumes model parameters = [ Period_1, K_1, k_1, h_1, M0_1,   Period_2, K_2, k_2, h_2, M0_2, ...  C ]
function calc_model_rv{T}( theta::Array{T,1}, t::Float64; obsid::Integer = 1, tol::Real = 1.e-8)
  Offset = extract_rvoffset(theta, obsid=obsid)
  calc_rv_pal_multi_planet(theta, t, tol=tol) + Offset
end

export isvalid, calc_model_rv


text:
# -------- Opening a window ---------------
# Forward reference for @cfunction
function windowEventWatcher end
const window_event_watcher_cfunc = Ref(Ptr{Nothing}(0))

const window_paused = Threads.Atomic{UInt8}(0) # Whether or not the game should be running (if lost focus)

function makeWinRenderer(title = "GameZero Julia", w=400,h=400 )
    global winWidth, winHeight, winWidth_highDPI, winHeight_highDPI

    win = SDL_CreateWindow(title,
        Int32(SDL_WINDOWPOS_CENTERED), Int32(SDL_WINDOWPOS_CENTERED), Int32(w), Int32(h),
        UInt32(SDL_WINDOW_ALLOW_HIGHDPI|SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN));
        SDL_SetWindowMinimumSize(win, Int32(w), Int32(h))
    window_event_watcher_cfunc[] = @cfunction(windowEventWatcher, Cint, (Ptr{Nothing}, Ptr{SDL_Event}))
    SDL_AddEventWatch(window_event_watcher_cfunc[], win);

    renderer = SDL_CreateRenderer(win, Int32(-1), UInt32(SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC))
    SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND)
    return win,renderer
end

# This function handles all window events.
# We currently do no allow window resizes
function windowEventWatcher(data_ptr::Ptr{Cvoid}, event_ptr::Ptr{SDL_Event})::Cint
    global winWidth, winHeight, cam, window_paused, renderer, win
    ev = unsafe_load(event_ptr, 1)
    #ee = evt.type
    #t = UInt32(ee[4]) << 24 | UInt32(ee[3]) << 16 | UInt32(ee[2]) << 8 | ee[1]
    t = ev.type
    if (t == SDL_WindowEvent)
        event = unsafe_load( Ptr{SDL_WindowEvent}(pointer_from_objref(ev)) )
        winevent = event.event;  # confusing, but that's what the field is called.
        if (winevent == SDL_WINDOWEVENT_FOCUS_LOST || winevent == SDL_WINDOWEVENT_HIDDEN || winevent == SDL_WINDOWEVENT_MINIMIZED)
            # Stop game playing when out of focus
                window_paused[] = 1
            #end
        elseif (winevent == SDL_WINDOWEVENT_FOCUS_GAINED || winevent == SDL_WINDOWEVENT_SHOWN)
            window_paused[] = 0
        end
    end
    return 0
end

function getWindowSize(win)
    w,h,w_highDPI,h_highDPI = Int32[0],Int32[0],Int32[0],Int32[0]
    SDL_GetWindowSize(win, w, h)
    SDL_GL_GetDrawableSize(win, w_highDPI, h_highDPI)
    return w[],h[],w_highDPI[],h_highDPI[]
end


text:
module Actions
    import Pluto: Pluto, without_pluto_file_extension
    using Base64
    using SHA
    using FromFile
    @from "./MoreAnalysis.jl" import MoreAnalysis
    @from "./Export.jl" using Export
    @from "./Types.jl" using Types
    myhash = base64encode ∘ sha256
    showall(xs) = Text(join(string.(xs),"\n"))

    function add_to_session!(notebook_sessions, server_session, path, settings, run_server=true, start_dir=".")
        jl_contents = read(joinpath(start_dir, path), String)
        current_hash = myhash(jl_contents)
        # The 5 lines below are needed if the code is not invoked within PlutoSliderServer.run_directory
        i = findfirst(s -> s.current_hash == current_hash, notebook_sessions)
        if isnothing(i)
            push!(notebook_sessions, QueuedNotebookSession(;path, current_hash=current_hash))
            i = length(notebook_sessions)
        end
        keep_running = run_server && path ∉ settings.SliderServer.exclude
        skip_cache = keep_running || path ∈ settings.Export.ignore_cache

        local notebook, original_state

        cached_state = skip_cache ? nothing : try_fromcache(settings.Export.cache_dir, current_hash)
        if cached_state !== nothing
            @info "Loaded from cache, skipping notebook run" current_hash
            original_state = cached_state
        else
            try
                # open and run the notebook (TODO: tell pluto not to write to the notebook file)
                notebook = Pluto.SessionActions.open(server_session, joinpath(start_dir, path); run_async=false)
                # get the state object
                original_state = Pluto.notebook_to_js(notebook)
                # shut down the notebook
                if !keep_running
                    @info "Shutting down notebook process"
                    Pluto.SessionActions.shutdown(server_session, notebook)
                end
                if keep_running
                    bond_connections = MoreAnalysis.bound_variable_connections_graph(notebook)
                    @info "Bond connections" showall(collect(bond_connections))

                    # By setting notebook_sessions[i] to a running session, (modifying the array), the HTTP router will now start serving requests for this notebook.
                    notebook_sessions[i] = RunningNotebookSession(;
                        path,
                        current_hash,
                        notebook,
                        original_state,
                        bond_connections,
                    )
                else
                    notebook_sessions[i] = FinishedNotebookSession(;
                        path,
                        current_hash,
                        original_state,
                    )
                end
                try_tocache(settings.Export.cache_dir, current_hash, original_state)
            catch e
                (e isa InterruptException) || rethrow(e)
                @error "Failed to run notebook!" path exception=(e,catch_backtrace())
                # continue
            end
        end
        notebook_sessions[i], jl_contents, original_state
    end

    function generate_static_export(path, settings, original_state=nothing, output_dir=".", jl_contents=nothing)
        pluto_version = Export.try_get_exact_pluto_version()
        export_jl_path = let
            relative_to_notebooks_dir = path
            joinpath(output_dir, relative_to_notebooks_dir)
        end
        export_html_path = let
            relative_to_notebooks_dir = without_pluto_file_extension(path) * ".html"
            joinpath(output_dir, relative_to_notebooks_dir)
        end
        export_statefile_path = let
            relative_to_notebooks_dir = without_pluto_file_extension(path) * ".plutostate"
            joinpath(output_dir, relative_to_notebooks_dir)
        end

        mkpath(dirname(export_jl_path))
        mkpath(dirname(export_html_path))
        mkpath(dirname(export_statefile_path))

        notebookfile_js = if (settings.Export.offer_binder || settings.Export.slider_server_url !== nothing)
            if settings.Export.baked_notebookfile
                "\"data:text/julia;charset=utf-8;base64,$(base64encode(jl_contents))\""
            else
                repr(basename(export_jl_path))
            end
        else
            "undefined"
        end
        slider_server_url_js = if settings.Export.slider_server_url !== nothing
            repr(settings.Export.slider_server_url)
        else
            "undefined"
        end
        binder_url_js = if settings.Export.offer_binder
            repr(something(settings.Export.binder_url, Pluto.default_binder_url))
            # not string(pluto_version) because it has to be an `x.y.z` version number, not a commit hash
        else
            "undefined"
        end
        statefile_js = if !settings.Export.baked_state
            open(export_statefile_path, "w") do io
                Pluto.pack(io, original_state)
            end
            repr(basename(export_statefile_path))
        else
            statefile64 = base64encode() do io
                Pluto.pack(io, original_state)
            end

            "\"data:;base64,$(statefile64)\""
        end

        html_contents = generate_html(;
            pluto_cdn_root=settings.Export.pluto_cdn_root,
            version=pluto_version,
            notebookfile_js, statefile_js,
            slider_server_url_js, binder_url_js,
            disable_ui=settings.Export.disable_ui
        )
        write(export_html_path, html_contents)

        if (settings.Export.offer_binder || settings.Export.slider_server_url !== nothing) && !settings.Export.baked_notebookfile
            write(export_jl_path, jl_contents)
        end

        @info "Written to $(export_html_path)"
    end
end


text:
export isafter

using Dates

function isafter(str::AbstractString, date::AbstractString=Dates.format(Dates.now(), "Y-mm-ddTHH:MM:SS"))::Bool
    comparison = Dates.DateTime(date)
    original = Dates.DateTime(str)

    return original > comparison
end