text:
#include("main.jl")
#Generation d'une population
include("DM2_exp.jl")
#parametre génération de population
alpha1 = 0.2
alpha2 = 0.6
alpha3 = 0.8
alphaS = [alpha1, alpha2, alpha3]
population = []
#paramétre de selection et de filliation
nbrParticipants = 16
nbrSelectionné = 4
chanceMut = 0.75
taillePop = 120
cuts = []
nbrEnfants = 60
nbrCuts = 4
nbrGen = 5
#Array{(Array{Bool,1}),Int64)}

function mutationAdd(pop::Array{Tuple{Int64,Array{Bool,1}},1}, p::Float64, matrix::Array{Int64,2}, cost::Array{Int64,1})
    for i in 1:length(pop)
        r = rand()
        if r < p
            # println("superMutation")
            pop[i] = addSimpleDescent(pop[i], matrix, cost)
        # elseif r < 0.6
        #     # pop_int[i] = zero_one_exchange(pop_int[i],matrix,cost)
            # pop_int[i] = one_one_exchange(pop_int[i],matrix,cost)
            # pop_int[i] = one_two_exchange(pop_int[i],matrix,cost)
        end
    end
    return pop
end

function addSimpleDescent(sol::Tuple{Int64,Array{Bool,1}}, matrix::Array{Int64,2}, cost::Array{Int64,1})
    best_sol = zero_one_exchange(sol,matrix,cost)
    while best_sol[1] > sol[1]
        sol = best_sol
        best_sol = zero_one_exchange(sol,matrix,cost)
    end
    return sol
end

function zero_one_exchange(sol::Tuple{Array{Bool,1},Int64}, matrix::Array{Int64,2}, cost::Array{Int64,1})
    best_voisin = copy(sol[1])
    best_z = copy(sol[2])
    indvar = 0
    stop = false

    vars_0 = Int64[]                             # Vecteur contenant l'indice des variables de decision valant 0 dans la solution @sol
    constr_sat = Int64[]                        # Vecteur contenant l'indice des contraintes satisfaites
    for i = 1:length(sol[1])
        if sol[1][i] == 0
            push!(vars_0,i)
        else
            for j = 1:size(matrix)[1]
                if matrix[j,i] == 1
                    push!(constr_sat,j)
                end
            end
        end
    end

    p_candidat = Int64[]
    for var in vars_0
        vaut0 = false
        for constr in constr_sat
            if matrix[constr,var] == 1
                vaut0 = true
            end
        end
        if !vaut0
            push!(p_candidat,var)
        end
    end

    i = 1
    while i <= length(p_candidat) && !stop
        z_voisin = sol[2] + cost[p_candidat[i]]
        if z_voisin > best_z
            stop = true
            best_z = z_voisin
        else
            i = i+1
        end
    end

    if stop
        best_voisin[p_candidat[i]] = 1
    end
    # println("amélioration :", sol[1]," ->", best_z)
    # println("admissibilite du voisin 0-1 :", is_admissible((best_z,best_voisin),cost,matrix))
    return best_z, best_voisin
end

function genPop(cost, matrix, n, m, alphaS)
    for i in 1:40
        (SOL, z, desactive_condition) = GRASP(cost, matrix, n, m, alphaS[1])
        push!(population, (SOL, z))
        (SOL, z, desactive_condition) = GRASP(cost, matrix, n, m, alphaS[2])
        push!(population, (SOL, z))
        (SOL, z) = UpgradeGRASP(cost, matrix, n, m, alphaS[3])
        #println(typeof(z))
        push!(population, (SOL, z))
    end
    #println(population)
    for x in population
        afficheSol(x)
    end
    println(typeof(population))
    sort!(population, by = x -> x[2])
    println("\n\n\n")
    #println(population)
    for x in population
        afficheSol(x)
    end
    return(population)
end

function evaluate(population)
    sort!(population, by = x -> x[2])
    bas = deepcopy(population[end-119:end-80])
    moyen = deepcopy(population[end-79:end-40])
    elite = deepcopy(population[end-39:end])
    return(bas,moyen,elite)
end

function roulette(population, tailleSelec)#la taille du tournoi sera le nombre de participants au départ, elle doit être un multiple de 2
    selection = []
    probaSelec = Array{Float64}(undef, length(population))
    for i in 1:length(population)
        probaSelec[i] = i/length(population)
    end
    println("probaSelec: ", probaSelec)
    noInf = 4
    while length(selection) < tailleSelec
        j = 1
        i = 1
        choisie = rand(Float64,tailleSelec)
        sort!(choisie)
        println("choisie: ", choisie)
        while i <= length(population) && j <= tailleSelec
            if choisie[j] <= probaSelec[i] && j<=tailleSelec
                j += 1
                push!(selection, population[i])
                println(i, " sélectionné")
            end
            i += 1
            println("i= ", i, "  j = ", j)
        end
    end
    selection = selection[1:tailleSelec]

    println("taille de la selection:  ", length(selection))
    println(selection)

    return(selection)
end

function TournoiMeilleur(participant, nbrSelectionne) #le nombre de participants et de selection doivent être des puissances de 2 avec nbrSelection < nbrParticipant
    sort!(participant, by = x -> x[2])
    pool1 = participant[1:Int64((length(participant)/2))]
    pool2 = participant[(Int64(length(participant)/2)+1):end]
    qualifié = participant

    while  length(qualifié) > nbrSelectionne
        qualifié = []
        for i in 1:length(pool1)
            randomNumber = rand(Float64)
            if randomNumber >= 0.75
                push!(qualifié, pool1[i])
            else
                push!(qualifié, pool2[i])
            end
        end
        sort!(qualifié, by = x -> x[2])
        pool1 = qualifié[1:Int64((length(qualifié)/2))]
        pool2 = qualifié[Int64((length(qualifié)/2)+1):end]
    end
    println("Fin tournoi meilleur avec ", length(qualifié), " qualifié!")
    println("qualifié: ", qualifié)
    return(qualifié)
end

function TournoiMoinsBon(participant, nbrSelectionne) #le nombre de participants et de selection doivent être des puissances de 2 avec nbrSelection < nbrParticipant
    sort!(participant, by = x -> x[2])
    pool1 = participant[1:Int64((length(participant)/2))]
    pool2 = participant[(Int64(length(participant)/2)+1):end]
    qualifié = participant

    while  length(qualifié) > nbrSelectionne
        qualifié = []
        for i in 1:length(pool1)
            randomNumber = rand(Float64)
            if randomNumber <= 0.75
                push!(qualifié, pool1[i])
            else
                push!(qualifié, pool2[i])
            end
        end
        sort!(qualifié, by = x -> x[2])
        pool1 = qualifié[1:Int64((length(qualifié)/2))]
        pool2 = qualifié[Int64((length(qualifié)/2)+1):end]
    end
    println("Fin tournoi moins bon avec ", length(qualifié), " qualifié!")
    println("qualifié: ", qualifié)
    return(qualifié)
end

function crossOver(A, B, cuts)
    #Init variables
    fils = Vector{Array{Int64,1}}(undef,2^(length(cuts)+1))
    k=2
    m = length(fils)/2
    #Init tableau des enfants
    println("A: ", A)
    println("B: ", B)
    for i in 1:length(fils)
        fils[i] = []
        if i > m
            fils[i] = vcat(fils[i], B[1:(cuts[1])])
        else
            fils[i] = vcat(fils[i], A[1:(cuts[1])])
        end
    end
    #Debut du crossover
    for i in 1:length(cuts)-1 #On ajoute les coupes
        k = k*2
        for j in 1:k #partie du tableau
            for l in 1:Int64(length(fils)/k) #nbr d'éléments changé
                m = l+(j-1)*Int64(length(fils)/k)
                if j%2 == 1
                    fils[m] = vcat(fils[m], A[cuts[i]+1:(cuts[i+1])])
                else
                    fils[m] = vcat(fils[m], B[cuts[i]+1:(cuts[i+1])])
                end #fin if
            end #fin acces case à case
       end #On sectionne le tableau en 2^k parties
   end #end for de boucle
   #On finie de remplir le tableau, les gènes de A sont présent 1 case sur 2
   for j in 1:length(fils)
       if j % 2 == 1
           fils[j] = vcat(fils[j], A[(cuts[end]+1):end])
       else
           fils[j] = vcat(fils[j], B[(cuts[end]+1):end])
       end
   end
   return(fils[2:(end-1)])
end#Fin de crossOver

function mortalitéInfantile(enfants,nbrSurvivants)
    for i in 1:(length(enfants)-nbrSurvivants)
        mort = rand(1:length(enfants))
        println("L'enfant: ", mort, " est mort.")
        deleteat!(enfants, mort)
    end
    return(enfants)
end

#=

function smartRepair(matrix , cost, x)
    conflit = transpose(matrix*x)
    #println("conflits init: ", conflit)
    numConflits = Int64[]
    for i in 1:length(conflit) #identification des conflits
        if conflit[i] > 1
            push!(numConflits, i)
        end
    end
    println("taille de numConflits: ", length(numConflits), "   numConflits: ", numConflits)
    cpt = 0
    while length(numConflits) > 0  && cpt < 30
        numConflits = Int64[]
        sousMatConflits = []
        for i in 1:length(conflit) #identification des conflits
            if conflit[i] > 1
                push!(numConflits, i)
            end
        end
        println("num des conflits: ", numConflits)
        for i in numConflits
            push!(sousMatConflits, matrix[i,1:end])
        end
        println("Sous matrice de conflits: ", sousMatConflits)
        #Calcul de l'inutilitée
        inutile = inutilitée(x, cost, sousMatConflits)
        #Drop de la variable conflictuelle la moins Utilite
        dropID = maxID(inutile)
        println("variable droppé: ", dropID)
        x[dropID] = false
        conflit = transpose(matrix*x)
        #println("conflit : ", conflit)
        cpt += 1
    end
    z = transpose(x) * cost
    return(x , z)
    #=
    while (map(x -> x <= 1, conflits) != ones(Bool,length(x)))
        inutilité = inutile(x, cost, matrix)
        drop = maxID(inutilité)
        x[drop] = false
        conflits = traspose(x*matrix)
    end
    z = transpose(x)*cost
    =#
    return(x,z)
end

=#

function smartRepair(matrix , cost, x)
    conflit = transpose(matrix*x)
    #println("conflits init: ", conflit)
    numConflits = Int64[]
    for i in 1:length(conflit) #identification des conflits
        if conflit[i] > 1
            push!(numConflits, i)
        end
    end
    println("taille de numConflits: ", length(numConflits), "   numConflits: ", numConflits)
    cpt = 0
    while length(numConflits) > 0  && cpt < 10
		println("---------------------------------------")
        numConflits = Int64[]
        sousMatConflits = []
        for i in 1:length(conflit) #identification des conflits
            if conflit[i] > 1
                push!(numConflits, i)
            end
        end
        println("num des conflits: ", numConflits)
        for i in numConflits
            push!(sousMatConflits, matrix[i,1:end])
        end

		print("sol = ")
		for i in 1:length(x)
			if x[i] == 1
				print(i," ")
			end
		end
		println()
		println("Sous matrice de conflits: ")
		for i in 1:length(sousMatConflits)
			print("constr ", i, " : ")
			for j in 1:length(sousMatConflits[i])
				if sousMatConflits[i][j] == 1
					print(j, " ")
				end
			end
			println()
		end

        # println("Sous matrice de conflits: ", sousMatConflits)
        #Calcul de l'inutilitée
        inutile = inutilitée(x, cost, sousMatConflits)
		println(inutile)
        #Drop de la variable conflictuelle la moins Utilite
        dropID = maxID(inutile)
        println("variable droppé: ", dropID)
        x[dropID] = false
        conflit = transpose(matrix*x)
        # println("conflit : ", conflit)
        cpt += 1

    end
    z = transpose(x) * cost
    return(x , z)
    #=
    while (map(x -> x <= 1, conflits) != ones(Bool,length(x)))
        inutilité = inutile(x, cost, matrix)
        drop = maxID(inutilité)
        x[drop] = false
        conflits = traspose(x*matrix)
    end
    z = transpose(x)*cost
    =#
end

#=
function inutilitée(x, cost, sousMatConflits)
    inutilité = Array{Float64}(undef, length(x))
    for i in 1:length(x) #Pour chaque variable
        cpt = 0
        for j in 1: length(sousMatConflits) #On regarde chaque contraite
            if sousMatConflits[j][i] == true
                cpt += 1
            end
        end
        inutilité[i] = cpt/cost[i]
    end
    return(inutilité)
end
=#
function inutilitée(x, cost, sousMatConflits)
    inutilité = Array{Float64}(undef, length(x))
    for i in 1:length(x) #Pour chaque variable
        cpt = 0
        if x[i] == 1
            for j in 1: length(sousMatConflits) #On regarde chaque contraite
                if sousMatConflits[j][i] == 1
                    cpt += 1
                end
            end
        end
        inutilité[i] = cpt/cost[i]
    end
    return(inutilité)
end

function maxID(liste)
    ID = 1
    for i in 2:length(liste)
        if liste[i] > liste[ID]
            ID = i
        end
    end
    return(ID)
end

function mutation(x, matrix, cost, chanceMut)
    randomNumber = rand(Float64)
    println("Mutation? RGN: ", randomNumber, "   chanceMut: ", chanceMut)
    m, n = size(matrix)
    if randomNumber <= chanceMut
        randomNumber = rand(1:4)
        println("mutation choisie: ", randomNumber)
        if randomNumber == 1 #simple 1-1exchange
            crts = matrix * x
            println("simple 1-1exchange")
            (x, z) = exchange1_1(x, n, m, cost, crts, matrix)
        elseif randomNumber == 2 #simple  1-2 exchange
            crts = matrix * x
            println("simple  1-2 exchange")
            (x, z) = exchange1_2(x, n, m, cost, crts, matrix)
        elseif randomNumber == 3 #descent 1-2 & 1-1 exchange
            println("#descent 1-2 & 1-1 exchange")
            crts = matrix * x
            z1 = transpose(x) * cost
            z2 = 0
            while z2 > z1
                println("avant alélioration: ", z1)
                (x,z2) = exchange1_2(x, n, m, cost, crts, matrix)
                (x,z2) = exchange1_1(x, n, m, cost, crts, matrix)
                z1 = z2
                println("aprés amélioration: ", z1)
            end
            z = transpose(x) * cost
        else
            println("addOrElseDrop")
            x = addOrElseDrop(x, matrix)
            x = smartRepair(matrix , cost, x)
            z = transpose(x[1]) * cost
        end
    else
        println("Pas de mutation!")
        z = transpose(x) * cost
    end
    if length(x) == 2
        return(x)
    else
        return( x , z)
    end

end

function addOrElseDrop(x, matrix)
    listeFalse = []
    for i in 1:length(x)
        if x[i] == false
            push!(listeFalse, i)
        end
    end
    randomNumber = rand(listeFalse)
    #debut du Add
    println("add de la variable: ", randomNumber)
    x[randomNumber] = true
    conflit = transpose(matrix*x)
    for i in 1:length(conflit) #verification des conflits
        if conflit[i] > 1 #partie "elseDrop"
            println("conflit detecté")
            x[randomNumber] = false #retour à la soltion de départ
            #drop
            listeTrue = []
            for j in 1:length(x)
                if x[j] == 1
                    push!(listeTrue, j)
                end  #fin if
            end # fin contruction listeTrue
            drop = rand(listeTrue)
            println("drop de la variable: ", drop)
            x[drop] = false
            conflit = transpose(matrix*x)
        end #fin du else drop
    end # fin de verification de conflits
    return(x)
end

function genEnfants(parents1, parents2, nbrCuts, nbrEnfants, chanceMut, matrix, cost)
    println("Debut genEnfants")
    enfants = []
    enfantFinal = []

    for i in 1:length(parents1)
        println("crossOver n°", i)
        cuts = genCuts(length(parents1[1][1]), nbrCuts)
        println("cuts = ",cuts)
        enfants =  union(enfants,crossOver(parents1[i][1], parents2[i][1], cuts))
        println("fin crossOver n°", i)
    end
    println("taille enfant avant mortalité: ", length(enfants))
    enfants = mortalitéInfantile(enfants, nbrEnfants)
    println("taille enfant après mortalité: ", length(enfants))
    println("enfants: ", enfants)

    cpt = 0
    for x in enfants
        cpt += 1
        println("\n reparation enfant n°", cpt)
        println("x =", x)
        x = smartRepair(matrix , cost, x)
        println("enfant ", cpt, " réparé!")
        println("enfant après répa:", x)
        x = mutation(x[1], matrix, cost, chanceMut)
        println("enfant après :", x)
        push!(enfantFinal, x)
    end

    return(enfantFinal)
end

function genCuts(taille, nbrCuts)
    cuts = []
    println("cuts ini: ", cuts, "   taille: ", taille, "   NbrCuts: ", nbrCuts)
    cpt = 0
    while length(cuts) != nbrCuts && cpt < 100
        cpt += 1
        randomNumber = rand(2:taille-1)
        push!(cuts, randomNumber)
        println("cut n°", cpt, " = ", cuts)
    end
    sort!(cuts)
    return(cuts)
end

function afficheSol(x)
    print("Valeur solution: ", x[2], "   ")

    print("Valeurs actives: ")
    for i in 1:length(x[1])
        if x[1][i] == 1
            print( i , " ")
        end
    end
    println("")
end

#======================================================#

function expPop(fnames)
    for f in fnames
        println("====================================================================")
        println(f)
        cost, matrix, n, m = loadSPP(f)
        population = genPop(cost, matrix, n, m, alphaS)
        (bas, moyen, elite) = evaluate(population)
        println("bas:\n")
        for x in bas
            afficheSol(x)
        end
        println("\nmoyen:\n")
        for x in moyen
            afficheSol(x)
        end
        println("\nelite:\n")
        for x in elite
            afficheSol(x)
        end

        for i in 1:nbrGen
            participant = roulette(elite, nbrParticipants)
            selecElite = TournoiMeilleur(participant, nbrSelectionné)
            println("\n selection elite: ",selecElite)
            participant = roulette(bas, nbrParticipants)
            selecBas = TournoiMoinsBon(participant, nbrSelectionné)
            println("\n selection bas: ",selecBas)
            enfants = genEnfants(selecBas, selecElite, nbrCuts, nbrEnfants, chanceMut, matrix, cost)
            population = vcat(population, enfants)
            (bas, moyen, elite) = evaluate(vcat(population, enfants))
            for x in elite
                afficheSol(x)
            end
        end

#=
        participant = roulette(elite, nbrParticipants)
        selecElite = TournoiMeilleur(participant, nbrSelectionné)
        participant = roulette(bas, nbrParticipants)
        selecBas = TournoiMoinsBon(participant, nbrSelectionné)
        enfants = genEnfants(selecBas, selecElite, nbrCuts, nbrEnfants, chanceMut, matrix, cost)
        #println("affichage des enfants brut:")
        #println(enfants)
        for x in enfants
            afficheSol(x)
        end

        println("Taille pop avant fusion: ", length(population))
        println("Taille enfants: ", length(enfants))
        population = vcat(population, enfants)
        println("Taille pop après fusion: ", length(population))
        (bas, moyen, elite) = evaluate(vcat(population, enfants))
        println("bas, ",length(bas),"\n")
        for x in bas
            afficheSol(x)
        end
        println("\nmoyen:",length(moyen),"\n")
        for x in moyen
            afficheSol(x)
        end
        println("\nelite:",length(elite), "\n")
        for x in elite
            afficheSol(x)
        end
=#
        #survivant = mortalitéInfantile(selecBas, 1)
        #println("Survivant: ", survivant)
        #a = Bool[0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        #a = survivant[1][1]
        #println("a: ", a)
        #println("matrix: ", matrix)
        #b = smartRepair(matrix , cost, a)
        #b = mutation(a, matrix, cost, chanceMut)
        #println("b: ", b)
    end
    cd("../")
end

expPop(fnames)

#===
#Fuction crossOver
x1 = [1, 1, 1, 1, 1, 1, 1, 1]
x2 = [2, 2, 2, 2, 2, 2, 2, 2]
cuts = [2, 4, 6]

function crossOver(A, B, cuts)

   fils = Vector{Array{Int64,1}}(undef,2^(length(cuts)+1))
   println("ini:\n" ,fils)

   k=2

   m = length(fils)/2
   for i in 1:length(fils)
       fils[i] = []
       if i > m
           fils[i] = vcat(fils[i], B[1:(cuts[1])])
       else
           fils[i] = vcat(fils[i], A[1:(cuts[1])])
       end
   end
   println("x=0 \n",fils)

   for i in 1:length(cuts)-1
       println("i= ",i)
       #println(fils)
       k = k*2

              for j in 1:k #partie du tableau
                   for l in 1:Int64(length(fils)/k) #nbr d'éléments changé
                       m = l+(j-1)*Int64(length(fils)/k)
                       if j%2 == 1
                           fils[m] = vcat(fils[m], A[cuts[i]+1:(cuts[i+1])])
                       else
                           fils[m] = vcat(fils[m], B[cuts[i]+1:(cuts[i+1])])
                       end
                   end
              end

       println(fils)
   end

   println("fin")
   for j in 1:length(fils)
       if j % 2 == 1
           fils[j] = vcat(fils[j], A[(cuts[end]+1):end])
       else
           fils[j] = vcat(fils[j], B[(cuts[end]+1):end])
       end
   end
   println(fils)
end

crossOver(x1, x2, cuts)
===#

#===

DM2_2 après edit

include("DM1_1.jl")
include("DM2_1.jl")
include("DM1_2.jl")

#======================================================================#
function ReactiveGRASP(
    matrix, #matrice de taille m*n representant les condion de notre SPP
    cost, #liste des couts de taille n de notre SPP
    n, #nombre de variable de notre SPP
    m, #nombre de condtion de notre SPP
    ite, #nombre de tirage au sort de alpha avant recalcul des probabilités
    coupe, #nombre de coupe du segment [0,1], si on à pas de liste alpha personalisé
    alphaset, #permet de passer une liste de alpha personnelle
    temps #ressource en seconde alloué a notre reactive-GRASP
    )

    #initialisation
    (p,nb_iteration,z_cumul,zBest,zWorst) = intialiser(matrix,cost, n, m, ite, coupe, alphaset)
    liste_alpha = deepcopy(p)
    evol_p = Float64[]

    liste_zmax = Int64[]
    liste_zavg = Float64[]
    liste_zmin = Int64[]

    t=time()
    z_global = zeros(Int64, length(p))
    ite_global = zeros(Int64, length(p))
    nb_boucle = 0

    while (time()-t <= temps)
        append!(evol_p,p) #MaJ de notre historique de probabilité
        cpt=1
        nb_boucle += 1
        #On s'assure que chaque alpha s'exprime au moins une fois.
        for i in 1:length(p)
            (SOL,z, crts) = GRASP(cost, matrix, n, m, liste_alpha[i])
            (SOL, z) = exchange1_1(SOL,n,m,cost,crts,matrix)
            z_cumul[i] += z
            if z < zWorst
                zWorst = z
            elseif z > zBest
                zBest = z
            end
        end #fin for
        while (cpt <= ite)
            #Selection du alpha
            prob = rand(Float64)
            alpha_choisit = choix_alpha(p,prob)
            #On lance GRASP avec cet alpha
            (SOL, z, crts) = GRASP(cost, matrix, n, m, liste_alpha[alpha_choisit])
            #Amelioration
            (SOL, z) = exchange1_1(SOL,n,m,cost,crts,matrix)
            #Réinitialisation
            nb_iteration[alpha_choisit] += 1
            z_cumul[alpha_choisit] += z
            #Mise à jours
            if z > zBest
                zBest = z
            end #fin if
            if z < zWorst
                zWorst = z
            end #fin if
            #Incrément
            cpt = cpt+1
        end #Fin while
        #On recalcul les probabilitées
        recalcul_p!(p,z_cumul,zBest,zWorst,nb_iteration,evol_p)
        #On sovegarde le nombre d'itération et les valeurs de z
        for i in 1:length(p)
            z_global[i] = z_global[i] + z_cumul[i]
            ite_global[i] = ite_global[i] + nb_iteration[i]
        end

        #Calcul de zAvg
        moyenne_global=zeros(Float64,length(p))
        for i in 1:length(p)
            moyenne_global[i] = z_global[i]/ite_global[i]
        end
        zAvg = sum(moyenne_global)/length(p)

        #Push de zMin/Avg/Max dans leurs liste (pour les plots)
        push!(liste_zmax,zBest)
        push!(liste_zavg,zAvg)
        push!(liste_zmin,zWorst)

        nb_iteration = ones(Int64, length(p))
        z_cumul = zeros(Int64, length(p))

    end #fin while
    #Calcul de zAvg
    moyenne_global=zeros(Float64,length(p))
    for i in 1:length(p)
        moyenne_global[i] = z_global[i]/ite_global[i]
    end
    zAvg = sum(moyenne_global)/length(p)

    println("zBest: ", zBest,"   zAvg:  ", zAvg, "    zWorst: ", zWorst , " nombre de recalcul de p: ", nb_boucle)
#    println("liste_zavg: ", liste_zavg, "\n\n liste_zmax:  ", liste_zmax, "\n\n liste_zmin: ", liste_zmin) #A decomenter si l'on souhaite afficehr les évolutions des solutions
#    println(evol_p) #A decommenter si l'on souhaite afficher l'évolution des probabilités
    return(evol_p)
end #fin reactive-GRASP

#=======================================#
function intialiser(matrix, cost, n, m, ite, coupe, alphaset) #initialisation des variables
    p = Float64[]
    if alphaset == 0 #On verifie si on posséde ou non un set
        if coupe >= 1 #On verifie que les coupes sont admissibles
            for i in 1:coupe
                push!(p,i/coupe)
            end #fin for
        end #fin if
    else #on initialise le alphaset
        p = alphaset
    end #fin if

    nb_iteration = ones(Int64, length(p)) #On s'assurera plus tard que tous les alpha s'esprime au moins une fois
    z_cumul = zeros(Int64, length(p)) #Sera une liste de stockage pour le recalcul des probabilités

    (SOL,z) =Glouton(cost, matrix, n, m) #Initialisation d'une solution de base
    zBest = z
    zWorst = z

    return(p,nb_iteration,z_cumul,zBest,zWorst)
end #fin initialiser

#=======================================#
function recalcul_p!(p,z_cumul,zBest,zWorst,nb_iteration,evol_p)
    #initialisation
    q=zeros(Float64,length(p))
    somme_q=0

    for i in 1:length(p)
        moyenne = (z_cumul[i]/nb_iteration[i])
        q[i] = (moyenne-zWorst)/(zBest-zWorst)
        somme_q += q[i]
    end
    for i in 1:length(q)
        p[i] = q[i]/somme_q
    end

    for i in 2:length(p)-1 #On additionne les proabilités entre elles
        p[i] += p[i-1]
    end
    p[length(p)] = 1 #On s'assure qu'il n'y ai pas d'erreur d'arrondie pour 1
end #fin recalcul_p!

#===========================================#
function choix_alpha(p,prob)
    for i in 1:length(p)
        if prob < p[i]
            return(i)
        elseif i==length(p)
            return(i)
        end #fin if
    end #fin for
end #fin choix_alpha
===#

#===
# DM2_2 avant édit:
include("DM1_1.jl")
include("DM2_1.jl")
include("DM1_2.jl")

#======================================================================#
function ReactiveGRASP(
    matrix, #matrice de taille m*n representant les condion de notre SPP
    cost, #liste des couts de taille n de notre SPP
    n, #nombre de variable de notre SPP
    m, #nombre de condtion de notre SPP
    ite, #nombre de tirage au sort de alpha avant recalcul des probabilités
    coupe, #nombre de coupe du segment [0,1], si on à pas de liste alpha personalisé
    alphaset, #permet de passer une liste de alpha personnelle
    temps #ressource en seconde alloué a notre reactive-GRASP
    )

    #initialisation
    (p,nb_iteration,z_cumul,zBest,zWorst) = intialiser(matrix,cost, n, m, ite, coupe, alphaset)
    liste_alpha = deepcopy(p)
    evol_p=Float64[]
    t=time()
    z_global = zeros(Int64, length(p))
    ite_global = zeros(Int64, length(p))
    nb_boucle = 0

    while (time()-t <= temps)
        append!(evol_p,p) #MaJ de notre historique de probabilité
        cpt=1
        nb_boucle += 1
        #On s'assure que chaque alpha s'exprime au moins une fois.
        for i in 1:length(p)
            (SOL,z, crts) = GRASP(cost, matrix, n, m, liste_alpha[i])
            (SOL, z) = exchange1_1(SOL,n,m,cost,crts,matrix)
            z_cumul[i] += z
            if z < zWorst
                zWorst = z
            elseif z > zBest
                zBest = z
            end
        end #fin for
        while (cpt <= ite)
            #Selection du alpha
            prob = rand(Float64)
            alpha_choisit = choix_alpha(p,prob)
            #On lance GRASP avec cet alpha
            (SOL, z, crts) = GRASP(cost, matrix, n, m, liste_alpha[alpha_choisit])
            #Amelioration
            (SOL, z) = exchange1_1(SOL,n,m,cost,crts,matrix)
            #Réinitialisation
            nb_iteration[alpha_choisit] += 1
            z_cumul[alpha_choisit] += z
            #Mise à jours
            if z > zBest
                zBest = z
            end #fin if
            if z < zWorst
                zWorst = z
            end #fin if
            #Incrément
            cpt = cpt+1
        end #Fin while
        #On recalcul les probabilitées
        recalcul_p!(p,z_cumul,zBest,zWorst,nb_iteration,evol_p)
        #On sovegarde le nombre d'itération et les valeurs de z
        for i in 1:length(p)
            z_global[i] = z_global[i] + z_cumul[i]
            ite_global[i] = ite_global[i] + nb_iteration[i]
        end

        nb_iteration = ones(Int64, length(p))
        z_cumul = zeros(Int64, length(p))

    end #fin while
    #Calcul de aAvg
    moyenne_global=zeros(Float64,length(p))
    for i in 1:length(p)
        moyenne_global[i] = z_global[i]/ite_global[i]
    end
    zAvg = sum(moyenne_global)/length(p)

    println("zBest: ", zBest,"   zAvg:  ", zAvg, "    zWorst: ", zWorst , " nombre de recalcul de p: ", nb_boucle)
#    println(evol_p) #A decommenter si l'on souhaite afficher l'évolution des probabilités
    return(evol_p)
end #fin reactive-GRASP

#=======================================#
function intialiser(matrix, cost, n, m, ite, coupe, alphaset) #initialisation des variables
    p = Float64[]
    if alphaset == 0 #On verifie si on posséde ou non un set
        if coupe >= 1 #On verifie que les coupes sont admissibles
            for i in 1:coupe
                push!(p,i/coupe)
            end #fin for
        end #fin if
    else #on initialise le alphaset
        p = alphaset
    end #fin if

    nb_iteration = ones(Int64, length(p)) #On s'assurera plus tard que tous les alpha s'esprime au moins une fois
    z_cumul = zeros(Int64, length(p)) #Sera une liste de stockage pour le recalcul des probabilités

    (SOL,z) =Glouton(cost, matrix, n, m) #Initialisation d'une solution de base
    zBest = z
    zWorst = z

    return(p,nb_iteration,z_cumul,zBest,zWorst)
end #fin initialiser

#=======================================#
function recalcul_p!(p,z_cumul,zBest,zWorst,nb_iteration,evol_p)
    #initialisation
    q=zeros(Float64,length(p))
    somme_q=0

    for i in 1:length(p)
        moyenne = (z_cumul[i]/nb_iteration[i])
        q[i] = (moyenne-zWorst)/(zBest-zWorst)
        somme_q += q[i]
    end
    for i in 1:length(q)
        p[i] = q[i]/somme_q
    end

    for i in 2:length(p)-1 #On additionne les proabilités entre elles
        p[i] += p[i-1]
    end
    p[length(p)] = 1 #On s'assure qu'il n'y ai pas d'erreur d'arrondie pour 1
end #fin recalcul_p!

#===========================================#
function choix_alpha(p,prob)
    for i in 1:length(p)
        if prob < p[i]
            return(i)
        elseif i==length(p)
            return(i)
        end #fin if
    end #fin for
end #fin choix_alpha

===#

#==
#DM2_2 après edition

include("DM1_1.jl")
include("DM2_1.jl")
include("DM1_2.jl")

#======================================================================#
function ReactiveGRASP(
    matrix, #matrice de taille m*n representant les condion de notre SPP
    cost, #liste des couts de taille n de notre SPP
    n, #nombre de variable de notre SPP
    m, #nombre de condtion de notre SPP
    ite, #nombre de tirage au sort de alpha avant recalcul des probabilités
    coupe, #nombre de coupe du segment [0,1], si on à pas de liste alpha personalisé
    alphaset, #permet de passer une liste de alpha personnelle
    temps #ressource en seconde alloué a notre reactive-GRASP
    )

    #initialisation
    (p,nb_iteration,z_cumul,zBest,zWorst) = intialiser(matrix,cost, n, m, ite, coupe, alphaset)
    liste_alpha = deepcopy(p)
    evol_p=Float64[]
    t=time()
    z_global = zeros(Int64, length(p))
    ite_global = zeros(Int64, length(p))
    nb_boucle = 0
#    println("liste alpha1: ", liste_alpha)

    while (time()-t <= temps)
        append!(evol_p,p) #MaJ de notre historique de probabilité
        cpt=1
        nb_boucle += 1
        #On s'assure que chaque alpha s'exprime au moins une fois.
        for i in 1:length(p)
            (SOL,z, crts) = GRASP(cost, matrix, n, m, liste_alpha[i])
            (SOL, z) = exchange1_2(SOL,n,m,cost,crts,matrix)
            z_cumul[i] += z
            if z < zWorst
                zWorst = z
            elseif z > zBest
                zBest = z
            end
        end #fin for
        while (cpt <= ite)
            #Selection du alpha
            prob = rand(Float64)
            alpha_choisit = choix_alpha(p,prob)
            #On lance GRASP avec cet alpha
            (SOL, z, crts) = GRASP(cost, matrix, n, m, liste_alpha[alpha_choisit])
            #Amelioration
            (SOL, z) = exchange1_2(SOL,n,m,cost,crts,matrix)
            #Réinitialisation
            nb_iteration[alpha_choisit] += 1
            z_cumul[alpha_choisit] += z
            #Mise à jours
            if z > zBest
                zBest = z
            end #fin if
            if z < zWorst
                zWorst = z
            end #fin if
            #Incrément
            cpt = cpt+1
        end #Fin while
        #On recalcul les probabilitées
        recalcul_p!(p,z_cumul,zBest,zWorst,nb_iteration,evol_p)
        #On sovegarde le nombre d'itération et les valeurs de z
        for i in 1:length(p)
            z_global[i] = z_global[i] + z_cumul[i]
            ite_global[i] = ite_global[i] + nb_iteration[i]
        end

        nb_iteration = ones(Int64, length(p))
        z_cumul = zeros(Int64, length(p))

    end #fin while
    #Calcul de aAvg
    moyenne_global=zeros(Float64,length(p))
    for i in 1:length(p)
        moyenne_global[i] = z_global[i]/ite_global[i]
    end
    zAvg = sum(moyenne_global)/length(p)

    println("zBest: ", zBest,"   zAvg:  ", zAvg, "    zWorst: ", zWorst , " nombre de recalcul de p: ", nb_boucle)
#    println(evol_p) #A decommenter si l'on souhaite afficher l'évolution des probabilités
    return(evol_p)
end #fin reactive-GRASP

#=======================================#
function intialiser(matrix, cost, n, m, ite, coupe, alphaset) #initialisation des variables
    p = Float64[]
    if alphaset == 0 #On verifie si on posséde ou non un set
        if coupe >= 1 #On verifie que les coupes sont admissibles
            for i in 1:coupe
                push!(p,i/coupe)
            end #fin for
        end #fin if
    else #on initialise le alphaset
        p = alphaset
    end #fin if

    nb_iteration = ones(Int64, length(p)) #On s'assurera plus tard que tous les alpha s'esprime au moins une fois
    z_cumul = zeros(Int64, length(p)) #Sera une liste de stockage pour le recalcul des probabilités

    (SOL,z) =Glouton(cost, matrix, n, m) #Initialisation d'une solution de base
    zBest = z
    zWorst = z

    return(p,nb_iteration,z_cumul,zBest,zWorst)
end #fin initialiser

#=======================================#
function recalcul_p!(p,z_cumul,zBest,zWorst,nb_iteration,evol_p)
    #initialisation
    q=zeros(Float64,length(p))
    somme_q=0

    for i in 1:length(p)
        moyenne = (z_cumul[i]/nb_iteration[i])
        q[i] = (moyenne-zWorst)/(zBest-zWorst)
        somme_q += q[i]
    end
    for i in 1:length(q)
        p[i] = q[i]/somme_q
    end

    for i in 2:length(p)-1 #On additionne les proabilités entre elles
        p[i] += p[i-1]
    end
    p[length(p)] = 1 #On s'assure qu'il n'y ai pas d'erreur d'arrondie pour 1
end #fin recalcul_p!

#===========================================#
function choix_alpha(p,prob)
    for i in 1:length(p)
        if prob < p[i]
            return(i)
        elseif i==length(p)
            return(i)
        end #fin if
    end #fin for
end #fin choix_alpha
==#

#==
#DM2_2 avant édition
include("DM1_1.jl")
include("DM2_1.jl")
include("DM1_2.jl")

#======================================================================#
function ReactiveGRASP(
    matrix, #matrice de taille m*n representant les condion de notre SPP
    cost, #liste des couts de taille n de notre SPP
    n, #nombre de variable de notre SPP
    m, #nombre de condtion de notre SPP
    ite, #nombre de tirage au sort de alpha avant recalcul des probabilités
    coupe, #nombre de coupe du segment [0,1], si on à pas de liste alpha personalisé
    alphaset, #permet de passer une liste de alpha personnelle
    temps #ressource en seconde alloué a notre reactive-GRASP
    )

    #initialisation
    (p,nb_iteration,z_cumul,zBest,zWorst) = intialiser(matrix,cost, n, m, ite, coupe, alphaset)
    evol_p=Float64[]
    t=time()
    z_global = zeros(Int64, length(p))
    ite_global = zeros(Int64, length(p))
    nb_boucle = 0

    while (time()-t <= temps)
        append!(evol_p,p) #MaJ de notre historique de probabilité
        cpt=1
        nb_boucle += 1
        #On s'assure que chaque alpha s'exprime au moins une fois.
        for i in 1:length(p)
            (SOL,z, crts) = GRASP(cost, matrix, n, m, p[i])
            z_cumul[i] += z
            if z < zWorst
                zWorst = z
            elseif z > zBest
                zBest = z
            end
        end #fin for
        while (cpt <= ite)
            #Selection du alpha
            prob = rand(Float64)
            alpha_choisit = choix_alpha(p,prob)
            #On lance GRASP avec cet alpha
            (SOL, z, crts) = GRASP(cost, matrix, n, m, p[alpha_choisit])
            #Amelioration
            (SOL, z) = exchange1_1(SOL,n,m,cost,crts,matrix)
            #Réinitialisation
            nb_iteration[alpha_choisit] += 1
            z_cumul[alpha_choisit] += z
            #Mise à jours
            if z > zBest
                zBest = z
            end #fin if
            if z < zWorst
                zWorst = z
            end #fin if
            #Incrément
            cpt = cpt+1
        end #Fin while
        #On recalcul les probabilitées
        recalcul_p!(p,z_cumul,zBest,zWorst,nb_iteration,evol_p)
        #On sovegarde le nombre d'itération et les valeurs de z
        for i in 1:length(p)
            z_global[i] = z_global[i] + z_cumul[i]
            ite_global[i] = ite_global[i] + nb_iteration[i]
        end

        nb_iteration = ones(Int64, length(p))
        z_cumul = zeros(Int64, length(p))

    end #fin while
    #Calcul de aAvg
    moyenne_global=zeros(Float64,length(p))
    for i in 1:length(p)
        moyenne_global[i] = z_global[i]/ite_global[i]
    end
    zAvg = sum(moyenne_global)/length(p)

    println("zBest: ", zBest,"   zAvg:  ", zAvg, "    zWorst: ", zWorst , " nombre de recalcul de p: ", nb_boucle)
#    println(evol_p) #A decommenter si l'on souhaite afficher l'évolution des probabilités
    return(evol_p)
end #fin reactive-GRASP

#=======================================#
function intialiser(matrix, cost, n, m, ite, coupe, alphaset) #initialisation des variables
    p = Float64[]
    if alphaset == 0 #On verifie si on posséde ou non un set
        if coupe >= 1 #On verifie que les coupes sont admissibles
            for i in 1:coupe
                push!(p,i/coupe)
            end #fin for
        end #fin if
    else #on initialise le alphaset
        p = alphaset
    end #fin if

    nb_iteration = ones(Int64, length(p)) #On s'assurera plus tard que tous les alpha s'esprime au moins une fois
    z_cumul = zeros(Int64, length(p)) #Sera une liste de stockage pour le recalcul des probabilités

    (SOL,z) =Glouton(cost, matrix, n, m) #Initialisation d'une solution de base
    zBest = z
    zWorst = z

    return(p,nb_iteration,z_cumul,zBest,zWorst)
end #fin initialiser

#=======================================#
function recalcul_p!(p,z_cumul,zBest,zWorst,nb_iteration,evol_p)
    #initialisation
    q=zeros(Float64,length(p))
    somme_q=0
#    println("p:  ", p)
#    println("zcummul:  ", z_cumul)
#    println("nb_ite;   ", nb_iteration)
#    println("zBest: ", zBest, "    zWorst: ", zWorst)

    for i in 1:length(p)
        moyenne = (z_cumul[i]/nb_iteration[i])
        q[i] = (moyenne-zWorst)/(zBest-zWorst)
#        println(i, " moyenne: ", moyenne, "   q[i] : " , q[i])
        somme_q += q[i]
    end
#    println("--------------------")
    for i in 1:length(q)
        p[i] = q[i]/somme_q
    end

    for i in 2:length(p)-1 #On additionne les proabilités entre elles
        p[i] += p[i-1]
    end
    p[length(p)] = 1 #On s'assure qu'il n'y ai pas d'erreur d'arrondie pour 1
end #fin recalcul_p!

#===========================================#
function choix_alpha(p,prob)
    for i in 1:length(p)
        if prob < p[i]
            return(i)
        elseif i==length(p)
            return(i)
        end #fin if
    end #fin for
end #fin choix_alpha
==#

#=
function exchange1_1(solution,n,m,couts,crts,matrix)
    x_best = Solution(solution,calculz(solution,couts,n))
    # notre boucle k
    for i in 1:n
        if  x_best.x[i]  == 1
            x_prime = deepcopy(x_best)
            x_prime.x[i] = 0
            x_prime.objectif = calculz(x_prime.x,couts,n)
            # notre boucle p
            for j = 1:n
                if x_prime.x[j] == 0 && j != i # j != i car ça sers à rien de remettre une variable enlevée
                    x_seconde = deepcopy(x_prime)
                    x_seconde.x[j] = 1
                    x_seconde.objectif = calculz(x_prime.x,couts,n)
                    #on met à jour notre meilleur Solution
                    if x_seconde.objectif > x_best.objectif
                        x_best = deepcopy(x_seconde)
                    end
                end
            end
        end
    end
    #x,objectif= Solution.x
    return(x_best.x,x_best.objectif)
end
=#

#Reactive grasp final

#=
include("DM1_1.jl")
include("DM2_1.jl")
function ReactiveGRASP(matrix,cost, n, m, ite, coupe,temps)
#    println("^^^^^^^^ Debut R-GRASP ^^^^^^^^")
    #initialisation
    (p,nb_iteration,z_cumul,zBest,zWorst) = intialiser(matrix,cost, n, m, ite, coupe)
#    println("valeurs initiales: ")
#    println("p: ", p)
#    println("nb_iteration: ", nb_iteration)
#    println("z_cumul: ", z_cumul)
#    println("zBest: ", zBest , "  zWorst: ", zWorst)
    evol_p=Float64[]
    t=time()
    while (time()-t <= temps)
        cpt = 1
        append!(evol_p,p)
        while (cpt <= ite)
            for i in 1:length(p)
                (SOL,z) = GRASP(cost, matrix, n, m, p[i])
                z_cumul[i] += z
            end
            cpt = cpt+1
            prob=rand(Float64)
            alpha_choisit = choix_alpha(p,prob)
#            println("alpha_choisit: ", alpha_choisit, "  p: ", p)
            (SOL,z) = GRASP(cost, matrix, n, m, p[alpha_choisit])
            nb_iteration[alpha_choisit] += 1
            z_cumul[alpha_choisit] += z
            if z > zBest
                zBest = z
            end
            if z < zWorst
                zWorst = z
            end
#            println(" ============= \n ite: ",cpt)
        end
#        println("zBest: ", zBest, "   zWorst: ", zWorst)
#        println("  z_cumul: ",z_cumul)
#        println( "    nb_iteration : ", nb_iteration , "    p: ", p)
        recalcul_p!(p,z_cumul,zBest,zWorst,nb_iteration,evol_p)
        nb_iteration = ones(Int64, length(p))
        z_cumul = zeros(Int64, length(p))
    end
    println("^^^^^^^^ Fin ReactiveGRASP ^^^^^^^^")
    println("zBest: ", zBest, "    zWorst: ", zWorst)
    println(evol_p)
end
#=======================================#
function intialiser(matrix,cost, n, m, ite, coupe)
    p = Float64[]
    for i in 1:coupe
        push!(p,i/coupe)
    end
    nb_iteration = ones(Int64, length(p))
    z_cumul = zeros(Int64, length(p))
    (SOL,z) =Glouton(cost, matrix, n, m)
    zBest = z
    zWorst = z
    return(p,nb_iteration,z_cumul,zBest,zWorst)
end
#=======================================#
function recalcul_p!(p,z_cumul,zBest,zWorst,nb_iteration,evol_p)
    q=zeros(Float64,length(p))
    somme_q=0
#    println("q: ", q)
#    println("nb_iteration: ", nb_iteration)
    for i in 1:length(p)
#        println("q: ", q, "   i:", i)
#        if nb_iteration[i]!=0
#            println("z_cumul[i]: ", z_cumul[i],"   nb_iteration[i]: ", nb_iteration[i] )
            moyenne=(z_cumul[i]/nb_iteration[i])
#            println("moyenne: ", moyenne)
#        else
#            moyenne=0
#        end
#        if moyenne>0
            q[i]=(moyenne-zWorst)/(zBest-zWorst)
#            println("q[i]: ", q[i])
#        else
#            q[i]= zWorst/(zBest-zWorst)
#        end
        somme_q+=q[i]
    end
#    println("q: ", q, "      somme_q", somme_q)
    for i in 1:length(q)
        p[i]=q[i]/somme_q
    end
    for i in 2:length(p)-1
        p[i]+=p[i-1]
    end
    p[length(p)]=1
#    println("p: ", p)
end
#=======================================#
function choix_alpha(p,prob)
    for i in 1:length(p)
        if prob < p[i]
            return(i)
        elseif i==length(p)
            return(i)
        end
    end
end
=#
#=
#DM2_1
# =========================================================================== #
# =========================================================================== #
#Implementing an x0 viable solution huristic with a gluton method
#receiving an array of lenght()=m , a matrix of size m*n and thoose size
#returing a Bool array of lenght=n
#Asked question:
#Mettre en place une heuristique de construction d’une x0 réalisable.
function RandomGlouton(cost, matrix, n, m, alpha)
    #Creating a set of lines that will be avaluated
    actif= zeros(Bool, m) #if actif[j]=0 the line will be avaluated
    stop1= ones(Bool,m)
    #Creation the an array of activated variables
    varactive = ones(Bool, n)
    stop2= zeros(Bool , n)
#    println("\n varactive: ", varactive, "\n stop2: ", stop2)
    #creating my utility array for my m variables
    util = zeros(Float64, n)
    #initialisation de la Solution
    SOL = zeros(Float64, n)
#    println( "\n Matrix: ", matrix, "\n Cost: ", cost,"\n n= ", n, "   m= ", m,"\n actif: ", actif, "\n stop: ", stop1, "\n util: ", util, "\n SOL: ", SOL, "\n \n")
    ite = 0
    #Création de la solution
    while actif!=stop1 && varactive!=stop2
#      println("\n ++++++++++++++++++++++++++++++++++++++++")
#      println("\n itération: ", ite)
      #println("\n actif : ", actif, "\n stop1 : " , "\n varactive : " , varactive , "\n stop2 : ")
#      println("\n ++++++++++++++++++++++++++++++++++++++++")
        #Foction d'utilité
        util = Utilite(cost, matrix, actif, n, m , varactive, stop1, stop2)
        #Choix parmis les candidats de util
#        PosCandidat::Int64
#        PosCandidat = PosMax(util,n)
        PosCandidat::Int64 = choixcandidat(util, alpha)
        #On ajoute le candidat à la solution
        SOL[PosCandidat] = 1
        #Desactive! le candidat selectionné
        Desactive!(PosCandidat, matrix, actif, m, varactive,n)
        ite=ite+1
    end
    #println(calculz(SOL,cost,n))
    #return(SOL)
    Z = calculz(SOL,cost,n)
    println("Solution avant améliration: " , Z)
#    return(SOL, actif, Z)
    return(SOL, Z)
end
# =========================================================================== #
#Detremine an utility  based on an active (actif) set of matrix's lines
function Utilite(cost, matrix, actif, n, m , varactive, stop1, stop2)
#    println("==========================")
    util = zeros(Float64, n) #réinitialisation du vecteur
    #On each column of matrix
    for j=1:n
            if varactive[j] == 1
                    #For each line
                    for i=1:m
                        #checking if the line is active
                        if actif[i]==0 #&& i <= m
                            K=matrix[i,j]
                            util[j]=util[j]+K
#                            println("====== \n", "i: ", i ,"    j: ", j , "   k: ", K )
#                            println("\n varactive: ", varactive)
#                            println("\n actif : ", actif)
#                            println("\n util : ", util)
                        end
                    end
                # dividing the number if iterations of the variable j by its cost (not a zero)
                if util[j]!=false #On évide de divisé par 0...
#                    println("\n util avant modif: ", util)
                    util[j] =  cost[j] / util[j]
#                    println("\n util après modif: ", util)
                else
                    varactive[j] = 0
                end
            end
    end
#    println("\n Util: ", util)
#    println("\n \n ===================Utilite fini =============")
    return util
end
# =========================================================================== #
#=
function PosMax(util,n) #On choisie un candidat parmie les différents coûts, par ordre lexicographique
#println("%%%%%%%%%%%%%%%%%%%%")
#    Pos::Int64
    Pos=0
    ValCan=0.0
    for i=1:n
        if util[i] > ValCan
            ValCan = util[i]
            Pos = i
        end
    end
    #println("\n \n %%%%%% Pos max fini %%%%% \n pos: ", Pos)
    return Pos
end
=#
# =========================================================================== #
function Desactive!(PosCandidat, matrix, actif, m , varactive , n) #On désactive les lignes où est le candidat
#println("\n======================= desactive ==============================")
#println("~~~~~~~~~~~~~~~~~~~~~~~~")
    for i=1:m
#        println("\n Boucle i: ", i)
        if matrix[i,PosCandidat] == 1
#            println("\n If matrix[i,PosCandidat] == 1: " , matrix[i,PosCandidat])
            actif[i] = 1
#            println("\n actif[i] = 1: ", actif[i])
            for j=1:n
#                println("\n for j=1:n ; j: ", j)
                if matrix[i,j] ==1
#                    println("\n if matrix[i,j] ==1 :", matrix[i,j])
                    varactive[j] = 0
#                    println("\n varactive[j] = 0: ", varactive)
                end
            end
        end
    end
#    println("\n \n ~~~~~~~~~Desactive fini! ~~~~~~~\n ")
#    println("varactive: ", varactive)
#    println("actif: ", actif)
end
#=========================================================================#
function calculz(x,costs,m)
    z = 0
    for i in 1:m
        z+= x[i]*costs[i]
    end
    return z
end
#==========================================#
function choixcandidat(util, alpha)
    max = maximum(util)
    min = minimum(util)
#    Rut = Array{Float64}[]
    Rut = Float64[]
#    println("util: ", util, "\n type de util: ", typeof(util))
#    println("min: ", min, " max: ", max, " Rut: ", Rut)
    cpt::Int=1
    for i in 1:length(util)
#        println("debut for: ", i)
        if util[i]>= min+alpha*(max-min)
            push!(Rut,i)
        end
    end
    prob=rand(1:length(Rut))
#    println("fini, Rut: ", Rut, " Prob: ", prob)
    return(Rut[prob])
end
=#

#==
#Version 0
function choixcandidat(util, alpha)
    max = maximum(util)
    min = minimum(util)
#    Rut = Array{Float64}[]
    Rut = Float64[]
#    println("util: ", util, "\n type de util: ", typeof(util))
#    println("min: ", min, " max: ", max, " Rut: ", Rut)
    cpt::Int=1
    for i in 1:length(util)
#        println("debut for: ", i)
        if util[i]>= min+alpha*(max-min)
            push!(Rut,util[i])
        end
    end
    prob=rand(1:length(Rut))
#    println("fini, Rut: ", Rut, " Prob: ", prob)
    return(Rut[prob])
end
=#
#=
#Test run
z = Array{Float64}(undef, 42)
alpha = 0.9
println("z: ", z, " alpha : ", alpha)
cand=choixcandidat(z,alpha)
println("\n candidat choisit: ",cand)
==#
#=========================#
#=
DM1_1
# =========================================================================== #
# =========================================================================== #
#Implementing an x0 viable solution huristic with a gluton method
#receiving an array of lenght()=m , a matrix of size m*n and thoose size
#returing a Bool array of lenght=n
#Asked question:
#Mettre en place une heuristique de construction d’une x0 réalisable.
function Glouton(cost, matrix, n, m)
    #Creating a set of lines that will be avaluated
    actif= zeros(Bool, m) #if actif[j]=0 the line will be avaluated
    stop1= ones(Bool,m)
    #Creation the an array of activated variables
    varactive = ones(Bool, n)
    stop2= zeros(Bool , n)
#    println("\n varactive: ", varactive, "\n stop2: ", stop2)
    #creating my utility array for my m variables
    util = zeros(Float64, n)
    #initialisation de la Solution
    SOL = zeros(Float64, n)
#    println( "\n Matrix: ", matrix, "\n Cost: ", cost,"\n n= ", n, "   m= ", m,"\n actif: ", actif, "\n stop: ", stop1, "\n util: ", util, "\n SOL: ", SOL, "\n \n")
    ite = 0
    #Création de la solution
    while actif!=stop1 && varactive!=stop2
#      println("\n ++++++++++++++++++++++++++++++++++++++++")
#      println("\n itération: ", ite)
      #println("\n actif : ", actif, "\n stop1 : " , "\n varactive : " , varactive , "\n stop2 : ")
#      println("\n ++++++++++++++++++++++++++++++++++++++++")
        #Foction d'utilité
        util = Utilite(cost, matrix, actif, n, m , varactive, stop1, stop2)
        #Choix parmis les candidats de util
#        PosCandidat::Int64
        PosCandidat = PosMax(util,n)
        #On ajoute le candidat à la solution
        SOL[PosCandidat] = 1
        #Desactive! le candidat selectionné
        Desactive!(PosCandidat, matrix, actif, m, varactive,n)
        ite=ite+1
    end
    #println(calculz(SOL,cost,n))
    #return(SOL)
    Z = calculz(SOL,cost,n)
    println("Solution avant améliration: " , Z)
#    return(SOL, actif, Z)
    return(SOL, Z)
end
# =========================================================================== #
#Detremine an utility  based on an active (actif) set of matrix's lines
function Utilite(cost, matrix, actif, n, m , varactive, stop1, stop2)
#    println("==========================")
    util = zeros(Float64, n) #réinitialisation du vecteur
    #On each column of matrix
    for j=1:n
            if varactive[j] == 1
                    #For each line
                    for i=1:m
                        #checking if the line is active
                        if actif[i]==0 #&& i <= m
                            K=matrix[i,j]
                            util[j]=util[j]+K
#                            println("====== \n", "i: ", i ,"    j: ", j , "   k: ", K )
#                            println("\n varactive: ", varactive)
#                            println("\n actif : ", actif)
#                            println("\n util : ", util)
                        end
                    end
                # dividing the number if iterations of the variable j by its cost (not a zero)
                if util[j]!=false #On évide de divisé par 0...
#                    println("\n util avant modif: ", util)
                    util[j] =  cost[j] / util[j]
#                    println("\n util après modif: ", util)
                else
                    varactive[j] = 0
                end
            end
    end
#    println("\n Util: ", util)
#    println("\n \n ===================Utilite fini =============")
    return util
end
# =========================================================================== #
function PosMax(util,n) #On choisie un candidat parmie les différents coûts, par ordre lexicographique
#println("%%%%%%%%%%%%%%%%%%%%")
#    Pos::Int64
    Pos=0
    ValCan=0.0
    for i=1:n
        if util[i] > ValCan
            ValCan = util[i]
            Pos = i
        end
    end
    #println("\n \n %%%%%% Pos max fini %%%%% \n pos: ", Pos)
    return Pos
end
# =========================================================================== #
function Desactive!(PosCandidat, matrix, actif, m , varactive , n) #On désactive les lignes où est le candidat
#println("\n======================= desactive ==============================")
#println("~~~~~~~~~~~~~~~~~~~~~~~~")
    for i=1:m
#        println("\n Boucle i: ", i)
        if matrix[i,PosCandidat] == 1
#            println("\n If matrix[i,PosCandidat] == 1: " , matrix[i,PosCandidat])
            actif[i] = 1
#            println("\n actif[i] = 1: ", actif[i])
            for j=1:n
#                println("\n for j=1:n ; j: ", j)
                if matrix[i,j] ==1
#                    println("\n if matrix[i,j] ==1 :", matrix[i,j])
                    varactive[j] = 0
#                    println("\n varactive[j] = 0: ", varactive)
                end
            end
        end
    end
#    println("\n \n ~~~~~~~~~Desactive fini! ~~~~~~~\n ")
#    println("varactive: ", varactive)
#    println("actif: ", actif)
end
#=========================================================================#
function calculz(x,costs,m)
    z = 0
    for i in 1:m
        z+= x[i]*costs[i]
    end
    return z
end
=#


text:
# MESSAGING DICTIONARY SYNCHRONISATION

function collectmsgs(msgname::Symbol)
    @sync for j in Main.eval( :(keys($(msgname))) )
        @async begin
        val = remotecall_fetch(Main.eval, j, Expr(:call, :getindex, msgname, j))
        Main.eval(Expr(:call, :setindex!, msgname, val, j))
        end
    end
end

function collectmsgs(msgname::Symbol, msglocal::Dict)
    @sync for j in keys(msglocal)
        @async begin
        msglocal[j] = remotecall_fetch(Main.eval, j, Expr(:call, :getindex, msgname, j))
        end
    end
    msglocal
end

function collectmsgs(msgname::Symbol, pids::Array{Int64, 1})
    msglocal = Dict{Int64, Any}()
    @sync for j in pids
        @async begin
        msglocal[j] = remotecall_fetch(Main.eval, j, Expr(:call, :getindex, msgname, j))
        end
    end
    msglocal
end

function swapmsgs(pids::Array{Int64,1}, msgname::Symbol)
    @sync for pid in pids
         @async remotecall_wait(collectmsgs, pid, msgname)
    end
end

function swapmsgs(msgname::Symbol)
    pids = workers()
    swapmsgs(pids, msgname)
end

###  Manipulation utilities

function stitch(pids::Array{Int64,1}, expr_::Doable, cattype::Function)
    parts = reap(pids, expr_)
    reduce(cattype, [parts[k] for k in sort(collect(keys(parts)))])
end

function stitch(pid::Int64, expr_::Doable, cattype::Function)
    stitch([pid], expr_, cattype)
end

function stitch(pids::Array{Int64,1}, expr_::Doable)
    stitch(pids, expr_, vcat)
end

function stitch(pid::Int64, expr_::Doable)
    stitch([pid], expr_, vcat)
end

function stitch(expr_::Doable)
    pids = workers()
    stitch(pids, expr_, vcat)
end

ext: jl


text:
"""
Transient analysis for CTMC
"""

"""
tran(Q, x, r, ts; forward = :T, ufact = 1.01, eps = 1.0e-8, rmax = 500)

Compute the instantaneous and cumulative rewards for CTMC on time series.

instantaneous reward: x * exp(Q*t) * r for t = ts
cumulative reward: x * int_0^t exp(Q*u) * r du for t = ts

Parameters:
- Q: CTMC Kernel
- x: initial vector.
- r: reward vector.
- ts: time series
- forward: forward or backward
- ufact: uniformization factor
- eps: tolerance error for Poisson p.m.f.
- rmax: The maximum number of uniformization steps

Return value (tuple)
- instantaneous reward
- cumulative reward
- probability vector at the last time (forward is :T)
- reward vector at the initial time (forward is :N)
"""

function tran(Q::AbstractMatrix{Tv}, x::ArrayT1, r::ArrayT2, ts::AbstractVector{Tv};
    forward::Symbol=:T, ufact::Tv=Tv(1.01), eps::Tv=Tv(1.0e-8), rmax=500) where {Tv,ArrayT1<:AbstractArray{Tv},ArrayT2<:AbstractArray{Tv}}
    _tran(Q, x, r, ts, Val{forward}, ufact, eps, rmax)
end

function _tran(Q::AbstractMatrix{Tv}, x::Array{Tv,1}, r::Array{Tv,1}, ts::AbstractVector{Tv},
    ::Type{Val{:T}}, ufact::Tv, eps::Tv, rmax) where Tv
    m, n = size(Q)
    @assert m == n
    dt, maxt = itime(ts)
    P, qv = unif(Q, ufact)
    right = rightbound(qv*maxt, eps) + 1
    @assert right <= rmax "Time interval is too large. t or rmax should be changed: right = $right (rmax: $rmax)."
    prob = Vector{Tv}(undef, right+1)
    cprob = Vector{Tv}(undef, right+1)
    result = Vector{Tv}(undef, length(dt))
    cresult = Vector{Tv}(undef, length(dt))
    y0 = copy(x)
    y1 = similar(x)
    cy = zero(x)
    tmp = similar(x)
    @inbounds for k = eachindex(dt)
        right = rightbound(qv*dt[k], eps) + 1
        weight = cpoipmf!(qv*dt[k], prob, cprob; left=0, right=right)
        y1 .= Tv(0)
        tmp .= Tv(0)
        cunifstep!(:T, P, prob, cprob, (0, right), weight, qv*weight, y0, y1, tmp)
        cy .+= tmp
        result[k] = @dot(y1, r)
        cresult[k] = @dot(cy, r)
        y0 .= y1
    end
    return result, cresult, y1, cy
end

function _tran(Q::AbstractMatrix{Tv}, x::Array{Tv,1}, r::Array{Tv,1}, ts::AbstractVector{Tv},
    ::Type{Val{:N}}, ufact::Tv, eps::Tv, rmax) where Tv
    m, n = size(Q)
    @assert m == n
    dt, maxt = itime(ts)
    P, qv = unif(Q, ufact)
    right = rightbound(qv*maxt, eps) + 1
    @assert right <= rmax "Time interval is too large. t or rmax should be changed: right = $right (rmax: $rmax)."
    prob = Vector{Tv}(undef, right+1)
    cprob = Vector{Tv}(undef, right+1)
    result = Vector{Tv}(undef, length(dt))
    cresult = Vector{Tv}(undef, length(dt))
    y0 = copy(r)
    y1 = similar(r)
    cy = zero(r)
    tmp = similar(r)
    @inbounds for k = eachindex(dt)
        right = rightbound(qv*dt[k], eps) + 1
        weight = cpoipmf!(qv*dt[k], prob, cprob; left=0, right=right)
        y1 .= Tv(0)
        tmp .= Tv(0)
        cunifstep!(:N, P, prob, cprob, (0, right), weight, qv*weight, y0, y1, tmp)
        cy .+= tmp
        result[k] = @dot(x, y1)
        cresult[k] = @dot(x, cy)
        y0 .= y1
    end
    return result, cresult, y1, cy
end

function _tran(Q::AbstractMatrix{Tv}, x::Array{Tv,1}, r::ArrayT2, ts::AbstractVector{Tv},
    ::Type{Val{:T}}, ufact::Tv, eps::Tv, rmax) where {Tv,ArrayT2<:AbstractArray{Tv}}
    m, n = size(Q)
    @assert m == n
    dt, maxt = itime(ts)
    P, qv = unif(Q, ufact)
    right = rightbound(qv*maxt, eps) + 1
    @assert right <= rmax "Time interval is too large. t or rmax should be changed: right = $right (rmax: $rmax)."
    prob = Vector{Tv}(undef, right+1)
    cprob = Vector{Tv}(undef, right+1)
    result = Vector{Any}(undef, length(dt))
    cresult = Vector{Any}(undef, length(dt))
    y0 = copy(x)
    y1 = similar(x)
    cy = zero(x)
    tmp = similar(x)
    @inbounds for k = eachindex(dt)
        right = rightbound(qv*dt[k], eps) + 1
        weight = cpoipmf!(qv*dt[k], prob, cprob; left=0, right=right)
        y1 .= Tv(0)
        tmp .= Tv(0)
        cunifstep!(:T, P, prob, cprob, (0, right), weight, qv*weight, y0, y1, tmp)
        cy .+= tmp
        result[k] = r' * y1
        cresult[k] = r' * cy
        y0 .= y1
    end
    return result, cresult, y1, cy
end

function _tran(Q::AbstractMatrix{Tv}, x::ArrayT1, r::ArrayT2, ts::AbstractVector{Tv},
    ::Type{Val{:T}}, ufact::Tv, eps::Tv, rmax) where {Tv,ArrayT1<:AbstractArray{Tv},ArrayT2<:AbstractArray{Tv}}
    m, n = size(Q)
    @assert m == n
    dt, maxt = itime(ts)
    P, qv = unif(Q, ufact)
    right = rightbound(qv*maxt, eps) + 1
    @assert right <= rmax "Time interval is too large. t or rmax should be changed: right = $right (rmax: $rmax)."
    prob = Vector{Tv}(undef, right+1)
    cprob = Vector{Tv}(undef, right+1)
    xdash = x'
    result = Vector{Any}(undef, length(dt))
    cresult = Vector{Any}(undef, length(dt))
    y0 = copy(xdash)
    y1 = similar(xdash)
    cy = zero(xdash)
    tmp = similar(xdash)
    @inbounds for k = eachindex(dt)
        right = rightbound(qv*dt[k], eps) + 1
        weight = cpoipmf!(qv*dt[k], prob, cprob; left=0, right=right)
        y1 .= Tv(0)
        tmp .= Tv(0)
        cunifstep!(:T, P, prob, cprob, (0, right), weight, qv*weight, y0, y1, tmp)
        cy .+= tmp
        result[k] = y1' * r
        cresult[k] = cy' * r
        y0 .= y1
    end
    return result, cresult, y1', cy'
end

function _tran(Q::AbstractMatrix{Tv}, x::ArrayT1, r::ArrayT2, ts::AbstractVector{Tv},
    ::Type{Val{:N}}, ufact::Tv, eps::Tv, rmax) where {Tv,ArrayT1<:AbstractArray{Tv},ArrayT2<:AbstractArray{Tv}}
    m, n = size(Q)
    @assert m == n
    dt, maxt = itime(ts)
    P, qv = unif(Q, ufact)
    right = rightbound(qv*maxt, eps) + 1
    @assert right <= rmax "Time interval is too large. t or rmax should be changed: right = $right (rmax: $rmax)."
    prob = Vector{Tv}(undef, right+1)
    cprob = Vector{Tv}(undef, right+1)
    result = Vector{Any}(undef, length(dt))
    cresult = Vector{Any}(undef, length(dt))
    y0 = copy(r)
    y1 = similar(r)
    cy = zero(r)
    tmp = similar(r)
    @inbounds for k = eachindex(dt)
        right = rightbound(qv*dt[k], eps) + 1
        weight = cpoipmf!(qv*dt[k], prob, cprob; left=0, right=right)
        y1 .= Tv(0)
        tmp .= Tv(0)
        cunifstep!(:N, P, prob, cprob, (0, right), weight, qv*weight, y0, y1, tmp)
        cy .+= tmp
        result[k] = x * y1
        cresult[k] = x * cy
        y0 .= y1
    end
    return result, cresult, y1, cy
end


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

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

 Retrieves details about an application component.

# Arguments
- `application_component_id`:  The ID of the application component. The ID is unique within
  an AWS account.

"""
function get_application_component_details(
    applicationComponentId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return migrationhubstrategy(
        "GET",
        "/get-applicationcomponent-details/$(applicationComponentId)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_application_component_details(
    applicationComponentId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return migrationhubstrategy(
        "GET",
        "/get-applicationcomponent-details/$(applicationComponentId)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Retrieves a list of all the recommended strategies and tools for an application component
running on a server.

# Arguments
- `application_component_id`:  The ID of the application component. The ID is unique within
  an AWS account.

"""
function get_application_component_strategies(
    applicationComponentId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return migrationhubstrategy(
        "GET",
        "/get-applicationcomponent-strategies/$(applicationComponentId)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_application_component_strategies(
    applicationComponentId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return migrationhubstrategy(
        "GET",
        "/get-applicationcomponent-strategies/$(applicationComponentId)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Retrieves the status of an on-going assessment.

# Arguments
- `id`:  The assessmentid returned by StartAssessment.

"""
function get_assessment(id; aws_config::AbstractAWSConfig=global_aws_config())
    return migrationhubstrategy(
        "GET",
        "/get-assessment/$(id)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_assessment(
    id, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return migrationhubstrategy(
        "GET",
        "/get-assessment/$(id)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Retrieves the details about a specific import task.

# Arguments
- `id`:  The ID of the import file task. This ID is returned in the response of
  StartImportFileTask.

"""
function get_import_file_task(id; aws_config::AbstractAWSConfig=global_aws_config())
    return migrationhubstrategy(
        "GET",
        "/get-import-file-task/$(id)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_import_file_task(
    id, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return migrationhubstrategy(
        "GET",
        "/get-import-file-task/$(id)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Retrieves your migration and modernization preferences.

"""
function get_portfolio_preferences(; aws_config::AbstractAWSConfig=global_aws_config())
    return migrationhubstrategy(
        "GET",
        "/get-portfolio-preferences";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_portfolio_preferences(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return migrationhubstrategy(
        "GET",
        "/get-portfolio-preferences",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Retrieves overall summary including the number of servers to rehost and the overall number
of anti-patterns.

"""
function get_portfolio_summary(; aws_config::AbstractAWSConfig=global_aws_config())
    return migrationhubstrategy(
        "GET",
        "/get-portfolio-summary";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_portfolio_summary(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return migrationhubstrategy(
        "GET",
        "/get-portfolio-summary",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Retrieves detailed information about the specified recommendation report.

# Arguments
- `id`:  The recommendation report generation task id returned by
  StartRecommendationReportGeneration.

"""
function get_recommendation_report_details(
    id; aws_config::AbstractAWSConfig=global_aws_config()
)
    return migrationhubstrategy(
        "GET",
        "/get-recommendation-report-details/$(id)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_recommendation_report_details(
    id, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return migrationhubstrategy(
        "GET",
        "/get-recommendation-report-details/$(id)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Retrieves detailed information about a specified server.

# Arguments
- `server_id`:  The ID of the server.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`:  The maximum number of items to include in the response. The maximum
  value is 100.
- `"nextToken"`:  The token from a previous call that you use to retrieve the next set of
  results. For example, if a previous call to this action returned 100 items, but you set
  maxResults to 10. You'll receive a set of 10 results along with a token. You then use the
  returned token to retrieve the next set of 10.
"""
function get_server_details(serverId; aws_config::AbstractAWSConfig=global_aws_config())
    return migrationhubstrategy(
        "GET",
        "/get-server-details/$(serverId)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_server_details(
    serverId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return migrationhubstrategy(
        "GET",
        "/get-server-details/$(serverId)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Retrieves recommended strategies and tools for the specified server.

# Arguments
- `server_id`:  The ID of the server.

"""
function get_server_strategies(serverId; aws_config::AbstractAWSConfig=global_aws_config())
    return migrationhubstrategy(
        "GET",
        "/get-server-strategies/$(serverId)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_server_strategies(
    serverId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return migrationhubstrategy(
        "GET",
        "/get-server-strategies/$(serverId)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Retrieves a list of all the application components (processes).

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"applicationComponentCriteria"`:  Criteria for filtering the list of application
  components.
- `"filterValue"`:  Specify the value based on the application component criteria type. For
  example, if applicationComponentCriteria is set to SERVER_ID and filterValue is set to
  server1, then ListApplicationComponents returns all the application components running on
  server1.
- `"groupIdFilter"`:  The group ID specified in to filter on.
- `"maxResults"`:  The maximum number of items to include in the response. The maximum
  value is 100.
- `"nextToken"`:  The token from a previous call that you use to retrieve the next set of
  results. For example, if a previous call to this action returned 100 items, but you set
  maxResults to 10. You'll receive a set of 10 results along with a token. You then use the
  returned token to retrieve the next set of 10.
- `"sort"`:  Specifies whether to sort by ascending (ASC) or descending (DESC) order.
"""
function list_application_components(; aws_config::AbstractAWSConfig=global_aws_config())
    return migrationhubstrategy(
        "POST",
        "/list-applicationcomponents";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function list_application_components(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return migrationhubstrategy(
        "POST",
        "/list-applicationcomponents",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Retrieves a list of all the installed collectors.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`:  The maximum number of items to include in the response. The maximum
  value is 100.
- `"nextToken"`:  The token from a previous call that you use to retrieve the next set of
  results. For example, if a previous call to this action returned 100 items, but you set
  maxResults to 10. You'll receive a set of 10 results along with a token. You then use the
  returned token to retrieve the next set of 10.
"""
function list_collectors(; aws_config::AbstractAWSConfig=global_aws_config())
    return migrationhubstrategy(
        "GET", "/list-collectors"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function list_collectors(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return migrationhubstrategy(
        "GET",
        "/list-collectors",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Retrieves a list of all the imports performed.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`:  The total number of items to return. The maximum value is 100.
- `"nextToken"`:  The token from a previous call that you use to retrieve the next set of
  results. For example, if a previous call to this action returned 100 items, but you set
  maxResults to 10. You'll receive a set of 10 results along with a token. You then use the
  returned token to retrieve the next set of 10.
"""
function list_import_file_task(; aws_config::AbstractAWSConfig=global_aws_config())
    return migrationhubstrategy(
        "GET",
        "/list-import-file-task";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function list_import_file_task(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return migrationhubstrategy(
        "GET",
        "/list-import-file-task",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Returns a list of all the servers.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"filterValue"`:  Specifies the filter value, which is based on the type of server
  criteria. For example, if serverCriteria is OS_NAME, and the filterValue is equal to
  WindowsServer, then ListServers returns all of the servers matching the OS name
  WindowsServer.
- `"groupIdFilter"`:  Specifies the group ID to filter on.
- `"maxResults"`:  The maximum number of items to include in the response. The maximum
  value is 100.
- `"nextToken"`:  The token from a previous call that you use to retrieve the next set of
  results. For example, if a previous call to this action returned 100 items, but you set
  maxResults to 10. You'll receive a set of 10 results along with a token. You then use the
  returned token to retrieve the next set of 10.
- `"serverCriteria"`:  Criteria for filtering servers.
- `"sort"`:  Specifies whether to sort by ascending (ASC) or descending (DESC) order.
"""
function list_servers(; aws_config::AbstractAWSConfig=global_aws_config())
    return migrationhubstrategy(
        "POST", "/list-servers"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function list_servers(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return migrationhubstrategy(
        "POST",
        "/list-servers",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Saves the specified migration and modernization preferences.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"applicationPreferences"`:  The transformation preferences for non-database
  applications.
- `"databasePreferences"`:  The transformation preferences for database applications.
- `"prioritizeBusinessGoals"`:  The rank of the business goals based on priority.
"""
function put_portfolio_preferences(; aws_config::AbstractAWSConfig=global_aws_config())
    return migrationhubstrategy(
        "POST",
        "/put-portfolio-preferences";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function put_portfolio_preferences(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return migrationhubstrategy(
        "POST",
        "/put-portfolio-preferences",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Starts the assessment of an on-premises environment.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"s3bucketForAnalysisData"`:  The S3 bucket used by the collectors to send analysis data
  to the service. The bucket name must begin with migrationhub-strategy-.
- `"s3bucketForReportData"`:  The S3 bucket where all the reports generated by the service
  are stored. The bucket name must begin with migrationhub-strategy-.
"""
function start_assessment(; aws_config::AbstractAWSConfig=global_aws_config())
    return migrationhubstrategy(
        "POST", "/start-assessment"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function start_assessment(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return migrationhubstrategy(
        "POST",
        "/start-assessment",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    start_import_file_task(s3_bucket, name, s3key)
    start_import_file_task(s3_bucket, name, s3key, params::Dict{String,<:Any})

 Starts a file import.

# Arguments
- `s3_bucket`:  The S3 bucket where the import file is located. The bucket name is required
  to begin with migrationhub-strategy-.
- `name`:  A descriptive name for the request.
- `s3key`:  The Amazon S3 key name of the import file.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"dataSourceType"`: Specifies the source that the servers are coming from. By default,
  Strategy Recommendations assumes that the servers specified in the import file are
  available in AWS Application Discovery Service.
- `"groupId"`: Groups the resources in the import file together with a unique name. This ID
  can be as filter in ListApplicationComponents and ListServers.
- `"s3bucketForReportData"`:  The S3 bucket where Strategy Recommendations uploads import
  results. The bucket name is required to begin with migrationhub-strategy-.
"""
function start_import_file_task(
    S3Bucket, name, s3key; aws_config::AbstractAWSConfig=global_aws_config()
)
    return migrationhubstrategy(
        "POST",
        "/start-import-file-task",
        Dict{String,Any}("S3Bucket" => S3Bucket, "name" => name, "s3key" => s3key);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function start_import_file_task(
    S3Bucket,
    name,
    s3key,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return migrationhubstrategy(
        "POST",
        "/start-import-file-task",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}("S3Bucket" => S3Bucket, "name" => name, "s3key" => s3key),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Starts generating a recommendation report.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"groupIdFilter"`:  Groups the resources in the recommendation report with a unique name.
- `"outputFormat"`:  The output format for the recommendation report file. The default
  format is Microsoft Excel.
"""
function start_recommendation_report_generation(;
    aws_config::AbstractAWSConfig=global_aws_config()
)
    return migrationhubstrategy(
        "POST",
        "/start-recommendation-report-generation";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function start_recommendation_report_generation(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return migrationhubstrategy(
        "POST",
        "/start-recommendation-report-generation",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Stops the assessment of an on-premises environment.

# Arguments
- `assessment_id`:  The assessmentId returned by StartAssessment.

"""
function stop_assessment(assessmentId; aws_config::AbstractAWSConfig=global_aws_config())
    return migrationhubstrategy(
        "POST",
        "/stop-assessment",
        Dict{String,Any}("assessmentId" => assessmentId);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function stop_assessment(
    assessmentId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return migrationhubstrategy(
        "POST",
        "/stop-assessment",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("assessmentId" => assessmentId), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Updates the configuration of an application component.

# Arguments
- `application_component_id`:  The ID of the application component. The ID is unique within
  an AWS account.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"inclusionStatus"`:  Indicates whether the application component has been included for
  server recommendation or not.
- `"secretsManagerKey"`:  Database credentials.
- `"sourceCodeList"`:  The list of source code configurations to update for the application
  component.
- `"strategyOption"`:  The preferred strategy options for the application component. Use
  values from the GetApplicationComponentStrategies response.
"""
function update_application_component_config(
    applicationComponentId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return migrationhubstrategy(
        "POST",
        "/update-applicationcomponent-config/",
        Dict{String,Any}("applicationComponentId" => applicationComponentId);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function update_application_component_config(
    applicationComponentId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return migrationhubstrategy(
        "POST",
        "/update-applicationcomponent-config/",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}("applicationComponentId" => applicationComponentId),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Updates the configuration of the specified server.

# Arguments
- `server_id`:  The ID of the server.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"strategyOption"`:  The preferred strategy options for the application component. See
  the response from GetServerStrategies.
"""
function update_server_config(serverId; aws_config::AbstractAWSConfig=global_aws_config())
    return migrationhubstrategy(
        "POST",
        "/update-server-config/",
        Dict{String,Any}("serverId" => serverId);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function update_server_config(
    serverId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return migrationhubstrategy(
        "POST",
        "/update-server-config/",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("serverId" => serverId), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end


text:
module RD2

using JLD2, DataFrames, SparseArrays, LinearAlgebra, Statistics, StatsPlots,
    Random, CodecZlib

dat_dir = "/home/xijiang/Music/workspace/data/RD2"

include("workflow.jl")
include("milk.jl")
include("compare.jl")
include("cv-stage-1.jl")
include("refresh-data.jl")

# Test procedures that can serve as examples
# and can be ignored in package of release version
#include("tst/cv.jl")
#include("tst/cv23.jl")
#include("tst/cv-210422.jl")

export workflow

end # module


text:
module StataTest

using MAFE
using Test
using DataFrames

@testset "Stata files" begin
    ctry = Ghana;
    @test isdir(MAFE.baseDir)
    @test isdir(MAFE.stata_dir(ctry))
    @test isfile(MAFE.stata_file_path(ctry, "general"))

    df = read_stata_file(ctry, "general");
    @test isa(df, DataFrame)

    df2 = read_person_file(ctry);
    @test isa(df, DataFrame)
    @test all(df2.birthYear .>= MAFE.birthYearMin)

    i1 = 10;
    p = MAFE.make_person_entry(ctry, i1, df2);
    @test p.id == df2.ident[i1]
    @test (df2.sex[i1] == 1) || (p.sex == MAFE.female)

    df3 = read_activity_file(ctry);
    @test length(df3.ident) > 1000
    @test all(df3.endYear .>= df3.startYear)
    id = "G0003001";
    idxV = findall(df3.ident .== id);
    @test length(idxV) == 1

    df4 = read_migration_file(ctry);
    @test length(df4.ident) > 500
    @test all(df4.endYear .>= df4.startYear)
end

end # module
# ----------


text:
"""
$(SIGNATURES)
Get all the statuses for a request.

Args:
    navAbilityClient (NavAbilityClient): The NavAbility client.
    id (String): The ID of the request that you want the statuses on.
"""
function getStatusMessagesEvent(navAbilityClient::NavAbilityClient, id::String)
    response = navAbilityClient.mutate(MutationOptions(
        "sdk_ls_statusmessages",
        GQL_GETSTATUSMESSAGES,
        Dict(
            "id" => id
        )
    )) |> fetch
    rootData = JSON.parse(response.Data)
    if haskey(rootData, "errors")
        throw("Error: $(rootData["errors"])")
    end
    data = get(rootData,"data",nothing)
    if data === nothing return "Error" end
    statusMessages = get(data,"statusMessages","Error")
    # TODO: What about marshalling?
    return statusMessages
end

getStatusMessages(navAbilityClient::NavAbilityClient, id::String) = @async getStatusMessagesEvent(navAbilityClient, id)

"""
$(SIGNATURES)
Get the latest status message for a request.

Args:
    navAbilityClient (NavAbilityClient): The NavAbility client.
    id (String): The ID of the request that you want the latest status on.
"""
function getStatusLatestEvent(navAbilityClient::NavAbilityClient, id::String)
    response = navAbilityClient.mutate(MutationOptions(
        "sdk_get_statuslatest",
        GQL_GETSTATUSLATEST,
        Dict(
            # "client" => client,
            "id" => id
        )
    )) |> fetch
    rootData = JSON.parse(response.Data)
    if haskey(rootData, "errors")
        throw("Error: $(rootData["errors"])")
    end
    data = get(rootData,"data",nothing)
    if data === nothing return "Error" end
    statusMessage = get(data,"statusLatest","Error")
    # TODO: What about marshalling?
    return statusMessage
end

getStatusLatest(navAbilityClient::NavAbilityClient, id::String) = @async getStatusLatestEvent(navAbilityClient, id)

"""
$(SIGNATURES)
Helper function to get a dictionary of all latest statues for a list of results.

Args:
    navAbilityClient (NavAbilityClient): The NavAbility client.
    ids (Vector{String}): A list of the IDS that you want statuses on.
"""
function getStatusesLatest(navAbilityClient::NavAbilityClient, ids::Vector{String})
    @async begin
        return Dict(r=>fetch(getStatusLatest(navAbilityClient, r)) for r in ids)
    end
end


text:
# Error bar plotting/annotation

# Vertical Error Bars

function PlotErrorBars(label_id, x::AbstractArray{<:Real}, y::AbstractArray{<:Real},
                       err::AbstractArray{<:Real}, args...)
    return PlotErrorBars(label_id, promote(x, y, err)..., args...)
end

function PlotErrorBars(label_id, x::AbstractArray{<:Real}, y::AbstractArray{<:Real},
                       neg::AbstractArray{<:Real}, pos::AbstractArray{<:Real}, args...)
    return PlotErrorBars(label_id, promote(x, y, neg, pos), count, offset, stride)
end

function PlotErrorBars(x::AbstractArray{T}, y::AbstractArray{T}, error::AbstractArray{T};
                       label_id::String="",
                       count::Integer=min(length(x), length(y), length(error)),
                       offset::Integer=0, stride::Integer=1) where {T<:ImPlotData}
    return PlotErrorBars(label_id, x, y, error, count, offset, stride * sizeof(T))
end

function PlotErrorBars(x::AbstractArray{T}, y::AbstractArray{T}, negative::AbstractArray{T},
                       positive::AbstractArray{T}; label_id::String="",
                       count::Integer=min(length(x), length(y), length(negative),
                                          length(positive)), offset::Integer=0,
                       stride::Integer=1) where {T<:ImPlotData}
    return PlotErrorBars(label_id, x, y, negative, positive, count, offset,
                         stride * sizeof(T))
end

function PlotErrorBars(x::AbstractArray{<:Real}, y::AbstractArray{<:Real},
                       error::AbstractArray{<:Real}; kwargs...)
    return PlotErrorBars(promote(x, y, error)...; kwargs...)
end

function PlotErrorBars(x::AbstractArray{<:Real}, y::AbstractArray{<:Real},
                       neg::AbstractArray{<:Real}, pos::AbstractArray{<:Real}; kwargs...)
    return PlotErrorBars(promote(x, y, pos, neg)...; kwargs...)
end

# Horizontal Error bars

function PlotErrorBarsH(label_id, x::AbstractArray{<:Real}, y::AbstractArray{<:Real},
                        err::AbstractArray{<:Real}, args...)
    return PlotErrorBarsH(label_id, promote(x, y, err)..., args...)
end

function PlotErrorBarsH(label_id, x::AbstractArray{<:Real}, y::AbstractArray{<:Real},
                        neg::AbstractArray{<:Real}, pos::AbstractArray{<:Real}, args...)
    return PlotErrorBarsH(label_id, promote(x, y, neg, pos), count, offset, stride)
end

function PlotErrorBarsH(x::AbstractArray{T}, y::AbstractArray{T}, error::AbstractArray{T};
                        label_id::String="",
                        count::Integer=min(length(x), length(y), length(error)),
                        offset::Integer=0, stride::Integer=1) where {T<:ImPlotData}
    return PlotErrorBarsH(label_id, x, y, error, count, offset, stride * sizeof(T))
end

function PlotErrorBarsH(x::AbstractArray{T}, y::AbstractArray{T},
                        negative::AbstractArray{T}, positive::AbstractArray{T};
                        label_id::String="",
                        count::Integer=min(length(x), length(y), length(negative),
                                           length(positive)), offset::Integer=0,
                        stride::Integer=1) where {T<:ImPlotData}
    return PlotErrorBarsH(label_id, x, y, negative, positive, count, offset,
                          stride * sizeof(T))
end

function PlotErrorBarsH(x::AbstractArray{<:Real}, y::AbstractArray{<:Real},
                        error::AbstractArray{<:Real}; kwargs...)
    return PlotErrorBarsH(promote(x, y, error)...; kwargs...)
end

function PlotErrorBarsH(x::AbstractArray{<:Real}, y::AbstractArray{<:Real},
                        neg::AbstractArray{<:Real}, pos::AbstractArray{<:Real}; kwargs...)
    return PlotErrorBarsH(promote(x, y, pos, neg)...; kwargs...)
end


text:
using ParticleGridMapper
using Test

include("test_amr.jl")


text:
# Include our abstract base classes for everything
include("ObjectHandle.jl")
include("Printing.jl")
include("Section.jl")
include("Segment.jl")
include("StrTab.jl")
include("Symbol.jl")
include("DynamicLink.jl")

# These are holdovers from ObjFileBase and friends that I haven't ported over yet
#include("Relocation.jl")
#include("Debug.jl")
#include("JIT.jl")


text:
"""
    struct CartesianMesh{N,T} <: AbstractMesh{N,T}

An `N`-dimensional cartesian grid given as the tensor-product of `N` one-dimensional
`LinRange{T}` objects. The grid spacing is therefore constant per dimension.
"""
struct CartesianMesh{N,T} <: AbstractMesh{N,T}
    grid1d::NTuple{N,LinRange{T}}
end
etype(m::CartesianMesh{N,T}) where {N,T}  = HyperRectangle{N,T}
etypes(m::CartesianMesh) = (etype(m),)

# allow for arguments to be passed as e.g. (x,y) instead of tuple and promote
# type if needed
CartesianMesh(args...) = CartesianMesh(promote(args...))

function CartesianMesh(d::ReferenceLine;h::Number=floatmax(),n::Int=1)
    m     = cld(1,h) |> Int
    n     = max(m,n)
    xgrid = LinRange(0,1,n+1)
    CartesianMesh(xgrid)
end

function CartesianMesh(d::ReferenceSquare, h, n)
    nx     = cld(1,h[1]) + 1 |> Int
    ny     = cld(1,h[2]) + 1 |> Int
    nx     = max(n[1],nx)
    ny     = max(n[2],ny)
    xgrid = LinRange(0,1,nx)
    ygrid = LinRange(0,1,ny)
    CartesianMesh(xgrid,ygrid)
end
CartesianMesh(d::ReferenceSquare; h::Number, n::Number) = CartesianMesh(d,(h,h),(n,n))

grid1d(g::CartesianMesh)     = g.grid1d
grid1d(g::CartesianMesh,dim) = g.grid1d[dim]

dimension(g::CartesianMesh{N}) where {N} = N

xgrid(g::CartesianMesh) = g.grid1d[1]
ygrid(g::CartesianMesh) = g.grid1d[2]
zgrid(g::CartesianMesh) = g.grid1d[3]

meshsize(g::CartesianMesh)      = step.(grid1d(g))
meshsize(g::CartesianMesh,dim)  = step(grid1d(g,dim))

Base.size(g::CartesianMesh) = length.(g.grid1d)
Base.length(g::CartesianMesh) = prod(size(g))

function Base.getindex(g::CartesianMesh,I)
    N = dimension(g)
    @assert N == length(I)
    ntuple(N) do dim
        i = I[dim]
        g.grid1d[dim][i]
    end
end

function Base.getindex(g::CartesianMesh,I...)
    N = dimension(g)
    @assert N == length(I)
    ntuple(N) do dim
        i = I[dim]
        g.grid1d[dim][i]
    end
end

Base.CartesianIndices(g::CartesianMesh) = CartesianIndices(size(g))

# iterate over all nodes
# function Base.iterate(g::CartesianMesh)
#     i = first(CartesianIndices(g))
#     return g[i],i
# end

# function Base.iterate(g::CartesianMesh,state)
#     idxs = CartesianIndices(g)
#     next = iterate(idxs,state)
#     if next === nothing
#         return nothing
#     else
#         i,state = next
#         return g[i],state
#     end
# end

# Base.IteratorSize(::CartesianMesh{N}) where {N} = Base.HasShape{N}()

max_stars_repo_name: WaveProp/WaveProp

max_issues_repo_name: WaveProp/WaveProp

max_forks_repo_name: WaveProp/WaveProp