text:
using Test

@testset "CustomMAC" begin
    @test mac(n"Si", n"O K-L3", :Henke1974) == 8790.0
    @test mac(n"U", n"B K-L2", :Henke1982) == 9020.0
    @test mac(n"Ta", n"N K-L3", :Bastin1988) == 15000.0
    @test ismissing(mac(n"W", n"F K-L3", :Bastin1988))

    cust1 = getcustommacs(:Bastin1988, true)
    cust2 = getcustommacs(:Bastin1988, false)

    @test !isnothing(findfirst(x -> x == (n"Si", n"N K-L3", 17170.0), cust1))
    @test !isnothing(findfirst(x -> x == (n"Si", n"N K-L2", 17170.0), cust1))
    @test isnothing(findfirst(x -> x == (n"Si", n"N K-L2", 17170.0), cust2))
    @test !isnothing(findfirst(x -> x == (n"Zr", n"N K-L3", 24000.0), cust1))

    clear_user_macs!()
    for ( el, cxr, mac) in getcustommacs(:Bastin1988, true)
        set_user_mac!(el, cxr, mac)
    end
    @test mac(n"Si", n"N K-L3") == 17170.0
    @test mac(n"Zr", n"N K-L3") == 24000.0
    @test mac(n"Zr", n"O K-L3") == mac(n"Zr", n"O K-L3", FFASTDB)

    for ( el, cxr, mac) in getcustommacs(:Bastin1989, true)
        set_user_mac!(el, cxr, mac)
    end
    @test mac(n"Zr", n"O K-L3") == 16200.0
    @test mac(n"Zr", n"O K-L2") == 16200.0
    @test mac(n"Pb", n"O K-L3") == 11000.0
    delete_user_mac!(n"Ga", n"O K-L2")
    @test mac(n"Ga", n"O K-L2") == mac(n"Ga", n"O K-L2", FFASTDB)

    clear_user_macs!()
    @test mac(n"Zr", n"O K-L3") == mac(n"Zr", n"O K-L3", FFASTDB)
end


text:
module caramel

using JuMP, Cbc, Clp
using CSV, Distances

include("./raw/IO.jl")
include("./raw/raw.jl")

#struct.jl
export satker, moda, lin
export haul

#reader.jl
export V, E, M, T
export read_vertex, read_edge, read_mode

#core.jl
export Q, w, md, dst, src
export IN, OUT
export f, g
export raw_model_IP, raw_model_LP, convert_raw
export period_view, lin_view
export cost

include("./fcnf/fcnf.jl")
include("./fcnf/IO.jl")

export Node, loc, per
export Arc, ori, dst, f, g, u
export Commodity, src, snk, d, δ

end

ext: jl


text:
# -*- coding: utf-8 -*-

const MaxPly   = 80      # とりあえず大きめに取る。実際はこの半分もいかない。。。
const MaxMoves = 8000000 # 少ないかも。。。でもこんなに読まない。。。

const SENTE = 0 # ▲先手
const GOTE  = 1 # △後手

const ALPHALINE = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" }

#fi = open("table.jl","w")
#
#idx = 1
#
#for dan = 9:-1:1
#    for suji = 1:9
#        write( fi, "const $(ALPHALINE[suji])$(dan) = $(idx)\n")
#        idx+=1
#    end
#end
#close(fi)

const MaskOfBoard = parseint(Uint128,"000000000001ffffffffffffffffffff",16)::Uint128

const A9 = 1
const B9 = 2
const C9 = 3
const D9 = 4
const E9 = 5
const F9 = 6
const G9 = 7
const H9 = 8
const I9 = 9
const A8 = 10
const B8 = 11
const C8 = 12
const D8 = 13
const E8 = 14
const F8 = 15
const G8 = 16
const H8 = 17
const I8 = 18
const A7 = 19
const B7 = 20
const C7 = 21
const D7 = 22
const E7 = 23
const F7 = 24
const G7 = 25
const H7 = 26
const I7 = 27
const A6 = 28
const B6 = 29
const C6 = 30
const D6 = 31
const E6 = 32
const F6 = 33
const G6 = 34
const H6 = 35
const I6 = 36
const A5 = 37
const B5 = 38
const C5 = 39
const D5 = 40
const E5 = 41
const F5 = 42
const G5 = 43
const H5 = 44
const I5 = 45
const A4 = 46
const B4 = 47
const C4 = 48
const D4 = 49
const E4 = 50
const F4 = 51
const G4 = 52
const H4 = 53
const I4 = 54
const A3 = 55
const B3 = 56
const C3 = 57
const D3 = 58
const E3 = 59
const F3 = 60
const G3 = 61
const H3 = 62
const I3 = 63
const A2 = 64
const B2 = 65
const C2 = 66
const D2 = 67
const E2 = 68
const F2 = 69
const G2 = 70
const H2 = 71
const I2 = 72
const A1 = 73
const B1 = 74
const C1 = 75
const D1 = 76
const E1 = 77
const F1 = 78
const G1 = 79
const H1 = 80
const I1 = 81

# const RL90 = [A1, A2, A3, A4, A5, A6, A7, A8, A9,
# 	      B1, B2, B3, B4, B5, B6, B7, B8, B9,
# 	      C1, C2, C3, C4, C5, C6, C7, C8, C9,
# 	      D1, D2, D3, D4, D5, D6, D7, D8, D9,
# 	      E1, E2, E3, E4, E5, E6, E7, E8, E9,
# 	      F1, F2, F3, F4, F5, F6, F7, F8, F9,
# 	      G1, G2, G3, G4, G5, G6, G7, G8, G9,
# 	      H1, H2, H3, H4, H5, H6, H7, H8, H9,
# 	      I1, I2, I3, I4, I5, I6, I7, I8, I9]::Array{Int,1}

# const RL45 = [A9, B1, C2, D3, E4, F5, G6, H7, I8,
# 	      A8, B9, C1, D2, E3, F4, G5, H6, I7,
# 	      A7, B8, C9, D1, E2, F3, G4, H5, I6,
# 	      A6, B7, C8, D9, E1, F2, G3, H4, I5,
# 	      A5, B6, C7, D8, E9, F1, G2, H3, I4,
# 	      A4, B5, C6, D7, E8, F9, G1, H2, I3,
# 	      A3, B4, C5, D6, E7, F8, G9, H1, I2,
# 	      A2, B3, C4, D5, E6, F7, G8, H9, I1,
# 	      A1, B2, C3, D4, E5, F6, G7, H8, I9]::Array{Int,1}

# const RR45 = [I8, I7, I6, I5, I4, I3, I2, I1, I9,
# 	      H7, H6, H5, H4, H3, H2, H1, H9, H8,
# 	      G6, G5, G4, G3, G2, G1, G9, G8, G7,
# 	      F5, F4, F3, F2, F1, F9, F8, F7, F6,
# 	      E4, E3, E2, E1, E9, E8, E7, E6, E5,
# 	      D3, D2, D1, D9, D8, D7, D6, D5, D4,
# 	      C2, C1, C9, C8, C7, C6, C5, C4, C3,
# 	      B1, B9, B8, B7, B6, B5, B4, B3, B2,
# 	      A9, A8, A7, A6, A5, A4, A3, A2, A1]::Array{Int,1}

const MJNONE = 0 # 駒なし
const MJFU   = 1 # 歩兵
const MJKY   = 2 # 香車
const MJKE   = 3 # 桂馬
const MJGI   = 4 # 銀将
const MJKI   = 5 # 金将
const MJKA   = 6 # 角行
const MJHI   = 7 # 飛車
const MJOU   = 8 # 玉将／王将
const MJNARI = 8 #
const MJTO   = 9 # と
const MJNY   = 10 #成香
const MJNK   = 11 #成桂
const MJNG   = 12 #成銀
const MJPKIN = 13 #金は成らない
const MJUM   = 14 #馬
const MJRY   = 15 #龍
const MJNUM  = 16 #正規の駒は16種類
const MJGOTE = 16 # 後手の駒は16を足す

const MJGOFU   = 17 # 歩兵
const MJGOKY   = 18 # 香車
const MJGOKE   = 19 # 桂馬
const MJGOGI   = 20 # 銀将
const MJGOKI   = 21 # 金将
const MJGOKA   = 22 # 角行
const MJGOHI   = 23 # 飛車
const MJGOOU   = 24 # 玉将／王将
const MJGONARI = 24
const MJGOTO   = 25 # と
const MJGONY   = 26 #成香
const MJGONK   = 27 #成桂
const MJGONG   = 28 #成銀
const MJGOPKIN = 29 #金は成らない
const MJGOUM   = 30 #馬
const MJGORY   = 31 #龍
const MJGONUM  = 32 #正規の駒は16種類

const mjfu_max = 18
const mfky_max = 4
const mjke_max = 4
const mjgi_max = 4
const mjki_max = 4
const mjka_max = 2
const mjhi_max = 2
const mjou_max = 2

const rank1 = 1
const rank2 = 2
const rank3 = 3
const rank4 = 4
const rank5 = 5
const rank6 = 6
const rank7 = 7
const rank8 = 8
const rank9 = 9

const file1 = 1
const file2 = 2
const file3 = 3
const file4 = 4
const file5 = 5
const file6 = 6
const file7 = 7
const file8 = 8
const file9 = 9

const FILES = [1,2,3,4,5,6,7,8,9,
               1,2,3,4,5,6,7,8,9,
               1,2,3,4,5,6,7,8,9,
               1,2,3,4,5,6,7,8,9,
               1,2,3,4,5,6,7,8,9,
               1,2,3,4,5,6,7,8,9,
               1,2,3,4,5,6,7,8,9,
               1,2,3,4,5,6,7,8,9,
               1,2,3,4,5,6,7,8,9]::Array{Int,1}

const RANKS = [9,9,9,9,9,9,9,9,9,
	       8,8,8,8,8,8,8,8,8,
	       7,7,7,7,7,7,7,7,7,
	       6,6,6,6,6,6,6,6,6,
	       5,5,5,5,5,5,5,5,5,
	       4,4,4,4,4,4,4,4,4,
	       3,3,3,3,3,3,3,3,3,
	       2,2,2,2,2,2,2,2,2,
	       1,1,1,1,1,1,1,1,1]::Array{Int,1}

const SQUARENAME = ["a9","b9","c9","d9","e9","f9","g9","h9","i9",
                    "a8","b8","c8","d8","e8","f8","g8","h8","i8",
                    "a7","b7","c7","d7","e7","f7","g7","h7","i7",
                    "a6","b6","c6","d6","e6","f6","g6","h6","i6",
                    "a5","b5","c5","d5","e5","f5","g5","h5","i5",
                    "a4","b4","c4","d4","e4","f4","g4","h4","i4",
                    "a3","b3","c3","d3","e3","f3","g3","h3","i3",
                    "a2","b2","c2","d2","e2","f2","g2","h2","i2",
                    "a1","b1","c1","d1","e1","f1","g1","h1","i1"]::Array{ASCIIString,1}

const USISQNAME = ["9a","8a","7a","6a","5a","4a","3a","2a","1a",
		   "9b","8b","7b","6b","5b","4b","3b","2b","1b",
		   "9c","8c","7c","6c","5c","4c","3c","2c","1c",
		   "9d","8d","7d","6d","5d","4d","3d","2d","1d",
		   "9e","8e","7e","6e","5e","4e","3e","2e","1e",
		   "9f","8f","7f","6f","5f","4f","3f","2f","1f",
		   "9g","8g","7g","6g","5g","4g","3g","2g","1g",
		   "9h","8h","7h","6h","5h","4h","3h","2h","1h",
		   "9i","8i","7i","6i","5i","4i","3i","2i","1i"]::Array{ASCIIString,1}

const HIRATE = [ MJGOKY, MJGOKE, MJGOGI, MJGOKI, MJGOOU, MJGOKI, MJGOGI, MJGOKE, MJGOKY,
                 MJNONE, MJGOHI, MJNONE, MJNONE, MJNONE, MJNONE, MJNONE, MJGOKA, MJNONE,
                 MJGOFU, MJGOFU, MJGOFU, MJGOFU, MJGOFU, MJGOFU, MJGOFU, MJGOFU, MJGOFU,
                 MJNONE, MJNONE, MJNONE, MJNONE, MJNONE, MJNONE, MJNONE, MJNONE, MJNONE,
                 MJNONE, MJNONE, MJNONE, MJNONE, MJNONE, MJNONE, MJNONE, MJNONE, MJNONE,
                 MJNONE, MJNONE, MJNONE, MJNONE, MJNONE, MJNONE, MJNONE, MJNONE, MJNONE,
                 MJFU,   MJFU,   MJFU,   MJFU,   MJFU,   MJFU,   MJFU,   MJFU,   MJFU,
                 MJNONE, MJKA,   MJNONE, MJNONE, MJNONE, MJNONE, MJNONE, MJHI,   MJNONE,
                 MJKY,   MJKE,   MJGI,   MJKI,   MJOU,   MJKI,   MJGI,   MJKE,   MJKY
                ]::Array{Int,1}

const PIECENAMES = ["  ", "P ", "L ", "N ", "S ", "G ", "B ", "R ",
		    "K ", "+P", "+L", "+N", "+S", "  ", "+B", "+R",
		    "  ", "p ", "l ", "n ", "s ", "g ", "b ", "r ",
		    "k ", "+p", "+l", "+n", "+s", "  ", "+b", "+r"]::Array{ASCIIString,1}
const usiDict = {"P"=>MJFU,"L"=>MJKY,"N"=>MJKE,"S"=>MJGI,
                 "G"=>MJKI,"B"=>MJKA,"R"=>MJHI,
                 "p"=>MJFU,"l"=>MJKY,"n"=>MJKE,"s"=>MJGI,
                 "g"=>MJKI,"b"=>MJKA,"r"=>MJHI}::Dict{Any,Any}

const num2usiDict = {MJFU=>"P",MJKY=>"L",MJKE=>"N",MJGI=>"S",
                     MJKI=>"G",MJKA=>"B",MJHI=>"R",
                     MJGOFU=>"P",MJGOKY=>"L",MJGOKE=>"N",MJGOGI=>"S",
                     MJGOKI=>"G",MJGOKA=>"B",MJGOHI=>"R"}::Dict{Any,Any}

const NumHand = 7
const NumFile = 9
const NumRank = 9
const NumSQ   = 81

const doubleZenkakuSpace = "　　"::UTF8String

const KOMASTR = ["歩　",
                 "香　",
                 "桂　",
                 "銀　",
                 "金　",
                 "角　",
                 "飛　",
                 "王　",
                 "と　",
                 "成香",
                 "成桂",
                 "成銀",
                 "成金",
                 "馬　",
                 "龍　"]::Array{UTF8String,1}

const MOCHISTR = ["歩",
                  "香",
                  "桂",
                  "銀",
                  "金",
                  "角",
                  "飛",
                  "王"]::Array{UTF8String,1}

const TEBANSTR = ["▲ ", "△ "]::Array{UTF8String,1}

const SUJISTR  = ["１",
                  "２",
                  "３",
                  "４",
                  "５",
                  "６",
                  "７",
                  "８",
                  "９"]::Array{UTF8String,1}

const DANSTR = ["一",
                "二",
                "三",
                "四",
                "五",
                "六",
                "七",
                "八",
                "九"]::Array{UTF8String,1}

const MATERIAL = [87, # FU
                  232,# KY
                  257,# KE
                  369,# GI
                  444,# KI
                  569,# KA
                  642,# HI
                  15000, # OU
                  534,# TO
                  489,# NY
                  510,# NK
                  495,# NG
                  0,  # Nari Kin
                  827,# UM
                  945,# RY
                  ]::Array{Int,1}

const MATERIAL_CAPTURE = [174,   # FU
                          464,   # KY
                          514,   # KE
                          738,   # GI
                          888,   # KI
                          1138,  # KA
                          1284,  # HI
                          15000, # OU
                          621,   # TO
                          721,   # NY
                          767,   # NK
                          864,   # NG
                          0,     # Nari Kin
                          1396,  # UM
                          1587,  # RY
                          ]::Array{Int,1}

FR2IDX(file,rank) = ((9-(rank))*NumFile + ((file)))

typealias BitBoard Uint128

const BOARDINDEX = [FR2IDX(f,r) for f = 1:9, r=1:9]::Array{Int,2}

const f_hand_pawn   =    0
const e_hand_pawn   =   19
const f_hand_lance  =   38
const e_hand_lance  =   43
const f_hand_knight =   48
const e_hand_knight =   53
const f_hand_silver =   58
const e_hand_silver =   63
const f_hand_gold   =   68
const e_hand_gold   =   73
const f_hand_bishop =   78
const e_hand_bishop =   81
const f_hand_rook   =   84
const e_hand_rook   =   87
const fe_hand_end   =   90
const f_pawn        =   81
const e_pawn        =  162
const f_lance       =  225
const e_lance       =  306
const f_knight      =  360
const e_knight      =  441
const f_silver      =  504
const e_silver      =  585
const f_gold        =  666
const e_gold        =  747
const f_bishop      =  828
const e_bishop      =  909
const f_horse       =  990
const e_horse       = 1071
const f_rook        = 1152
const e_rook        = 1233
const f_dragon      = 1314
const e_dragon      = 1395
const fe_end        = 1476

const kkp_hand_pawn   =   0
const kkp_hand_lance  =  19
const kkp_hand_knight =  24
const kkp_hand_silver =  29
const kkp_hand_gold   =  34
const kkp_hand_bishop =  39
const kkp_hand_rook   =  42
const kkp_hand_end    =  45
const kkp_pawn        =  36
const kkp_lance       = 108
const kkp_knight      = 171
const kkp_silver      = 252
const kkp_gold        = 333
const kkp_bishop      = 414
const kkp_horse       = 495
const kkp_rook        = 576
const kkp_dragon      = 657
const kkp_end         = 738

const pos_n = int((fe_end) * ( fe_end + 1) / 2)

max_stars_repo_name: kimrin/JapaneseChess

max_issues_repo_name: kimrin/JapaneseChess

max_forks_repo_name: kimrin/JapaneseChess


text:
#==============================================================================#
# Discovery.jl
#
# This file is generated from:
# https://github.com/aws/aws-sdk-js/blob/master/apis/discovery-2015-11-01.normal.json
#==============================================================================#

__precompile__()

module Discovery

using AWSCore

"""
    using AWSSDK.Discovery.associate_configuration_items_to_application
    associate_configuration_items_to_application([::AWSConfig], arguments::Dict)
    associate_configuration_items_to_application([::AWSConfig]; applicationConfigurationId=, configurationIds=)

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "AssociateConfigurationItemsToApplication", arguments::Dict)
    discovery([::AWSConfig], "AssociateConfigurationItemsToApplication", applicationConfigurationId=, configurationIds=)

# AssociateConfigurationItemsToApplication Operation

Associates one or more configuration items with an application.

# Arguments

## `applicationConfigurationId = ::String` -- *Required*
The configuration ID of an application with which items are to be associated.

## `configurationIds = [::String, ...]` -- *Required*
The ID of each configuration item to be associated with an application.

# Returns

`AssociateConfigurationItemsToApplicationResponse`

# Exceptions

`AuthorizationErrorException`, `InvalidParameterException`, `InvalidParameterValueException` or `ServerInternalErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/AssociateConfigurationItemsToApplication)
"""
@inline associate_configuration_items_to_application(aws::AWSConfig=default_aws_config(); args...) = associate_configuration_items_to_application(aws, args)

@inline associate_configuration_items_to_application(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "AssociateConfigurationItemsToApplication", args)

@inline associate_configuration_items_to_application(args) = associate_configuration_items_to_application(default_aws_config(), args)

"""
    using AWSSDK.Discovery.create_application
    create_application([::AWSConfig], arguments::Dict)
    create_application([::AWSConfig]; name=, <keyword arguments>)

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "CreateApplication", arguments::Dict)
    discovery([::AWSConfig], "CreateApplication", name=, <keyword arguments>)

# CreateApplication Operation

Creates an application with the given name and description.

# Arguments

## `name = ::String` -- *Required*
Name of the application to be created.

## `description = ::String`
Description of the application to be created.

# Returns

`CreateApplicationResponse`

# Exceptions

`AuthorizationErrorException`, `InvalidParameterException`, `InvalidParameterValueException` or `ServerInternalErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/CreateApplication)
"""
@inline create_application(aws::AWSConfig=default_aws_config(); args...) = create_application(aws, args)

@inline create_application(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "CreateApplication", args)

@inline create_application(args) = create_application(default_aws_config(), args)

"""
    using AWSSDK.Discovery.create_tags
    create_tags([::AWSConfig], arguments::Dict)
    create_tags([::AWSConfig]; configurationIds=, tags=)

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "CreateTags", arguments::Dict)
    discovery([::AWSConfig], "CreateTags", configurationIds=, tags=)

# CreateTags Operation

Creates one or more tags for configuration items. Tags are metadata that help you categorize IT assets. This API accepts a list of multiple configuration items.

# Arguments

## `configurationIds = [::String, ...]` -- *Required*
A list of configuration items that you want to tag.

## `tags = [[ ... ], ...]` -- *Required*
Tags that you want to associate with one or more configuration items. Specify the tags that you want to create in a *key*-*value* format. For example:

`{"key": "serverType", "value": "webServer"}`
```
 tags = [[
        "key" => <required> ::String,
        "value" => <required> ::String
    ], ...]
```

# Returns

`CreateTagsResponse`

# Exceptions

`AuthorizationErrorException`, `ResourceNotFoundException`, `InvalidParameterException`, `InvalidParameterValueException` or `ServerInternalErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/CreateTags)
"""
@inline create_tags(aws::AWSConfig=default_aws_config(); args...) = create_tags(aws, args)

@inline create_tags(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "CreateTags", args)

@inline create_tags(args) = create_tags(default_aws_config(), args)

"""
    using AWSSDK.Discovery.delete_applications
    delete_applications([::AWSConfig], arguments::Dict)
    delete_applications([::AWSConfig]; configurationIds=)

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "DeleteApplications", arguments::Dict)
    discovery([::AWSConfig], "DeleteApplications", configurationIds=)

# DeleteApplications Operation

Deletes a list of applications and their associations with configuration items.

# Arguments

## `configurationIds = [::String, ...]` -- *Required*
Configuration ID of an application to be deleted.

# Returns

`DeleteApplicationsResponse`

# Exceptions

`AuthorizationErrorException`, `InvalidParameterException`, `InvalidParameterValueException` or `ServerInternalErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/DeleteApplications)
"""
@inline delete_applications(aws::AWSConfig=default_aws_config(); args...) = delete_applications(aws, args)

@inline delete_applications(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "DeleteApplications", args)

@inline delete_applications(args) = delete_applications(default_aws_config(), args)

"""
    using AWSSDK.Discovery.delete_tags
    delete_tags([::AWSConfig], arguments::Dict)
    delete_tags([::AWSConfig]; configurationIds=, <keyword arguments>)

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "DeleteTags", arguments::Dict)
    discovery([::AWSConfig], "DeleteTags", configurationIds=, <keyword arguments>)

# DeleteTags Operation

Deletes the association between configuration items and one or more tags. This API accepts a list of multiple configuration items.

# Arguments

## `configurationIds = [::String, ...]` -- *Required*
A list of configuration items with tags that you want to delete.

## `tags = [[ ... ], ...]`
Tags that you want to delete from one or more configuration items. Specify the tags that you want to delete in a *key*-*value* format. For example:

`{"key": "serverType", "value": "webServer"}`
```
 tags = [[
        "key" => <required> ::String,
        "value" => <required> ::String
    ], ...]
```

# Returns

`DeleteTagsResponse`

# Exceptions

`AuthorizationErrorException`, `ResourceNotFoundException`, `InvalidParameterException`, `InvalidParameterValueException` or `ServerInternalErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/DeleteTags)
"""
@inline delete_tags(aws::AWSConfig=default_aws_config(); args...) = delete_tags(aws, args)

@inline delete_tags(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "DeleteTags", args)

@inline delete_tags(args) = delete_tags(default_aws_config(), args)

"""
    using AWSSDK.Discovery.describe_agents
    describe_agents([::AWSConfig], arguments::Dict)
    describe_agents([::AWSConfig]; <keyword arguments>)

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "DescribeAgents", arguments::Dict)
    discovery([::AWSConfig], "DescribeAgents", <keyword arguments>)

# DescribeAgents Operation

Lists agents or the Connector by ID or lists all agents/Connectors associated with your user account if you did not specify an ID.

# Arguments

## `agentIds = [::String, ...]`
The agent or the Connector IDs for which you want information. If you specify no IDs, the system returns information about all agents/Connectors associated with your AWS user account.

## `filters = [[ ... ], ...]`
You can filter the request using various logical operators and a *key*-*value* format. For example:

`{"key": "collectionStatus", "value": "STARTED"}`
```
 filters = [[
        "name" => <required> ::String,
        "values" => <required> [::String, ...],
        "condition" => <required> ::String
    ], ...]
```

## `maxResults = ::Int`
The total number of agents/Connectors to return in a single page of output. The maximum value is 100.

## `nextToken = ::String`
Token to retrieve the next set of results. For example, if you previously specified 100 IDs for `DescribeAgentsRequest\$agentIds` but set `DescribeAgentsRequest\$maxResults` to 10, you received a set of 10 results along with a token. Use that token in this query to get the next set of 10.

# Returns

`DescribeAgentsResponse`

# Exceptions

`AuthorizationErrorException`, `InvalidParameterException`, `InvalidParameterValueException` or `ServerInternalErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/DescribeAgents)
"""
@inline describe_agents(aws::AWSConfig=default_aws_config(); args...) = describe_agents(aws, args)

@inline describe_agents(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "DescribeAgents", args)

@inline describe_agents(args) = describe_agents(default_aws_config(), args)

"""
    using AWSSDK.Discovery.describe_configurations
    describe_configurations([::AWSConfig], arguments::Dict)
    describe_configurations([::AWSConfig]; configurationIds=)

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "DescribeConfigurations", arguments::Dict)
    discovery([::AWSConfig], "DescribeConfigurations", configurationIds=)

# DescribeConfigurations Operation

Retrieves attributes for a list of configuration item IDs. All of the supplied IDs must be for the same asset type (server, application, process, or connection). Output fields are specific to the asset type selected. For example, the output for a *server* configuration item includes a list of attributes about the server, such as host name, operating system, and number of network cards.

For a complete list of outputs for each asset type, see [Using the DescribeConfigurations Action](http://docs.aws.amazon.com/application-discovery/latest/APIReference/discovery-api-queries.html#DescribeConfigurations).

# Arguments

## `configurationIds = [::String, ...]` -- *Required*
One or more configuration IDs.

# Returns

`DescribeConfigurationsResponse`

# Exceptions

`AuthorizationErrorException`, `InvalidParameterException`, `InvalidParameterValueException` or `ServerInternalErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/DescribeConfigurations)
"""
@inline describe_configurations(aws::AWSConfig=default_aws_config(); args...) = describe_configurations(aws, args)

@inline describe_configurations(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "DescribeConfigurations", args)

@inline describe_configurations(args) = describe_configurations(default_aws_config(), args)

"""
    using AWSSDK.Discovery.describe_export_configurations
    describe_export_configurations([::AWSConfig], arguments::Dict)
    describe_export_configurations([::AWSConfig]; <keyword arguments>)

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "DescribeExportConfigurations", arguments::Dict)
    discovery([::AWSConfig], "DescribeExportConfigurations", <keyword arguments>)

# DescribeExportConfigurations Operation

Deprecated. Use `DescribeExportTasks` instead.

Retrieves the status of a given export process. You can retrieve status from a maximum of 100 processes.

# Arguments

## `exportIds = [::String, ...]`
A unique identifier that you can use to query the export status.

## `maxResults = ::Int`
The maximum number of results that you want to display as a part of the query.

## `nextToken = ::String`
A token to get the next set of results. For example, if you specify 100 IDs for `DescribeExportConfigurationsRequest\$exportIds` but set `DescribeExportConfigurationsRequest\$maxResults` to 10, you get results in a set of 10. Use the token in the query to get the next set of 10.

# Returns

`DescribeExportConfigurationsResponse`

# Exceptions

`AuthorizationErrorException`, `ResourceNotFoundException`, `InvalidParameterException`, `InvalidParameterValueException` or `ServerInternalErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/DescribeExportConfigurations)
"""
@inline describe_export_configurations(aws::AWSConfig=default_aws_config(); args...) = describe_export_configurations(aws, args)

@inline describe_export_configurations(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "DescribeExportConfigurations", args)

@inline describe_export_configurations(args) = describe_export_configurations(default_aws_config(), args)

"""
    using AWSSDK.Discovery.describe_export_tasks
    describe_export_tasks([::AWSConfig], arguments::Dict)
    describe_export_tasks([::AWSConfig]; <keyword arguments>)

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "DescribeExportTasks", arguments::Dict)
    discovery([::AWSConfig], "DescribeExportTasks", <keyword arguments>)

# DescribeExportTasks Operation

Retrieve status of one or more export tasks. You can retrieve the status of up to 100 export tasks.

# Arguments

## `exportIds = [::String, ...]`
One or more unique identifiers used to query the status of an export request.

## `filters = [[ ... ], ...]`
One or more filters.

*   `AgentId` - ID of the agent whose collected data will be exported
```
 filters = [[
        "name" => <required> ::String,
        "values" => <required> [::String, ...],
        "condition" => <required> ::String
    ], ...]
```

## `maxResults = ::Int`
The maximum number of volume results returned by `DescribeExportTasks` in paginated output. When this parameter is used, `DescribeExportTasks` only returns `maxResults` results in a single page along with a `nextToken` response element.

## `nextToken = ::String`
The `nextToken` value returned from a previous paginated `DescribeExportTasks` request where `maxResults` was used and the results exceeded the value of that parameter. Pagination continues from the end of the previous results that returned the `nextToken` value. This value is null when there are no more results to return.

# Returns

`DescribeExportTasksResponse`

# Exceptions

`AuthorizationErrorException`, `InvalidParameterException`, `InvalidParameterValueException` or `ServerInternalErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/DescribeExportTasks)
"""
@inline describe_export_tasks(aws::AWSConfig=default_aws_config(); args...) = describe_export_tasks(aws, args)

@inline describe_export_tasks(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "DescribeExportTasks", args)

@inline describe_export_tasks(args) = describe_export_tasks(default_aws_config(), args)

"""
    using AWSSDK.Discovery.describe_tags
    describe_tags([::AWSConfig], arguments::Dict)
    describe_tags([::AWSConfig]; <keyword arguments>)

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "DescribeTags", arguments::Dict)
    discovery([::AWSConfig], "DescribeTags", <keyword arguments>)

# DescribeTags Operation

Retrieves a list of configuration items that are tagged with a specific tag. Or retrieves a list of all tags assigned to a specific configuration item.

# Arguments

## `filters = [[ ... ], ...]`
You can filter the list using a *key*-*value* format. You can separate these items by using logical operators. Allowed filters include `tagKey`, `tagValue`, and `configurationId`.
```
 filters = [[
        "name" => <required> ::String,
        "values" => <required> [::String, ...]
    ], ...]
```

## `maxResults = ::Int`
The total number of items to return in a single page of output. The maximum value is 100.

## `nextToken = ::String`
A token to start the list. Use this token to get the next set of results.

# Returns

`DescribeTagsResponse`

# Exceptions

`AuthorizationErrorException`, `ResourceNotFoundException`, `InvalidParameterException`, `InvalidParameterValueException` or `ServerInternalErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/DescribeTags)
"""
@inline describe_tags(aws::AWSConfig=default_aws_config(); args...) = describe_tags(aws, args)

@inline describe_tags(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "DescribeTags", args)

@inline describe_tags(args) = describe_tags(default_aws_config(), args)

"""
    using AWSSDK.Discovery.disassociate_configuration_items_from_application
    disassociate_configuration_items_from_application([::AWSConfig], arguments::Dict)
    disassociate_configuration_items_from_application([::AWSConfig]; applicationConfigurationId=, configurationIds=)

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "DisassociateConfigurationItemsFromApplication", arguments::Dict)
    discovery([::AWSConfig], "DisassociateConfigurationItemsFromApplication", applicationConfigurationId=, configurationIds=)

# DisassociateConfigurationItemsFromApplication Operation

Disassociates one or more configuration items from an application.

# Arguments

## `applicationConfigurationId = ::String` -- *Required*
Configuration ID of an application from which each item is disassociated.

## `configurationIds = [::String, ...]` -- *Required*
Configuration ID of each item to be disassociated from an application.

# Returns

`DisassociateConfigurationItemsFromApplicationResponse`

# Exceptions

`AuthorizationErrorException`, `InvalidParameterException`, `InvalidParameterValueException` or `ServerInternalErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/DisassociateConfigurationItemsFromApplication)
"""
@inline disassociate_configuration_items_from_application(aws::AWSConfig=default_aws_config(); args...) = disassociate_configuration_items_from_application(aws, args)

@inline disassociate_configuration_items_from_application(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "DisassociateConfigurationItemsFromApplication", args)

@inline disassociate_configuration_items_from_application(args) = disassociate_configuration_items_from_application(default_aws_config(), args)

"""
    using AWSSDK.Discovery.export_configurations
    export_configurations([::AWSConfig])

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "ExportConfigurations",)

# ExportConfigurations Operation

Deprecated. Use `StartExportTask` instead.

Exports all discovered configuration data to an Amazon S3 bucket or an application that enables you to view and evaluate the data. Data includes tags and tag associations, processes, connections, servers, and system performance. This API returns an export ID that you can query using the *DescribeExportConfigurations* API. The system imposes a limit of two configuration exports in six hours.

# Returns

`ExportConfigurationsResponse`

# Exceptions

`AuthorizationErrorException`, `InvalidParameterException`, `InvalidParameterValueException`, `ServerInternalErrorException` or `OperationNotPermittedException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/ExportConfigurations)
"""
@inline export_configurations(aws::AWSConfig=default_aws_config(); args...) = export_configurations(aws, args)

@inline export_configurations(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "ExportConfigurations", args)

@inline export_configurations(args) = export_configurations(default_aws_config(), args)

"""
    using AWSSDK.Discovery.get_discovery_summary
    get_discovery_summary([::AWSConfig], arguments::Dict)
    get_discovery_summary([::AWSConfig]; )

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "GetDiscoverySummary", arguments::Dict)
    discovery([::AWSConfig], "GetDiscoverySummary", )

# GetDiscoverySummary Operation

Retrieves a short summary of discovered assets.

# Arguments

# Returns

`GetDiscoverySummaryResponse`

# Exceptions

`AuthorizationErrorException`, `InvalidParameterException`, `InvalidParameterValueException` or `ServerInternalErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/GetDiscoverySummary)
"""
@inline get_discovery_summary(aws::AWSConfig=default_aws_config(); args...) = get_discovery_summary(aws, args)

@inline get_discovery_summary(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "GetDiscoverySummary", args)

@inline get_discovery_summary(args) = get_discovery_summary(default_aws_config(), args)

"""
    using AWSSDK.Discovery.list_configurations
    list_configurations([::AWSConfig], arguments::Dict)
    list_configurations([::AWSConfig]; configurationType=, <keyword arguments>)

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "ListConfigurations", arguments::Dict)
    discovery([::AWSConfig], "ListConfigurations", configurationType=, <keyword arguments>)

# ListConfigurations Operation

Retrieves a list of configuration items according to criteria that you specify in a filter. The filter criteria identifies the relationship requirements.

# Arguments

## `configurationType = "SERVER", "PROCESS", "CONNECTION" or "APPLICATION"` -- *Required*
A valid configuration identified by Application Discovery Service.

## `filters = [[ ... ], ...]`
You can filter the request using various logical operators and a *key*-*value* format. For example:

`{"key": "serverType", "value": "webServer"}`

For a complete list of filter options and guidance about using them with this action, see [Querying Discovered Configuration Items](http://docs.aws.amazon.com/application-discovery/latest/APIReference/discovery-api-queries.html#ListConfigurations).
```
 filters = [[
        "name" => <required> ::String,
        "values" => <required> [::String, ...],
        "condition" => <required> ::String
    ], ...]
```

## `maxResults = ::Int`
The total number of items to return. The maximum value is 100.

## `nextToken = ::String`
Token to retrieve the next set of results. For example, if a previous call to ListConfigurations returned 100 items, but you set `ListConfigurationsRequest\$maxResults` to 10, you received a set of 10 results along with a token. Use that token in this query to get the next set of 10.

## `orderBy = [[ ... ], ...]`
Certain filter criteria return output that can be sorted in ascending or descending order. For a list of output characteristics for each filter, see [Using the ListConfigurations Action](http://docs.aws.amazon.com/application-discovery/latest/APIReference/discovery-api-queries.html#ListConfigurations).
```
 orderBy = [[
        "fieldName" => <required> ::String,
        "sortOrder" =>  "ASC" or "DESC"
    ], ...]
```

# Returns

`ListConfigurationsResponse`

# Exceptions

`AuthorizationErrorException`, `ResourceNotFoundException`, `InvalidParameterException`, `InvalidParameterValueException` or `ServerInternalErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/ListConfigurations)
"""
@inline list_configurations(aws::AWSConfig=default_aws_config(); args...) = list_configurations(aws, args)

@inline list_configurations(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "ListConfigurations", args)

@inline list_configurations(args) = list_configurations(default_aws_config(), args)

"""
    using AWSSDK.Discovery.list_server_neighbors
    list_server_neighbors([::AWSConfig], arguments::Dict)
    list_server_neighbors([::AWSConfig]; configurationId=, <keyword arguments>)

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "ListServerNeighbors", arguments::Dict)
    discovery([::AWSConfig], "ListServerNeighbors", configurationId=, <keyword arguments>)

# ListServerNeighbors Operation

Retrieves a list of servers that are one network hop away from a specified server.

# Arguments

## `configurationId = ::String` -- *Required*
Configuration ID of the server for which neighbors are being listed.

## `portInformationNeeded = ::Bool`
Flag to indicate if port and protocol information is needed as part of the response.

## `neighborConfigurationIds = [::String, ...]`
List of configuration IDs to test for one-hop-away.

## `maxResults = ::Int`
Maximum number of results to return in a single page of output.

## `nextToken = ::String`
Token to retrieve the next set of results. For example, if you previously specified 100 IDs for `ListServerNeighborsRequest\$neighborConfigurationIds` but set `ListServerNeighborsRequest\$maxResults` to 10, you received a set of 10 results along with a token. Use that token in this query to get the next set of 10.

# Returns

`ListServerNeighborsResponse`

# Exceptions

`AuthorizationErrorException`, `InvalidParameterException`, `InvalidParameterValueException` or `ServerInternalErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/ListServerNeighbors)
"""
@inline list_server_neighbors(aws::AWSConfig=default_aws_config(); args...) = list_server_neighbors(aws, args)

@inline list_server_neighbors(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "ListServerNeighbors", args)

@inline list_server_neighbors(args) = list_server_neighbors(default_aws_config(), args)

"""
    using AWSSDK.Discovery.start_data_collection_by_agent_ids
    start_data_collection_by_agent_ids([::AWSConfig], arguments::Dict)
    start_data_collection_by_agent_ids([::AWSConfig]; agentIds=)

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "StartDataCollectionByAgentIds", arguments::Dict)
    discovery([::AWSConfig], "StartDataCollectionByAgentIds", agentIds=)

# StartDataCollectionByAgentIds Operation

Instructs the specified agents or connectors to start collecting data.

# Arguments

## `agentIds = [::String, ...]` -- *Required*
The IDs of the agents or connectors from which to start collecting data. If you send a request to an agent/connector ID that you do not have permission to contact, according to your AWS account, the service does not throw an exception. Instead, it returns the error in the *Description* field. If you send a request to multiple agents/connectors and you do not have permission to contact some of those agents/connectors, the system does not throw an exception. Instead, the system shows `Failed` in the *Description* field.

# Returns

`StartDataCollectionByAgentIdsResponse`

# Exceptions

`AuthorizationErrorException`, `InvalidParameterException`, `InvalidParameterValueException` or `ServerInternalErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/StartDataCollectionByAgentIds)
"""
@inline start_data_collection_by_agent_ids(aws::AWSConfig=default_aws_config(); args...) = start_data_collection_by_agent_ids(aws, args)

@inline start_data_collection_by_agent_ids(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "StartDataCollectionByAgentIds", args)

@inline start_data_collection_by_agent_ids(args) = start_data_collection_by_agent_ids(default_aws_config(), args)

"""
    using AWSSDK.Discovery.start_export_task
    start_export_task([::AWSConfig], arguments::Dict)
    start_export_task([::AWSConfig]; <keyword arguments>)

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "StartExportTask", arguments::Dict)
    discovery([::AWSConfig], "StartExportTask", <keyword arguments>)

# StartExportTask Operation

Begins the export of discovered data to an S3 bucket.

If you specify `agentIds` in a filter, the task exports up to 72 hours of detailed data collected by the identified Application Discovery Agent, including network, process, and performance details. A time range for exported agent data may be set by using `startTime` and `endTime`. Export of detailed agent data is limited to five concurrently running exports.

If you do not include an `agentIds` filter, summary data is exported that includes both AWS Agentless Discovery Connector data and summary data from AWS Discovery Agents. Export of summary data is limited to two exports per day.

# Arguments

## `exportDataFormat = ["CSV" or "GRAPHML", ...]`
The file format for the returned export data. Default value is `CSV`. **Note:** *The* `GRAPHML` *option has been deprecated.*

## `filters = [[ ... ], ...]`
If a filter is present, it selects the single `agentId` of the Application Discovery Agent for which data is exported. The `agentId` can be found in the results of the `DescribeAgents` API or CLI. If no filter is present, `startTime` and `endTime` are ignored and exported data includes both Agentless Discovery Connector data and summary data from Application Discovery agents.
```
 filters = [[
        "name" => <required> ::String,
        "values" => <required> [::String, ...],
        "condition" => <required> ::String
    ], ...]
```

## `startTime = timestamp`
The start timestamp for exported data from the single Application Discovery Agent selected in the filters. If no value is specified, data is exported starting from the first data collected by the agent.

## `endTime = timestamp`
The end timestamp for exported data from the single Application Discovery Agent selected in the filters. If no value is specified, exported data includes the most recent data collected by the agent.

# Returns

`StartExportTaskResponse`

# Exceptions

`AuthorizationErrorException`, `InvalidParameterException`, `InvalidParameterValueException`, `ServerInternalErrorException` or `OperationNotPermittedException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/StartExportTask)
"""
@inline start_export_task(aws::AWSConfig=default_aws_config(); args...) = start_export_task(aws, args)

@inline start_export_task(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "StartExportTask", args)

@inline start_export_task(args) = start_export_task(default_aws_config(), args)

"""
    using AWSSDK.Discovery.stop_data_collection_by_agent_ids
    stop_data_collection_by_agent_ids([::AWSConfig], arguments::Dict)
    stop_data_collection_by_agent_ids([::AWSConfig]; agentIds=)

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "StopDataCollectionByAgentIds", arguments::Dict)
    discovery([::AWSConfig], "StopDataCollectionByAgentIds", agentIds=)

# StopDataCollectionByAgentIds Operation

Instructs the specified agents or connectors to stop collecting data.

# Arguments

## `agentIds = [::String, ...]` -- *Required*
The IDs of the agents or connectors from which to stop collecting data.

# Returns

`StopDataCollectionByAgentIdsResponse`

# Exceptions

`AuthorizationErrorException`, `InvalidParameterException`, `InvalidParameterValueException` or `ServerInternalErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/StopDataCollectionByAgentIds)
"""
@inline stop_data_collection_by_agent_ids(aws::AWSConfig=default_aws_config(); args...) = stop_data_collection_by_agent_ids(aws, args)

@inline stop_data_collection_by_agent_ids(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "StopDataCollectionByAgentIds", args)

@inline stop_data_collection_by_agent_ids(args) = stop_data_collection_by_agent_ids(default_aws_config(), args)

"""
    using AWSSDK.Discovery.update_application
    update_application([::AWSConfig], arguments::Dict)
    update_application([::AWSConfig]; configurationId=, <keyword arguments>)

    using AWSCore.Services.discovery
    discovery([::AWSConfig], "UpdateApplication", arguments::Dict)
    discovery([::AWSConfig], "UpdateApplication", configurationId=, <keyword arguments>)

# UpdateApplication Operation

Updates metadata about an application.

# Arguments

## `configurationId = ::String` -- *Required*
Configuration ID of the application to be updated.

## `name = ::String`
New name of the application to be updated.

## `description = ::String`
New description of the application to be updated.

# Returns

`UpdateApplicationResponse`

# Exceptions

`AuthorizationErrorException`, `InvalidParameterException`, `InvalidParameterValueException` or `ServerInternalErrorException`.

See also: [AWS API Documentation](https://docs.aws.amazon.com/goto/WebAPI/discovery-2015-11-01/UpdateApplication)
"""
@inline update_application(aws::AWSConfig=default_aws_config(); args...) = update_application(aws, args)

@inline update_application(aws::AWSConfig, args) = AWSCore.Services.discovery(aws, "UpdateApplication", args)

@inline update_application(args) = update_application(default_aws_config(), args)

end # module Discovery

#==============================================================================#
# End of file
#==============================================================================#


text:
function flat_vol_covariance(t1::Float64, t2::Float64, T::Float64, S::Float64, v1::Float64, v2::Float64)
  t1 <= t2 || error("integrations bounds are in reverse order")
  cutOff = min(S, T)
  if t1 >= cutOff
    return 0.0
  else
    cutOff = min(t2, cutOff)
    return (cutOff - t1) * v1 * v2
  end
end

type FlatVol <: AbstractMarketModel
  covariance::Vector{Matrix{Float64}}
  totalCovariance::Vector{Matrix{Float64}}
  numberOfFactors::Int
  numberOfRates::Int
  numberOfSteps::Int
  initialRates::Vector{Float64}
  displacements::Vector{Float64}
  evolution::EvolutionDescription
  pseudoRoots::Vector{Matrix{Float64}}
end

function FlatVol(vols::Vector{Float64},
                corr::PiecewiseConstantCorrelation,
                evolution::EvolutionDescription,
                numberOfFactors::Int,
                initialRates::Vector{Float64},
                displacements::Vector{Float64})

  numberOfRates = length(initialRates)
  numberOfSteps = length(evolution.evolutionTimes)
  pseudoRoots = Matrix{Float64}[Matrix{Float64}(numberOfRates, numberOfFactors) for i = 1:numberOfSteps]

  rateTimes = evolution.rateTimes
  numberOfRates == length(rateTimes) - 1 || error("mismatch between number of rates and rate times")
  numberOfRates == length(displacements) || error("mismatch between number of rates and displacements")
  numberOfRates == length(vols) || error("mismatch between number of rates and vols")
  numberOfRates <= numberOfFactors * numberOfSteps || error("number of rates greater than number of factors times number of steps")
  numberOfFactors <= numberOfRates || error("number of factors cannot be greater than number of rates")
  numberOfFactors > 0 || error("number of factors must be greater than zero")

  effStopTime = 0.0
  corrTimes = corr.times
  evolTimes = evolution.evolutionTimes
  covariance = Matrix{Float64}(numberOfRates, numberOfRates)

  kk = 1
  for k = 1:numberOfSteps
    # one covariance per evolution step
    fill!(covariance, 0.0)

    # there might be more than one correlation matrix in a single evolution step
    while corrTimes[kk] < evolTimes[k]
      effStartTime = effStopTime
      corrMatrix = corr.correlations[kk]
      for i = 1:numberOfRates, j = i:numberOfRates
        cov = flat_vol_covariance(effStartTime, effStopTime, rateTimes[i], rateTimes[j], vols[i], vols[j])
        covariance[i, j] += cov * corrMatrix[i, j]
      end

      kk += 1
    end

    # last part in the evolution step
    effStartTime = effStopTime
    effStopTime = evolTimes[k]
    corrMatrix = corr.correlations[kk]
    for i = 1:numberOfRates, j = 1:numberOfRates
      cov = flat_vol_covariance(effStartTime, effStopTime, rateTimes[i], rateTimes[j], vols[i], vols[j])
      covariance[i, j] += cov * corrMatrix[i, j]
    end

    # no more use for the kk-th correlation matrix
    while kk < length(corrTimes) && corrTimes[kk] <= evolTimes[k]
      kk+=1
    end

    # make it symmetric
    for i = 1:numberOfRates, j = i+1:numberOfRates
      covariance[j, i] = covariance[i, j]
    end
    pseudoRoots[k] = rank_reduced_sqrt(covariance, numberOfFactors, 1.0, NoneSalvagingAlgo())
  end
  return FlatVol(Vector{Matrix{Float64}}(), Vector{Matrix{Float64}}(), numberOfFactors, numberOfRates, numberOfSteps, initialRates, displacements, evolution, pseudoRoots)
end

clone(flatVol::FlatVol) = FlatVol(deepcopy(flatVol.covariance), deepcopy(flatVol.totalCovariance), flatVol.numberOfFactors, flatVol.numberOfRates, flatVol.numberOfSteps,
                                  copy(flatVol.initialRates), copy(flatVol.displacements), clone(flatVol.evolution), deepcopy(flatVol.pseudoRoots))


text:
#=
    DenseKKTSystem
=#

"""
    DenseKKTSystem{T, VT, MT} <: AbstractReducedKKTSystem{T, MT}

Implement [`AbstractReducedKKTSystem`](@ref) with dense matrices.

Requires a dense linear solver to be factorized (otherwise an error is returned).

"""
struct DenseKKTSystem{T, VT, MT} <: AbstractReducedKKTSystem{T, MT}
    hess::MT
    jac::MT
    pr_diag::VT
    du_diag::VT
    diag_hess::VT
    # KKT system
    aug_com::MT
    # Info
    n_ineq::Int
    ind_ineq::Vector{Int}
    ind_fixed::Vector{Int}
    constraint_scaling::VT
    # Buffers
    etc::Dict{Symbol, Any}
end

"""
    DenseCondensedKKTSystem{T, VT, MT} <: AbstractCondensedKKTSystem{T, MT}

Implement [`AbstractCondensedKKTSystem`](@ref) with dense matrices.

Requires a dense linear solver to factorize the associated KKT system (otherwise an error is returned).

"""
struct DenseCondensedKKTSystem{T, VT, MT} <: AbstractCondensedKKTSystem{T, MT}
    hess::MT
    jac::MT
    jac_ineq::MT
    pr_diag::VT
    du_diag::VT
    # KKT system
    aug_com::MT
    # Info
    n_eq::Int
    ind_eq::Vector{Int}
    ind_eq_shifted::Vector{Int}
    n_ineq::Int
    ind_ineq::Vector{Int}
    ind_ineq_shifted::Vector{Int}
    ind_fixed::Vector{Int}
    constraint_scaling::VT
    # Buffers
    etc::Dict{Symbol, Any}
end

# For templating
const AbstractDenseKKTSystem{T, VT, MT} = Union{DenseKKTSystem{T, VT, MT}, DenseCondensedKKTSystem{T, VT, MT}}

#=
    Generic functions
=#

function jtprod!(y::AbstractVector, kkt::AbstractDenseKKTSystem, x::AbstractVector)
    nx = size(kkt.hess, 1)
    ns = kkt.n_ineq
    yx = view(y, 1:nx)
    ys = view(y, 1+nx:nx+ns)
    # / x
    mul!(yx, kkt.jac', x)
    # / s
    ys .= -x[kkt.ind_ineq] .* kkt.constraint_scaling[kkt.ind_ineq]
    return
end

function set_jacobian_scaling!(kkt::AbstractDenseKKTSystem, constraint_scaling::AbstractVector)
    copyto!(kkt.constraint_scaling, constraint_scaling)
end

function compress_jacobian!(kkt::AbstractDenseKKTSystem{T, VT, MT}) where {T, VT, MT}
    # Scale
    kkt.jac .*= kkt.constraint_scaling
    return
end

get_raw_jacobian(kkt::AbstractDenseKKTSystem) = kkt.jac
nnz_jacobian(kkt::AbstractDenseKKTSystem) = length(kkt.jac)

#=
    DenseKKTSystem
=#

function DenseKKTSystem{T, VT, MT}(n, m, ind_ineq, ind_fixed) where {T, VT, MT}
    ns = length(ind_ineq)
    hess = MT(undef, n, n)
    jac = MT(undef, m, n)
    pr_diag = VT(undef, n+ns)
    du_diag = VT(undef, m)
    diag_hess = VT(undef, n)

    # If the the problem is unconstrained, then KKT system is directly equal
    # to the Hessian (+ some regularization terms)
    aug_com = if (m == 0)
        hess
    else
        MT(undef, n+ns+m, n+ns+m)
    end

    constraint_scaling = VT(undef, m)

    # Init!
    fill!(aug_com, zero(T))
    fill!(hess,    zero(T))
    fill!(jac,     zero(T))
    fill!(pr_diag, zero(T))
    fill!(du_diag, zero(T))
    fill!(diag_hess, zero(T))
    fill!(constraint_scaling, one(T))

    return DenseKKTSystem{T, VT, MT}(
        hess, jac, pr_diag, du_diag, diag_hess, aug_com,
        ns, ind_ineq, ind_fixed, constraint_scaling, Dict{Symbol, Any}(),
    )
end

function DenseKKTSystem{T, VT, MT}(nlp::AbstractNLPModel, info_constraints=get_index_constraints(nlp)) where {T, VT, MT}
    return DenseKKTSystem{T, VT, MT}(
        get_nvar(nlp), get_ncon(nlp), info_constraints.ind_ineq, info_constraints.ind_fixed
    )
end

is_reduced(::DenseKKTSystem) = true
num_variables(kkt::DenseKKTSystem) = length(kkt.pr_diag)

function mul!(y::AbstractVector, kkt::DenseKKTSystem, x::AbstractVector)
    mul!(y, kkt.aug_com, x)
end
function mul!(y::ReducedKKTVector, kkt::DenseKKTSystem, x::ReducedKKTVector)
    mul!(full(y), kkt.aug_com, full(x))
end

# Special getters for Jacobian
function get_jacobian(kkt::DenseKKTSystem)
    n = size(kkt.hess, 1)
    ns = length(kkt.ind_ineq)
    return view(kkt.jac, :, 1:n)
end

function diag_add!(dest::AbstractMatrix, d1::AbstractVector, d2::AbstractVector)
    n = length(d1)
    @inbounds for i in 1:n
        dest[i, i] = d1[i] + d2[i]
    end
end

function _build_dense_kkt_system!(dest, hess, jac, pr_diag, du_diag, diag_hess, ind_ineq, con_scale, n, m, ns)
    # Transfer Hessian
    for i in 1:n, j in 1:i
        if i == j
            dest[i, i] = pr_diag[i] + diag_hess[i]
        else
            dest[i, j] = hess[i, j]
            dest[j, i] = hess[j, i]
        end
    end
    # Transfer slack diagonal
    for i in 1:ns
        dest[i+n, i+n] = pr_diag[i+n]
    end
    # Transfer Jacobian / variables
    for i in 1:m, j in 1:n
        dest[i + n + ns, j] = jac[i, j]
        dest[j, i + n + ns] = jac[i, j]
    end
    # Transfer Jacobian / slacks
    for j in 1:ns
        is = ind_ineq[j]
        dest[is + n + ns, j + n] = - con_scale[is]
        dest[j + n, is + n + ns] = - con_scale[is]
    end
    # Transfer dual regularization
    for i in 1:m
        dest[i + n + ns, i + n + ns] = du_diag[i]
    end
end

function build_kkt!(kkt::DenseKKTSystem{T, VT, MT}) where {T, VT, MT}
    n = size(kkt.hess, 1)
    m = size(kkt.jac, 1)
    ns = length(kkt.ind_ineq)
    if m == 0 # If problem is unconstrained, just need to update the diagonal
        diag_add!(kkt.aug_com, kkt.diag_hess, kkt.pr_diag)
    else # otherwise, we update the full matrix
        _build_dense_kkt_system!(kkt.aug_com, kkt.hess, kkt.jac,
                                 kkt.pr_diag, kkt.du_diag, kkt.diag_hess,
                                 kkt.ind_ineq, kkt.constraint_scaling,
                                 n, m, ns)
    end
    treat_fixed_variable!(kkt)
end

function compress_hessian!(kkt::DenseKKTSystem)
    # Transfer diagonal term for future regularization
    diag!(kkt.diag_hess, kkt.hess)
end

#=
    DenseCondensedKKTSystem
=#

function DenseCondensedKKTSystem{T, VT, MT}(nlp::AbstractNLPModel, info_constraints=get_index_constraints(nlp)) where {T, VT, MT}
    n = get_nvar(nlp)
    m = get_ncon(nlp)
    ns = length(info_constraints.ind_ineq)
    n_eq = m - ns

    aug_com  = MT(undef, n+m-ns, n+m-ns)
    hess     = MT(undef, n, n)
    jac      = MT(undef, m, n)
    jac_ineq = MT(undef, ns, n)

    pr_diag  = VT(undef, n+ns)
    du_diag  = VT(undef, m)
    constraint_scaling = VT(undef, m)

    # Init!
    fill!(aug_com, zero(T))
    fill!(hess,    zero(T))
    fill!(jac,     zero(T))
    fill!(pr_diag, zero(T))
    fill!(du_diag, zero(T))
    fill!(constraint_scaling, one(T))

    ind_eq = setdiff(1:m, info_constraints.ind_ineq)

    # Shift indexes to avoid additional allocation in views
    ind_eq_shifted = ind_eq .+ n .+ ns
    ind_ineq_shifted = info_constraints.ind_ineq .+ n .+ ns

    return DenseCondensedKKTSystem{T, VT, MT}(
        hess, jac, jac_ineq, pr_diag, du_diag, aug_com,
        n_eq, ind_eq, ind_eq_shifted,
        ns, info_constraints.ind_ineq, ind_ineq_shifted,
        info_constraints.ind_fixed,
        constraint_scaling, Dict{Symbol, Any}(),
    )
end

is_reduced(kkt::DenseCondensedKKTSystem) = true
num_variables(kkt::DenseCondensedKKTSystem) = size(kkt.hess, 1)

function get_slack_regularization(kkt::DenseCondensedKKTSystem)
    n, ns = num_variables(kkt), kkt.n_ineq
    return view(kkt.pr_diag, n+1:n+ns)
end
get_scaling_inequalities(kkt::DenseCondensedKKTSystem) = kkt.constraint_scaling[kkt.ind_ineq]

function _build_condensed_kkt_system!(
    dest::AbstractMatrix, hess::AbstractMatrix, jac::AbstractMatrix,
    pr_diag::AbstractVector, du_diag::AbstractVector, ind_eq::AbstractVector, n, m_eq,
)
    # Transfer Hessian
    @inbounds for i in 1:n, j in 1:i
        if i == j
            dest[i, i] += pr_diag[i] + hess[i, i]
        else
            dest[i, j] += hess[i, j]
            dest[j, i] += hess[j, i]
        end
    end
    # Transfer Jacobian / variables
    @inbounds for i in 1:m_eq, j in 1:n
        is = ind_eq[i]
        dest[i + n, j] = jac[is, j]
        dest[j, i + n] = jac[is, j]
    end
    # Transfer dual regularization
    @inbounds for i in 1:m_eq
        is = ind_eq[i]
        dest[i + n, i + n] = du_diag[is]
    end
end

function _build_ineq_jac!(
    dest::AbstractMatrix, jac::AbstractMatrix, pr_diag::AbstractVector,
    ind_ineq::AbstractVector, ind_fixed::AbstractVector, con_scale::AbstractVector,
    n, m_ineq,
)
    @inbounds for i in 1:m_ineq, j in 1:n
        is = ind_ineq[i]
        dest[i, j] = jac[is, j] * sqrt(pr_diag[n+i]) / con_scale[is]
    end
    # need to zero the fixed components
    dest[:, ind_fixed] .= 0.0
end

function build_kkt!(kkt::DenseCondensedKKTSystem{T, VT, MT}) where {T, VT, MT}
    n = size(kkt.hess, 1)
    ns = kkt.n_ineq
    n_eq = length(kkt.ind_eq)
    m = size(kkt.jac, 1)

    kkt.pr_diag[kkt.ind_fixed] .= 0
    fill!(kkt.aug_com, zero(T))
    # Build √Σₛ * J
    _build_ineq_jac!(kkt.jac_ineq, kkt.jac, kkt.pr_diag, kkt.ind_ineq, kkt.ind_fixed, kkt.constraint_scaling, n, ns)

    # Select upper-left block
    W = if n_eq > 0
        view(kkt.aug_com, 1:n, 1:n) # TODO: does not work on GPU
    else
        kkt.aug_com
    end
    # Build J' * Σₛ * J
    mul!(W, kkt.jac_ineq', kkt.jac_ineq)

    _build_condensed_kkt_system!(
        kkt.aug_com, kkt.hess, kkt.jac,
        kkt.pr_diag, kkt.du_diag,
        kkt.ind_eq, n, kkt.n_eq,
    )
    treat_fixed_variable!(kkt)
end

# TODO: check how to handle inertia with the condensed form
function is_inertia_correct(kkt::DenseCondensedKKTSystem, num_pos, num_zero, num_neg)
    return (num_zero == 0)
end

# For inertia-free regularization
function _mul_expanded!(y::AbstractVector, kkt::DenseCondensedKKTSystem, x::AbstractVector)
    n = size(kkt.hess, 1)
    ns = kkt.n_ineq
    m = size(kkt.jac, 1)

    Σx = view(kkt.pr_diag, 1:n)
    Σs = view(kkt.pr_diag, 1+n:n+ns)
    Σd = kkt.du_diag

    # Decompose x
    xx = view(x, 1:n)
    xs = view(x, 1+n:n+ns)
    xy = view(x, 1+n+ns:n+ns+m)

    # Decompose y
    yx = view(y, 1:n)
    ys = view(y, 1+n:n+ns)
    yy = view(y, 1+n+ns:n+ns+m)

    # / x (variable)
    yx .= Σx .* xx
    mul!(yx, kkt.hess, xx, 1.0, 1.0)
    mul!(yx, kkt.jac', xy, 1.0, 1.0)

    # / s (slack)
    ys .= Σs .* xs
    ys .-= kkt.constraint_scaling[kkt.ind_ineq] .* xy[kkt.ind_ineq]

    # / y (multiplier)
    yy .= Σd .* xy
    mul!(yy, kkt.jac, xx, 1.0, 1.0)
    yy[kkt.ind_ineq] .-= kkt.constraint_scaling[kkt.ind_ineq] .* xs
    return
end

function mul!(y::AbstractVector, kkt::DenseCondensedKKTSystem, x::AbstractVector)
    # TODO: implement properly with AbstractKKTRHS
    if length(y) == length(x) == size(kkt.aug_com, 1)
        mul!(y, kkt.aug_com, x)
    else
        _mul_expanded!(y, kkt, x)
    end
end

function mul!(y::ReducedKKTVector, kkt::DenseCondensedKKTSystem, x::ReducedKKTVector)
    mul!(full(y), kkt, full(x))
end

function jprod_ineq!(y::AbstractVector, kkt::DenseCondensedKKTSystem, x::AbstractVector)
    mul!(y, kkt.jac_ineq, x)
end


text:
isvideo(file) = any(endswith.(Ref(file), [".mkv", ".avi"])) && stat(file).size / 10^9 > 0.2 # consider that a file > 200 MB is a video file

function deflate(source, pattern; dest="deflated")
    run(`mkdir -p $dest`)
    for el ∈ readdir(source, join=true)
        if isdir(el) && !isnothing(match(pattern, el))
            for file ∈ readdir(el, join=false)
                file_joined = joinpath(el, file)
                if isvideo(file_joined)
                    mv(file_joined, joinpath(dest, file))
                end
            end
        end
    end
end


text:
# Julia wrappers around the NumPy API, as part of the PyCall package

#########################################################################
# Initialization (UGLY)

# Linking NumPy's C API from Julia requires some serious hackery,
# because NumPy does not export its symbols in the usual way for
# shared libraries.  Instead, it provides a Python variable
# numpy.core.multiarray._ARRAY_API that points to a lookup table of
# pointers to the API functions and global variables.  Moreover, the
# meaning of this table, along with a lot of other important
# constants, is defined in a C header file which changes between NumPy
# versions, so we need to do some regex parsing of this header file in
# order to extract the necessary information to call NumPy.  Ugly and
# mildly insane, but I don't see much alternative (at least to do this
# purely in Julia).
#
# The result of npy_api_initialize, below, is to produce the following
# tables of API pointers:
const npy_api = Dict{Symbol, Ptr{Void}}()

# need a global to cache pyimport("numpy.core.multiarray"), in order
# to ensure the module is not garbage-collected as long as we are using it
# for the npy_api pointers.
const npy_multiarray = PyNULL()

npy_initialized = false # global to prevent multiple initializations

# Macro version of npyinitialize() to inline npy_initialized? check
macro npyinitialize()
    :(npy_initialized::Bool ? nothing : npyinitialize())
end

# numpy.number types, used to detect scalars for conversion routines
const npy_number = PyNULL()
const npy_integer = PyNULL()
const npy_floating = PyNULL()
const npy_complexfloating = PyNULL()

function npyinitialize()
    global npy_initialized

    if npy_initialized::Bool
        return
    end
    try
        copy!(npy_multiarray, pyimport("numpy.core.multiarray"))
    catch e
        error("numpy.core.multiarray required for multidimensional Array conversions - ", e)
    end
    if pyversion_build.major < 3
        PyArray_API = @pycheck ccall((@pysym :PyCObject_AsVoidPtr),
                                     Ptr{Ptr{Void}}, (PyPtr,),
                                     npy_multiarray["_ARRAY_API"])
    else
        PyArray_API = @pycheck ccall((@pysym :PyCapsule_GetPointer),
                                     Ptr{Ptr{Void}}, (PyPtr,Ptr{Void}),
                                     npy_multiarray["_ARRAY_API"], C_NULL)
    end

    numpy = pyimport("numpy")

    # directory for numpy include files to parse
    inc = pycall(numpy["get_include"], AbstractString)

    # numpy.number types
    copy!(npy_number, numpy["number"])
    copy!(npy_integer, numpy["integer"])
    copy!(npy_floating, numpy["floating"])
    copy!(npy_complexfloating, numpy["complexfloating"])

    # Parse __multiarray_api.h to obtain length and meaning of PyArray_API
    try
        hdrfile = open(joinpath(inc, "numpy", "__multiarray_api.h"))
        hdr = readstring(hdrfile);
        close(hdrfile)
    catch e
        error("could not read __multiarray_api.h to parse PyArray_API ", e)
    end
    hdr = replace(hdr, r"\\\s*\n", " "); # rm backslashed newlines
    r = r"^#define\s+([A-Za-z]\w*)\s+\(.*\bPyArray_API\s*\[\s*([0-9]+)\s*\]\s*\)\s*$"m # regex to match #define PyFoo (... PyArray_API[nnn])
    PyArray_API_length = 0
    for m in eachmatch(r, hdr) # search for max index into PyArray_API
        PyArray_API_length = max(PyArray_API_length, parse(Int, m.captures[2])+1)
    end
    API = pointer_to_array(PyArray_API, (PyArray_API_length,))
    for m in eachmatch(r, hdr) # build npy_api table
        npy_api[Symbol(m.captures[1])] = API[parse(Int, m.captures[2])+1]
    end
    if !haskey(npy_api, :PyArray_New)
        error("failure parsing NumPy PyArray_API symbol table")
    end

    npy_initialized::Bool = true
    return
end

#########################################################################
# Hard-coded constant values, copied from numpy/ndarraytypes.h ...
# the values of these seem to have been stable for some time, and
# the NumPy developers seem to have some awareness of binary compatibility

# NPY_TYPES:

const NPY_BOOL = Int32(0)
const NPY_BYTE = Int32(1)
const NPY_UBYTE = Int32(2)
const NPY_SHORT = Int32(3)
const NPY_USHORT = Int32(4)
const NPY_INT = Int32(5)
const NPY_UINT = Int32(6)
const NPY_LONG = Int32(7)
const NPY_ULONG = Int32(8)
const NPY_LONGLONG = Int32(9)
const NPY_ULONGLONG = Int32(10)
const NPY_FLOAT = Int32(11)
const NPY_DOUBLE = Int32(12)
const NPY_LONGDOUBLE = Int32(13)
const NPY_CFLOAT = Int32(14)
const NPY_CDOUBLE = Int32(15)
const NPY_CLONGDOUBLE = Int32(16)
const NPY_OBJECT = Int32(17)
const NPY_STRING = Int32(18)
const NPY_UNICODE = Int32(19)
const NPY_VOID = Int32(20)

# NPY_ORDER:
const NPY_ANYORDER = Int32(-1)
const NPY_CORDER = Int32(0)
const NPY_FORTRANORDER = Int32(1)

# flags:
const NPY_ARRAY_C_CONTIGUOUS = Int32(1)
const NPY_ARRAY_F_CONTIGUOUS = Int32(2)
const NPY_ARRAY_ALIGNED = Int32(0x0100)
const NPY_ARRAY_WRITEABLE = Int32(0x0400)
const NPY_ARRAY_OWNDATA = Int32(0x0004)
const NPY_ARRAY_ENSURECOPY = Int32(0x0020)
const NPY_ARRAY_ENSUREARRAY = Int32(0x0040)
const NPY_ARRAY_FORCECAST = Int32(0x0010)
const NPY_ARRAY_UPDATEIFCOPY = Int32(0x1000)
const NPY_ARRAY_NOTSWAPPED = Int32(0x0200)
const NPY_ARRAY_ELEMENTSTRIDES = Int32(0x0080)

#########################################################################
# conversion from Julia types to NPY_TYPES constant

npy_type(::Type{Bool}) = NPY_BOOL
npy_type(::Type{Int8}) = NPY_BYTE
npy_type(::Type{UInt8}) = NPY_UBYTE
npy_type(::Type{Int16}) = NPY_SHORT
npy_type(::Type{UInt16}) = NPY_USHORT
npy_type(::Type{Int32}) = NPY_INT
npy_type(::Type{UInt32}) = NPY_UINT
npy_type(::Type{Int64}) = NPY_LONGLONG
npy_type(::Type{UInt64}) = NPY_ULONGLONG
npy_type(::Type{Float32}) = NPY_FLOAT
npy_type(::Type{Float64}) = NPY_DOUBLE
npy_type(::Type{Complex64}) = NPY_CFLOAT
npy_type(::Type{Complex128}) = NPY_CDOUBLE
npy_type(::Type{PyPtr}) = NPY_OBJECT

typealias NPY_TYPES Union{Bool,Int8,UInt8,Int16,UInt16,Int32,UInt32,Int64,UInt64,Float32,Float64,Complex64,Complex128,PyPtr}

# conversions from __array_interface__ type strings to supported Julia types
const npy_typestrs = Dict( "b1"=>Bool,
                           "i1"=>Int8,      "u1"=>UInt8,
                           "i2"=>Int16,     "u2"=>UInt16,
                           "i4"=>Int32,     "u4"=>UInt32,
                           "i8"=>Int64,     "u8"=>UInt64,
                           "f4"=>Float32,   "f8"=>Float64,
                           "c8"=>Complex64, "c16"=>Complex128,
                           "O"=>PyPtr, "O$(div(WORD_SIZE,8))"=>PyPtr )

#########################################################################
# no-copy conversion of Julia arrays to NumPy arrays.

# Julia arrays are in column-major order, but in some cases it is useful
# to pass them to Python as row-major arrays simply by reversing the
# dimensions. For example, although NumPy works with both row-major and
# column-major data, some Python libraries like OpenCV seem to require
# row-major data (the default in NumPy). In such cases, use PyReverseDims(array)
function NpyArray{T<:NPY_TYPES}(a::StridedArray{T}, revdims::Bool)
    @npyinitialize
    size_a = revdims ? reverse(size(a)) : size(a)
    strides_a = revdims ? reverse(strides(a)) : strides(a)
    p = @pycheck ccall(npy_api[:PyArray_New], PyPtr,
          (PyPtr,Cint,Ptr{Int},Cint, Ptr{Int},Ptr{T}, Cint,Cint,PyPtr),
          npy_api[:PyArray_Type],
          ndims(a), Int[size_a...], npy_type(T),
          Int[strides_a...] * sizeof(eltype(a)), a, sizeof(eltype(a)),
          NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE,
          C_NULL)
    return PyObject(p, a)
end

function PyObject{T<:NPY_TYPES}(a::StridedArray{T})
    try
        return NpyArray(a, false)
    catch
        array2py(a) # fallback to non-NumPy version
    end
end

PyReverseDims{T<:NPY_TYPES}(a::StridedArray{T}) = NpyArray(a, true)
PyReverseDims(a::BitArray) = PyReverseDims(Array(a))

"""
    PyReverseDims(array)

Passes a Julia `array` to Python as a NumPy row-major array
(rather than Julia's native column-major order) with the
dimensions reversed (e.g. a 2×3×4 Julia array is passed as
a 4×3×2 NumPy row-major array).  This is useful for Python
libraries that expect row-major data.
"""
PyReverseDims(a::AbstractArray)

#########################################################################
# Extract shape and other information about a NumPy array.  We need
# to call the Python interface to do this, since the equivalent information
# in NumPy's C API is only available via macros (or parsing structs).
# [ Hopefully, this will be improved in a future NumPy version. ]

type PyArray_Info
    T::Type
    native::Bool # native byte order?
    sz::Vector{Int}
    st::Vector{Int} # strides, in multiples of bytes!
    data::Ptr{Void}
    readonly::Bool

    function PyArray_Info(a::PyObject)
        ai = PyDict{AbstractString,PyObject}(a["__array_interface__"])
        typestr = convert(AbstractString, ai["typestr"])
        T = npy_typestrs[typestr[2:end]]
        datatuple = convert(Tuple{Int,Bool}, ai["data"])
        sz = convert(Vector{Int}, ai["shape"])
        local st
        try
            st = isempty(sz) ? Int[] : convert(Vector{Int}, ai["strides"])
        catch
            # default is C-order contiguous
            st = similar(sz)
            st[end] = sizeof(T)
            for i = length(sz)-1:-1:1
                st[i] = st[i+1]*sz[i+1]
            end
        end
        return new(T,
                   (ENDIAN_BOM == 0x04030201 && typestr[1] == '<')
                   || (ENDIAN_BOM == 0x01020304 && typestr[1] == '>')
                   || typestr[1] == '|',
                   sz, st,
                   convert(Ptr{Void}, datatuple[1]),
                   datatuple[2])
    end
end

aligned(i::PyArray_Info) = #  FIXME: also check pointer alignment?
  all(m -> m == 0, mod(i.st, sizeof(i.T))) # strides divisible by elsize

# whether a contiguous array in column-major (Fortran, Julia) order
function f_contiguous(T::Type, sz::Vector{Int}, st::Vector{Int})
    if prod(sz) == 1
        return true
    end
    if st[1] != sizeof(T)
        return false
    end
    for j = 2:length(st)
        if st[j] != st[j-1] * sz[j-1]
            return false
        end
    end
    return true
end

f_contiguous(i::PyArray_Info) = f_contiguous(i.T, i.sz, i.st)
c_contiguous(i::PyArray_Info) = f_contiguous(i.T, flipdim(i.sz,1), flipdim(i.st,1))

#########################################################################
# PyArray: no-copy wrapper around NumPy ndarray
#
# Hopefully, in the future this can be a subclass of StridedArray (see
# Julia issue #2345), which will allow it to be used with most Julia
# functions, but that is not possible at the moment.  So, to use this
# with Julia linalg functions etcetera a copy is still required.

"""
    PyArray(o::PyObject)

This converts an `ndarray` object `o` to a PyArray.

This implements a nocopy wrapper to a NumPy array (currently of only numeric types only).

If you are using `pycall` and the function returns an `ndarray`, you can use `PyArray` as the return type to directly receive a `PyArray`.
"""
type PyArray{T,N} <: AbstractArray{T,N}
    o::PyObject
    info::PyArray_Info
    dims::Dims
    st::Vector{Int}
    f_contig::Bool
    c_contig::Bool
    data::Ptr{T}

    function PyArray(o::PyObject, info::PyArray_Info)
        if !aligned(info)
            throw(ArgumentError("only NPY_ARRAY_ALIGNED arrays are supported"))
        elseif !info.native
            throw(ArgumentError("only native byte-order arrays are supported"))
        elseif info.T != T
            throw(ArgumentError("inconsistent type in PyArray constructor"))
        elseif length(info.sz) != N || length(info.st) != N
            throw(ArgumentError("inconsistent ndims in PyArray constructor"))
        end
        return new(o, info, tuple(info.sz...), div(info.st, sizeof(T)),
                   f_contiguous(info), c_contiguous(info),
                   convert(Ptr{T}, info.data))
    end
end

function PyArray(o::PyObject)
    info = PyArray_Info(o)
    return PyArray{info.T, length(info.sz)}(o, info)
end

size(a::PyArray) = a.dims
ndims{T,N}(a::PyArray{T,N}) = N

similar(a::PyArray, T, dims::Dims) = Array(T, dims)

function copy{T,N}(a::PyArray{T,N})
    if N > 1 && a.c_contig # equivalent to f_contig with reversed dims
        B = pointer_to_array(a.data, ntuple((n -> a.dims[N - n + 1]), N))
        return N == 2 ? transpose(B) : permutedims(B, (N:-1:1))
    end
    A = Array(T, a.dims)
    if a.f_contig
        ccall(:memcpy, Void, (Ptr{T}, Ptr{T}, Int), A, a, sizeof(T)*length(a))
        return A
    else
        return copy!(A, a)
    end
end

# TODO: need to do bounds-checking of these indices!

getindex{T}(a::PyArray{T,0}) = unsafe_load(a.data)
getindex{T}(a::PyArray{T,1}, i::Integer) = unsafe_load(a.data, 1 + (i-1)*a.st[1])

getindex{T}(a::PyArray{T,2}, i::Integer, j::Integer) =
  unsafe_load(a.data, 1 + (i-1)*a.st[1] + (j-1)*a.st[2])

function getindex(a::PyArray, i::Integer)
    if a.f_contig
        return unsafe_load(a.data, i)
    else
        return a[ind2sub(a.dims, i)...]
    end
end

function getindex(a::PyArray, is::Integer...)
    index = 1
    n = min(length(is),length(a.st))
    for i = 1:n
        index += (is[i]-1)*a.st[i]
    end
    for i = n+1:length(is)
        if is[i] != 1
            throw(BoundsError())
        end
    end
    unsafe_load(a.data, index)
end

function writeok_assign(a::PyArray, v, i::Integer)
    if a.info.readonly
        throw(ArgumentError("read-only PyArray"))
    else
        unsafe_store!(a.data, v, i)
    end
    return a
end

setindex!{T}(a::PyArray{T,0}, v) = writeok_assign(a, v, 1)
setindex!{T}(a::PyArray{T,1}, v, i::Integer) = writeok_assign(a, v, 1 + (i-1)*a.st[1])

setindex!{T}(a::PyArray{T,2}, v, i::Integer, j::Integer) =
  writeok_assign(a, v, 1 + (i-1)*a.st[1] + (j-1)*a.st[2])

function setindex!(a::PyArray, v, i::Integer)
    if a.f_contig
        return writeok_assign(a, v, i)
    else
        return setindex!(a, v, ind2sub(a.dims, i)...)
    end
end

function setindex!(a::PyArray, v, is::Integer...)
    index = 1
    n = min(length(is),length(a.st))
    for i = 1:n
        index += (is[i]-1)*a.st[i]
    end
    for i = n+1:length(is)
        if is[i] != 1
            throw(BoundsError())
        end
    end
    writeok_assign(a, v, index)
end

stride(a::PyArray, i::Integer) = a.st[i]

Base.unsafe_convert{T}(::Type{Ptr{T}}, a::PyArray{T}) = a.data

pointer(a::PyArray, i::Int) = pointer(a, ind2sub(a.dims, i))

function pointer{T}(a::PyArray{T}, is::Tuple{Vararg{Int}})
    offset = 0
    for i = 1:length(is)
        offset += (is[i]-1)*a.st[i]
    end
    return a.data + offset*sizeof(T)
end

summary{T}(a::PyArray{T}) = string(Base.dims2string(size(a)), " ",
                                   string(T), " PyArray")

#########################################################################
# PyArray <-> PyObject conversions

PyObject(a::PyArray) = a.o

convert(::Type{PyArray}, o::PyObject) = PyArray(o)

function convert{T<:NPY_TYPES}(::Type{Array{T, 1}}, o::PyObject)
    try
        copy(PyArray{T, 1}(o, PyArray_Info(o))) # will check T and N vs. info
    catch
        len = @pycheckz ccall((@pysym :PySequence_Size), Int, (PyPtr,), o)
        A = Array(pyany_toany(T), len)
        py2array(T, A, o, 1, 1)
    end
end

function convert{T<:NPY_TYPES}(::Type{Array{T}}, o::PyObject)
    try
        info = PyArray_Info(o)
        try
            copy(PyArray{T, length(info.sz)}(o, info)) # will check T == info.T
        catch
            return py2array(T, Array(pyany_toany(T), info.sz...), o, 1, 1)
        end
    catch
        py2array(T, o)
    end
end

function convert{T<:NPY_TYPES,N}(::Type{Array{T,N}}, o::PyObject)
    try
        info = PyArray_Info(o)
        try
            copy(PyArray{T,N}(o, info)) # will check T == info.T and N == length(info.sz)
        catch
            nd = length(info.sz)
            if nd != N
                throw(ArgumentError("cannot convert $(nd)d array to $(N)d"))
            end
            return py2array(T, Array(pyany_toany(T), info.sz...), o, 1, 1)
        end
    catch
        A = py2array(T, o)
        if ndims(A) != N
            throw(ArgumentError("cannot convert $(ndims(A))d array to $(N)d"))
        end
        A
    end
end

function convert(::Type{Array{PyObject}}, o::PyObject)
    map(pyincref, convert(Array{PyPtr}, o))
end

function convert(::Type{Array{PyObject,1}}, o::PyObject)
    map(pyincref, convert(Array{PyPtr, 1}, o))
end

function convert{N}(::Type{Array{PyObject,N}}, o::PyObject)
    map(pyincref, convert(Array{PyPtr, N}, o))
end

#########################################################################


text:
@timedtestset "neural_kernel_network" begin

    rng, N, N′, D = MersenneTwister(123456), 5, 6, 2
    x0 = collect(range(-2.0, 2.0; length=N)) .+ 1e-3 .* randn(rng, N)
    x1 = collect(range(-1.7, 2.3; length=N)) .+ 1e-3 .* randn(rng, N)
    x2 = collect(range(-1.7, 3.3; length=N′)) .+ 1e-3 .* randn(rng, N′)

    X0 = ColVecs(randn(rng, D, N))
    X1 = ColVecs(randn(rng, D, N))
    X2 = ColVecs(randn(rng, D, N′))

    ȳ, Ȳ, Ȳ_sq = randn(rng, N), randn(rng, N, N′), randn(rng, N, N)

    @timedtestset "general test" begin

        # Specify primitives.
        k1 = 0.6 * stretch(EQ(), 0.5)
        k2 = 0.4 * stretch(PerEQ(0.9), 1.1)
        primitives = Primitive(k1, k2)

        # Build NKN Kernel.
        nkn = NeuralKernelNetwork(primitives, Chain(LinearLayer(2, 2), product))

        # Run consistency checks + differentiability tests.
        differentiable_kernel_tests(nkn, ȳ, Ȳ, Ȳ_sq, x0, x1, x2; atol=1e-7, rtol=1e-7)
        differentiable_kernel_tests(nkn, ȳ, Ȳ, Ȳ_sq, X0, X1, X2; atol=1e-7, rtol=1e-7)
    end
    @timedtestset "kernel composition test" begin
        rng = MersenneTwister(123456)

        # Specify primitives.
        k1 = randn(rng) * stretch(EQ(), randn(rng))
        k2 = randn(rng) * stretch(PerEQ(randn(rng)), randn(rng))
        primitives = Primitive(k1, k2)

        @timedtestset "LinearLayer" begin

            # Specify linear NKN and equivalent composite kernel.
            weights = rand(rng, 1, 2)
            nkn_add_kernel = NeuralKernelNetwork(primitives, LinearLayer(weights))
            sum_k = Stheno.softplus(weights[1]) * k1 + Stheno.softplus(weights[2]) * k2

            # Vector input.
            @test ew(nkn_add_kernel, x0) ≈ ew(sum_k, x0)
            @test ew(nkn_add_kernel, x0, x1) ≈ ew(sum_k, x0, x1)

            # ColVecs input.
            @test ew(nkn_add_kernel, X0) ≈ ew(sum_k, X0)
            @test ew(nkn_add_kernel, X0, X1) ≈ ew(sum_k, X0, X1)
        end
        @timedtestset "product" begin
            nkn_prod_kernel = NeuralKernelNetwork(primitives, product)
            prod_k = k1 * k2

            # Vector input.
            @test pw(nkn_prod_kernel, x0) ≈ pw(prod_k, x0)
            @test pw(nkn_prod_kernel, x0, x1) ≈ pw(prod_k, x0, x1)

            # ColVecs input.
            @test pw(nkn_prod_kernel, X0) ≈ pw(prod_k, X0)
            @test pw(nkn_prod_kernel, X0, X1) ≈ pw(prod_k, X0, X1)
        end
    end
end


text:
# This file was generated by the Julia Swagger Code Generator
# Do not modify this file directly. Modify the swagger specification instead.

mutable struct VpnClientRootCertificatePropertiesFormat <: SwaggerModel
    publicCertData::Any # spec type: Union{ Nothing, String } # spec name: publicCertData
    provisioningState::Any # spec type: Union{ Nothing, String } # spec name: provisioningState

    function VpnClientRootCertificatePropertiesFormat(;publicCertData=nothing, provisioningState=nothing)
        o = new()
        validate_property(VpnClientRootCertificatePropertiesFormat, Symbol("publicCertData"), publicCertData)
        setfield!(o, Symbol("publicCertData"), publicCertData)
        validate_property(VpnClientRootCertificatePropertiesFormat, Symbol("provisioningState"), provisioningState)
        setfield!(o, Symbol("provisioningState"), provisioningState)
        o
    end
end # type VpnClientRootCertificatePropertiesFormat

const _property_map_VpnClientRootCertificatePropertiesFormat = Dict{Symbol,Symbol}(Symbol("publicCertData")=>Symbol("publicCertData"), Symbol("provisioningState")=>Symbol("provisioningState"))
const _property_types_VpnClientRootCertificatePropertiesFormat = Dict{Symbol,String}(Symbol("publicCertData")=>"String", Symbol("provisioningState")=>"String")
Base.propertynames(::Type{ VpnClientRootCertificatePropertiesFormat }) = collect(keys(_property_map_VpnClientRootCertificatePropertiesFormat))
Swagger.property_type(::Type{ VpnClientRootCertificatePropertiesFormat }, name::Symbol) = Union{Nothing,eval(Meta.parse(_property_types_VpnClientRootCertificatePropertiesFormat[name]))}
Swagger.field_name(::Type{ VpnClientRootCertificatePropertiesFormat }, property_name::Symbol) =  _property_map_VpnClientRootCertificatePropertiesFormat[property_name]

function check_required(o::VpnClientRootCertificatePropertiesFormat)
    (getproperty(o, Symbol("publicCertData")) === nothing) && (return false)
    true
end

function validate_property(::Type{ VpnClientRootCertificatePropertiesFormat }, name::Symbol, val)
end