text:
using SparseArrays, Test
LarA = Lar.Arrangement
using LinearAlgebraicRepresentation
LAR = LinearAlgebraicRepresentation

#-------------------------------------------------------------------------------
#   PLANAR ARRANGEMENT PIPELINE - PART 1 METHODS
#    frag_edge_channel
#    frag_edge
#    intersect_edges
#    merge_vertices!
#-------------------------------------------------------------------------------

@testset "Edge Fragmentation" begin
    model = Lar.Model(hcat([
        [2., 2.], [4., 2.], [3., 3.5], [1., 3.], [5., 3.], [1., 2.], [5., 2.]
    ]...))
    Lar.addModelCells!(model, 1, SparseArrays.sparse(Array{Int8, 2}([
        [1 1 0 0 0 0 0] #1->1,2
        [0 1 1 0 0 0 0] #2->2,3
        [1 0 1 0 0 0 0] #3->1,3
        [0 0 0 1 1 0 0] #4->4,5
        [0 0 0 0 0 1 1] #5->6,7
    ])))
    bigPI = LarA.spaceIndex(model, 1)

    @testset "intersect_edges" begin
        V = convert(Lar.Points, model.G')
        EV = model.T[1]

        inters1 = LarA.intersect_edges(V, EV[5, :], EV[1, :])
        inters2 = LarA.intersect_edges(V, EV[1, :], EV[4, :])
        inters3 = LarA.intersect_edges(V, EV[1, :], EV[2, :])

        @test inters1 == [([2. 2.], 1/4),([4. 2.], 3/4)]
        @test inters2 == []
        @test inters3 == [([4. 2.], 1)]
    end

    @testset "frag_edges" begin
        V1, EV1 = LarA.frag_edge(model, 1, bigPI)
        V4, EV4 = LarA.frag_edge(model, 4, bigPI)
        V5, EV5 = LarA.frag_edge(model, 5, bigPI)

        @test V1 == [2.0 2.0; 4.0 2.0; 2.0 2.0; 4.0 2.0]
        @test EV1 == SparseArrays.sparse(Array{Int8, 2}([1 1 0 0]))

        @test isapprox(V4, [1.0 3.0; 5.0 3.0; 2.666666666 3.0; 3.33333333 3.0])
        @test EV4 == SparseArrays.sparse(Array{Int8, 2}([
            [1 0 1 0]
            [0 0 1 1]
            [0 1 0 1]
        ]))

        @test V5 == [1.0 2.0; 5.0 2.0; 2.0 2.0; 2.0 2.0; 4.0 2.0; 4.0 2.0]
        @test EV5 == SparseArrays.sparse(Array{Int8, 2}([
            [1 0 0 1 0 0]
            [0 0 0 1 0 1]
            [0 1 0 0 0 1]
        ]))
    end

    @testset "frag_edge_channel" begin
                                                                                # TODO
    end
end

@testset "merge_vertices" begin
    n0 = 1e-12
    n1l = 1-1e-12
    n1u = 1+1e-12
    model = Lar.Model([
        n0 -n0  n0 -n0  n0 -n0  n0 -n0 n1u n1l n1u n1l n1u n1l n1u n1l
        n0  n0 -n0 -n0 n1u n1u n1l n1l n1u n1u n1l n1l  n0  n0 -n0 -n0
    ])
    Lar.addModelCells!(model, 1, SparseArrays.sparse(Array{Int8, 2}([
        [1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0]
        [0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0]
        [0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0]
        [0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0]
        [0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0]
        [0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0]
        [0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0]
        [0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0]
        [0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0]
        [0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0]
        [0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0]
        [0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1]
        [1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0]
        [0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0]
        [0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0]
        [0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1]
    ])))
    Lar.Arrangement.merge_vertices!(model)

    @test model.G == [n0 n0; n0 n1u; n1u n1u; n1u n0]'
    @test Array(model.T[1]) == [1 1 0 0; 0 1 1 0; 0 0 1 1; 1 0 0 1]
end

#-------------------------------------------------------------------------------
#   PLANAR ARRANGEMENT 1
#-------------------------------------------------------------------------------

@testset "Planar Arrangement 1" begin
    model = Lar.Model([
        2.0 2.0 4.0 4.0 1.5 3.0 4.5 3.0
        2.0 4.0 4.0 2.0 3.0 4.5 3.0 1.5
    ])
    Lar.addModelCells!(model, 1, SparseArrays.sparse(Array{Int8, 2}([
        1 1 0 0 0 0 0 0
        0 1 1 0 0 0 0 0
        0 0 1 1 0 0 0 0
        1 0 0 1 0 0 0 0
        0 0 0 0 1 1 0 0
        0 0 0 0 0 1 1 0
        0 0 0 0 0 0 1 1
        0 0 0 0 1 0 0 1
    ])))
    sigma = SparseArrays.sparse(Array{Int8, 1}([
        0; 0; 0; 0; 1; 1; 1; 1
    ]))
    model, sigma, edges = LarA.planar_arrangement_1(model, sigma, true, false)
    @test model.G == [
        2.0 2.0 2.0 2.0 4.0 2.5 3.5 4.0 4.0 4.0 2.5 3.5 1.5 3.0 4.5 3.0
        2.0 4.0 3.5 2.5 4.0 4.0 4.0 2.0 3.5 2.5 2.0 2.0 3.0 4.5 3.0 1.5
    ]
    @test model.T[1] == abs.(LAR.coboundary_0([
        [1,4],[4,3],[3,2],[2,6],[6,7],[7,5],
        [5,9],[9,10],[10,8],[1,11],[11,12],[12,8],
        [13,3],[3,6],[6,14],[14,7],[7,9],[9,15],
        [15,10],[10,12],[12,16],[13,4],[4,11],[11,16],
    ]))
    @test sigma == 13:24
    @test edges == [
        [ 1,  2,  3], [ 4,  5,  6], [ 7,  8,  9], [10, 11, 12],
        [13, 14, 15], [16, 17, 18], [19, 20, 21], [22, 23, 24]
    ]
end

#-------------------------------------------------------------------------------
#   PLANAR ARRANGEMENT PIPELINE - CLEAN DECOMPOSITION
#-------------------------------------------------------------------------------

@testset "Clean Decomposition" begin
    model = Lar.Model([
        2.0 2.0 2.0 2.0 4.0 2.5 3.5 4.0 4.0 4.0 2.5 3.5 1.5 3.0 4.5 3.0
        2.0 4.0 3.5 2.5 4.0 4.0 4.0 2.0 3.5 2.5 2.0 2.0 3.0 4.5 3.0 1.5
    ])
    Lar.addModelCells!(model, 1, abs.(LAR.coboundary_0([
        [ 1,  4], [ 4,  3], [ 3,  2], [ 2,  6], [ 6,  7], [ 7,  5],
        [ 5,  9], [ 9, 10], [10,  8], [ 1, 11], [11, 12], [12,  8],
        [13,  3], [ 3,  6], [ 6, 14], [14,  7], [ 7,  9], [ 9, 15],
        [15, 10], [10, 12], [12, 16], [13,  4], [ 4, 11], [11, 16]
    ])))
    sigma = collect(13:24)
    edges = [
        [ 1,  2,  3], [ 4,  5,  6], [ 7,  8,  9], [10, 11, 12],
        [13, 14, 15], [16, 17, 18], [19, 20, 21], [22, 23, 24]
    ]
    model, edges = LarA.cleandecomposition(model, sigma, edges)
    @test model.G == [
        2.0 2.0 2.5 3.5 4.0 4.0 2.5 3.5 1.5 3.0 4.5 3.0
        3.5 2.5 4.0 4.0 3.5 2.5 2.0 2.0 3.0 4.5 3.0 1.5
    ]
    @test model.T[1] == abs.(LAR.coboundary_0([
        [ 2,  1], [ 3,  4],
        [ 5,  6], [ 8,  7],
        [ 9,  1], [ 1,  3], [3, 10], [10,  4], [ 4,  5], [ 5, 11],
        [11,  6], [ 6,  8], [8, 12], [ 9,  2], [ 2,  7], [ 7, 12]
    ]))
    @test edges == [
        [         1], [         2], [         3], [         4],
        [ 5,  6,  7], [ 8,  9, 10], [11, 12, 13], [14, 15, 16]
    ]
end

#-------------------------------------------------------------------------------
#   PLANAR ARRANGEMENT PIPELINE - BICONNECTED COMPONENTS
#-------------------------------------------------------------------------------

@testset "Biconnected Components" begin
    EV = SparseArrays.sparse(Int8[
        0 0 0 1 0 0 0 0 0 0 1 0 #1
        0 0 1 0 0 1 0 0 0 0 0 0 #2
        0 0 0 0 0 0 1 0 0 1 0 0 #3
        1 0 0 0 1 0 0 0 0 0 0 0 #4
        0 0 0 1 0 0 0 1 0 0 0 0 #5
        0 0 1 0 0 0 0 0 1 0 0 0 #6
        0 1 0 0 0 0 0 0 0 1 0 0 #7
        0 0 0 0 1 0 0 0 0 0 0 1 #8
        0 0 0 0 0 0 0 1 0 0 1 0 #9
        0 0 0 0 0 1 0 0 1 0 0 0 #10
        0 1 0 0 0 0 1 0 0 0 0 0 #11
        0 0 0 0 1 0 0 0 0 0 1 0 #12
        0 0 0 0 1 0 0 0 1 0 0 0 #13
    ])

    bc = Lar.Arrangement.biconnected_components(EV)
    bc = Set(map(Set, bc))

    @test bc == Set([Set([1,5,9]), Set([2,6,10]), Set([3,7,11])])
end

#-------------------------------------------------------------------------------
#   PLANAR ARRANGEMENT PIPELINE - PART 2 - COMPONENT GRAPH (TGW) METHODS
#    get_external_cycle
#    pre_containment_test
#    prune_containment_graph
#    transitive_reduction!
#-------------------------------------------------------------------------------

@testset "TGW Methods" begin
    @testset "External cell individuation" begin
        V = [ .5 .5;  1.5   1;  1.5  2;
             2.5  2;  2.5   1;  3.5 .5;
             3.5  3;    2 2.5;   .5  3]

        EV = SparseArrays.sparse(Int8[
            -1  1  0  0  0  0  0  0  0
             0 -1  1  0  0  0  0  0  0
             0  0 -1  1  0  0  0  0  0
             0  0  0 -1  1  0  0  0  0
             0  0  0  0 -1  1  0  0  0
             0  0  0  0  0 -1  1  0  0
             0  0  0  0  0  0 -1  1  0
             0  0  0  0  0  0  0 -1  1
            -1  0  0  0  0  0  0  0  1
             0 -1  0  0  1  0  0  0  0
        ])

        FE = SparseArrays.sparse(Int8[
             0 -1 -1 -1  0  0  0  0  0  1
             1  1  1  1  1  1  1  1 -1  0
            -1  0  0  0 -1 -1 -1 -1  1 -1
        ])

        @test Lar.Arrangement.get_external_cycle(V, EV, FE) == 3

        model = Lar.Model(hcat([[0.0,0.0], [4.0,0.0], [2.0,3.0], [2.0,1.5]]...))
        Lar.addModelCells!(model, 1, SparseArrays.sparse(Array{Int8, 2}([
    		[1 1 0 0] #1 -> 1,2
    		[0 1 1 0] #2 -> 2,3
    		[1 0 1 0] #3 -> 3,1
    		[1 0 0 1] #4 -> 1,2
    		[0 1 0 1] #5 -> 2,3
    		[0 0 1 1] #6 -> 3,1
    	])))
        Lar.addModelCells!(model, 2, SparseArrays.sparse(Array{Int8, 2}([
    		[1 0 0 1 1 0] #1 -> 1,4,5
    		[0 1 0 0 1 1] #2 -> 2,5,6
    		[0 0 1 1 0 1] #3 -> 3,4,6
    		[1 1 1 0 0 0] #4 -> 1,2,3 External
    	])))

        @test LarA.get_external_cycle(model) == 4
        Lar.deleteModelCell!(model, 2, 4)
        @test isnothing(LarA.get_external_cycle(model))
    end

    @testset "Containment test" begin
        V = [  0   0;    4   0;    4   2;   2   4;  0 4;
              .5  .5;  2.5  .5;  2.5 2.5;  .5 2.5;
               1   1;  1.5   1;    1   2;
               2   1;    2   2;  1.5   2;
             3.5 3.5;    3 3.5;  3.5   3]
        EV1 = Int8[ 0  0  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  0 -1  1  0  0  0  0  0  0;
                    0  0  0  0  0  0  0  0  0 -1  0  1  0  0  0  0  0  0]
        EV2 = Int8[ 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  0  0  0  0  0 -1  1  0  0  0;
                    0  0  0  0  0  0  0  0  0  0  0  0 -1  0  1  0  0  0]
        EV3 = Int8[ 0  0  0  0  0 -1  1  0  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  0  0  0  0  0 -1  1  0  0  0  0  0  0  0  0  0;
                    0  0  0  0  0 -1  0  0  1  0  0  0  0  0  0  0  0  0]
        EV4 = Int8[-1  1  0  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  0  0  0;
                    0  0 -1  1  0  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  0;
                   -1  0  0  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0]
        EV5 = Int8[ 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  0  0  0  0  0 -1  1;
                    0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 -1  0  1]
        EVs = map(sparse, [EV1, EV2, EV3, EV4, EV5])

        shell1 = Int8[-1 -1  1]
        shell2 = Int8[-1 -1  1]
        shell3 = Int8[-1 -1 -1  1]
        shell4 = Int8[-1 -1 -1 -1  1]
        shell5 = Int8[-1 -1  1]
        shells = map(sparsevec, [shell1, shell2, shell3, shell4, shell5])

        shell_bboxes = []
        n = 5
        for i in 1:n
            vs_indexes = (abs.(EVs[i]')*abs.(shells[i])).nzind
            push!(shell_bboxes, LAR.bbox(V[vs_indexes, :]))
        end

        graph = Lar.Arrangement.pre_containment_test(shell_bboxes)
        @test graph == [0 0 1 1 0; 0 0 1 1 0; 0 0 0 1 0; 0 0 0 0 0; 0 0 0 1 0]

        graph = Lar.Arrangement.prune_containment_graph(V, EVs, shells, graph)
        @test graph == [0 0 1 1 0; 0 0 1 1 0; 0 0 0 1 0; 0 0 0 0 0; 0 0 0 0 0]
    end

    @testset "Transitive reduction" begin
        graph = [0 0 1 1 0; 0 0 1 1 0; 0 0 0 1 0; 0 0 0 0 0; 0 0 0 0 0]
        Lar.Arrangement.transitive_reduction!(graph)
        @test graph == [0 0 1 0 0; 0 0 1 0 0; 0 0 0 1 0; 0 0 0 0 0; 0 0 0 0 0]
    end
end

#-------------------------------------------------------------------------------
#   PLANAR ARRANGEMENT PIPELINE - PART 2 METHODS
#    componentgraph (aka TGW)
#    cell_merging
#-------------------------------------------------------------------------------

@testset "Component Graph" begin
    @testset "Cell merging" begin
        graph = [0 1; 0 0]
        V = [.25 .25; .75 .25; .75 .75; .25 .75;
               0   0;   1   0;   1   1;   0   1]
        EV1 = Int8[-1  1  0  0  0  0  0  0;
                    0 -1  1  0  0  0  0  0;
                    0  0 -1  1  0  0  0  0;
                   -1  0  0  1  0  0  0  0;
                   -1  0  1  0  0  0  0  0]
        EV2 = Int8[ 0  0  0  0 -1  1  0  0;
                    0  0  0  0  0 -1  1  0;
                    0  0  0  0  0  0 -1  1;
                    0  0  0  0 -1  0  0  1]
        EVs = map(sparse, [EV1, EV2])

        shell1 = Int8[-1 -1 -1  1  0]
        shell2 = Int8[-1 -1 -1  1]
        shells = map(sparsevec, [shell1, shell2])

        boundary1 = Int8[ 1  1  0  0 -1;
                          0  0  1 -1  1]
        boundary2 = Int8[ 1  1  1 -1]
        boundaries = map(sparse, [boundary1, boundary2])

        shell_bboxes = []
        n = 2
        for i in 1:n
            vs_indexes = (abs.(EVs[i]')*abs.(shells[i])).nzind
            push!(shell_bboxes, LAR.bbox(V[vs_indexes, :]))
        end

        EV, FE = Lar.Arrangement.cell_merging(2, graph, V, EVs, boundaries, shells, shell_bboxes)

        selector = sparse(ones(Int8, 1, 3))

        @test selector*FE == [0  0  0  0  0  1  1  1 -1]
    end
end

@testset "Cell Merging" begin
end

#-------------------------------------------------------------------------------
#   PLANAR ARRANGEMENT PIPELINE - PART 2
#-------------------------------------------------------------------------------

@testset "Planar Arrangement 2" begin
    model = Lar.Model([
        0.0 0 2 0 0 1 4 4 3 2 4 4
        0.0 2 0 3 4 4 2 0 0 4 4 2
    ]);
    Lar.addModelCells!(model, 1, abs.(LAR.coboundary_0([
        [ 1,  2], [ 2,  3], [ 3,  1],
        [ 4,  5], [ 5,  6], [ 6,  7], [ 7,  8], [ 8,  9], [ 9, 4],
        [10, 11], [11, 12], [12, 10]
    ])))

    bicon_comps = [
        [ 1,  2,  3],
        [ 4,  5,  6,  7,  8,  9],
        [10, 11, 12]
    ]
    model = Lar.Arrangement.planar_arrangement_2(model, bicon_comps)
end

#-------------------------------------------------------------------------------
#   COMPLETE PLANAR ARRANGEMENT
#-------------------------------------------------------------------------------

@testset "Complete Pipeline" begin

    #=== TRIFORCE MODEL DEFINITION ===#
    triforce = Lar.Model([
        0.0  4.0  8.0  4.0  2.0  6.0  4.0 -4.0 12.0  4.0  3.0  5.0  4.0  4.0
        0.0  6.0  0.0  0.0  3.0  3.0 -6.0  6.0  6.0  1.0  2.5  2.5  1.0  2.0
    ])
    Lar.addModelCells!(triforce, 1, SparseArrays.sparse(Array{Int8, 2}([
        [1 1 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]
        [1 0 1 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 0 1 1 0 0 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 1 1 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 1 0 1 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 0 1 1 0 0]
        [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 1 1]
    ])))
    sigma = convert(Lar.Chain, SparseArrays.sparse([
        1; 1; 1; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0
    ]))

    #=== PLANAR ARRANGEMENT 1 ===#
    arranged_triforce = Lar.Model([
        0.0  4.0  2.0  8.0  6.0  4.0  4.0 -4.0 12.0  4.0  3.0  5.0  4.0
        0.0  6.0  3.0  0.0  3.0  0.0 -6.0  6.0  6.0  1.0  2.5  2.5  2.0
    ])
    Lar.addModelCells!(arranged_triforce, 1, SparseArrays.sparse(Int8[
        1 0 1 0 0 0 0 0 0 0 0 0 0
        0 1 1 0 0 0 0 0 0 0 0 0 0
        0 1 0 0 1 0 0 0 0 0 0 0 0
        0 0 0 1 1 0 0 0 0 0 0 0 0
        1 0 0 0 0 1 0 0 0 0 0 0 0
        0 0 0 1 0 1 0 0 0 0 0 0 0
        0 0 1 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 1 1 0 0 0 0 0 0 0
        1 0 0 0 0 0 1 0 0 0 0 0 0
        1 0 0 0 0 0 0 1 0 0 0 0 0
        0 1 0 0 0 0 0 1 0 0 0 0 0
        0 1 0 0 0 0 0 0 1 0 0 0 0
        0 0 0 1 0 0 1 0 0 0 0 0 0
        0 0 0 1 0 0 0 0 1 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 1 1 0
        0 0 0 0 0 0 0 0 0 1 0 1 0
        0 0 0 0 0 0 0 0 0 1 0 0 1
    ]))
    arranged_sigma = collect(1:6)
    arranged_edge_map = Array{Int64,1}[
        [ 1,  2], [ 3,  4], [ 5,  6],
        [     7], [     8], [     9],
        [10, 11], [12, 13], [14, 15],
        [    16], [    17], [    18], [    19]
    ]

    a, b, c = LarA.planar_arrangement_1(triforce, sigma, true, false)
    @test arranged_triforce == a
    @test arranged_sigma    == b
    @test arranged_edge_map == c

    #=== CLEAN DECOMPOSITION ===#
    cleaned_triforce = Lar.Model([
        0.0 4.0 2.0 8.0 6.0 4.0 4.0 3.0 5.0 4.0
        0.0 6.0 3.0 0.0 3.0 0.0 1.0 2.5 2.5 2.0
    ])
    Lar.addModelCells!(cleaned_triforce, 1, SparseArrays.sparse(Int8[
        1 0 1 0 0 0 0 0 0 0
        0 1 1 0 0 0 0 0 0 0
        0 1 0 0 1 0 0 0 0 0
        0 0 0 1 1 0 0 0 0 0
        1 0 0 0 0 1 0 0 0 0
        0 0 0 1 0 1 0 0 0 0
        0 0 1 0 0 1 0 0 0 0
        0 0 1 0 1 0 0 0 0 0
        0 0 0 0 1 1 0 0 0 0
        0 0 0 0 0 0 1 1 0 0
        0 0 0 0 0 0 0 1 1 0
        0 0 0 0 0 0 1 0 1 0
        0 0 0 0 0 0 1 0 0 1
    ]))
    cleaned_edge_map = Array{Int64,1}[
        [1, 2], [3, 4], [5, 6],
        [   7], [   8], [   9],
        [    ], [    ], [    ],
        [  10], [  11], [  12], [  13]
    ]

    a, b = LarA.cleandecomposition(a, b, c)
    @test cleaned_triforce == a
    @test cleaned_edge_map == b

    #=== BICONNECTED COMPONENTS ===#
    bicon_comps = Array{Int64,1}[[8, 9, 7, 5, 6, 4, 3, 2, 1], [12, 11, 10]]
    c = Lar.Arrangement.biconnected_components(a.T[1])
    @test bicon_comps == c

    #=== REMOVE DANGLING EDGES FROM EDGE MAP ===#
    b = LarA.remove_mapping_dangling_edges(b, c)
    purged_edge_map = [
        [1, 2], [3, 4], [5, 6],
        [   7], [   8], [   9],
        [    ], [    ], [    ],
        [  10], [  11], [  12], [    ]
    ]
    @test purged_edge_map == b

    #=== PLANAR ARRANGEMENT 2 ===#

    rearranged_triforce = Lar.Model([
        0.0 4.0 2.0 8.0 6.0 4.0 4.0 3.0 5.0
        0.0 6.0 3.0 0.0 3.0 0.0 1.0 2.5 2.5
    ])
    Lar.addModelCells!(rearranged_triforce, 1, SparseArrays.sparse(Int8[
        -1  0  1  0  0  0  0  0  0
         0 -1  1  0  0  0  0  0  0
         0 -1  0  0  1  0  0  0  0
         0  0  0 -1  1  0  0  0  0
        -1  0  0  0  0  1  0  0  0
         0  0  0 -1  0  1  0  0  0
         0  0 -1  0  0  1  0  0  0
         0  0 -1  0  1  0  0  0  0
         0  0  0  0 -1  1  0  0  0
         0  0  0  0  0  0 -1  1  0
         0  0  0  0  0  0  0 -1  1
         0  0  0  0  0  0 -1  0  1
    ]))
    Lar.addModelCells!(rearranged_triforce, 2, SparseArrays.sparse(Int8[
        0  0  0  0  0  0  1 -1 -1  1  1 -1
        -1 0  0  0  1  0 -1  0  0  0  0  0
        0  1 -1  0  0  0  0  1  0  0  0  0
        0  0  0  1  0 -1  0  0  1  0  0  0
        0  0  0  0  0  0  0  0  0 -1 -1  1
    ]))
    a = Lar.Arrangement.planar_arrangement_2(a, c)
    @test rearranged_triforce == a

end

#-------------------------------------------------------------------------------
#   BIG RANDOM DATASETS
#-------------------------------------------------------------------------------

@testset "Planar Arrangement - Big Random Data" begin
    npts = 100
    ndgs = 200
    V = rand(2, npts)
    model = Lar.Model(rand(2, npts))
    cv = unique([rand(1 : npts, 2) for i = 1 : 10*npts])[1 : ndgs*2]
    cv = [[c[1] c[2]] for c in cv if c[1] != c[2]][1 : ndgs]
    I = []
    J = []
    K = ones(Int8, 2*ndgs)
    for i = 1 : ndgs
        push!(J, cv[i]...)
        push!(I, [i; i]...)
    end
    Lar.addModelCells!(model, 1, SparseArrays.sparse(I, J, K, ndgs, npts))
    model1, edge_map = LarA.planar_arrangement_1(model, spzeros(Int8, 0), true)
    bicon_comps = LarA.biconnected_components(model1.T[1])
    edge_map = LarA.remove_mapping_dangling_edges(edge_map, bicon_comps)
    model2 = LarA.planar_arrangement_2(model1, bicon_comps)

    @testset "Closure of 2-cells" begin
        for i = 1 : size(model2, 2, 1)
            edges  = findnz(model2.T[2][i, :])[1]
            points = abs.(model2.T[1][edges, :])
            @test sum(points) == 2 * length(edges)
        end
    end

    @testset "Well formed cells" begin
        @test sum(sum(abs.(model2.T[1]), dims = 1) .<= 1) == 0
        @test sum(sum(abs.(model2.T[1]), dims = 2) .!= 2) == 0
        @test sum(sum(abs.(model2.T[2]), dims = 1) .>= 3) == 0
        @test sum(sum(abs.(model2.T[2]), dims = 2) .<= 2) == 0
    end

    @testset "Euler" begin
        @test size(model2, 0, 2) - size(model2, 1, 1) + size(model2, 2, 1) == 1
    end

    @testset "1-Cell Compactness" begin
        #@test sum(abs.(model2.T[1])) == 2 * size(model, 1, 2)
    end

    @testset "2-Cell Compactness" begin
        #@test sum(abs.(model2.T[2])) == 2 * size(model2, 2, 2)
    end

    @testset "Biconnected Components" begin
        # for comp in bicon_comps
        #     sum(
        #         (sum(abs.(model.T[1][comp, :]), dims=1) .!= 0)
        #         + (sum(abs.(model.T[1][setdiff(1:size(model, 1, 1), comp), :]), dims=1) .!= 0)
        #         .!= 1
        #     ) == 0
        # end
    end
end


text:
# Note that this script can accept some limited command-line arguments, run
# `julia build_tarballs.jl --help` to see a usage message.
using BinaryBuilder

name = "Opus"
version = v"1.3.1"

# Collection of sources required to build Opus
sources = [
    ArchiveSource("https://archive.mozilla.org/pub/opus/opus-$(version).tar.gz",
                  "65b58e1e25b2a114157014736a3d9dfeaad8d41be1c8179866f144a2fb44ff9d"),
]

# Bash recipe for building across all platforms
script = raw"""
cd $WORKSPACE/srcdir/opus-*/

# On musl, disable stack protection (https://www.openwall.com/lists/musl/2018/09/11/2)
if [[ ${target} == *musl* ]]; then
    STACK_PROTECTOR="--disable-stack-protector"
fi

./configure --prefix=$prefix --host=$target --build=${MACHTYPE} \
            --disable-static \
            --enable-custom-modes \
            ${STACK_PROTECTOR}
make -j${nproc}
make install
"""

# These are the platforms we will build for by default, unless further
# platforms are passed in on the command line
platforms = supported_platforms()

# The products that we will ensure are always built
products = [
    LibraryProduct("libopus", :libopus),
]

# Dependencies that must be installed before this package can be built
dependencies = [
]

# Build the tarballs, and possibly a `build.jl` as well.
build_tarballs(ARGS, name, version, sources, script, platforms, products, dependencies; preferred_gcc_version=v"8")

ext: jl

max_stars_repo_name: waralex/Yggdrasil

max_issues_repo_name: waralex/Yggdrasil

max_forks_repo_name: waralex/Yggdrasil


text:
export findM
"""
function findM(param,w;nsol,pwr)

Find a binary matrix M in Omega_M that solves

min_M  \| M*w - d \|\_{Gamma,pwr} + lambda \| M \|\_0,

Input:

	1. param - StrainReconParam
	2. w     - vector of weights

Keyword arguments:

	3. nsol  - returns nsol matrices (default = 1); if nsol = 2, first matrix has rows with lowest difference |M(i)*w-d(i)| by each row i and is the MAP estimator, second matrix has rows with second lowest difference |M(i)*w-d(i)| by each row i but is NOT the second "best" or most likely matrix
	4. pwr   - exponent in the likelihood function (default = param.pwr)
    5. probM - returns p(M) for nsol matrices corresponding to "confidence"/probability for each row of M, size(m,nsol), (default = false); p(M(i)) = C* exp(-(1/pwr) * (|M(i)*w - d(i)|_R)^pwr) where R is the diagonal of the inverse square of the noise covariance matrix and C is the normalization constant 1/(sum_{m}{j}(sum_{2^n}{i} exp(-(1/pwr) * (|B(i)*w - d(j)|_R)^pwr))), where B is a binary matrix with all possible permutation of binary entries and has size(2^n,n)

Output:

	1. M  - binary matrix of size (q,n) or an array of size (q,n,nsol)
    2. pM - matrix of p(M) of size (m,nsol), entries in each column \in [0,1] represent "confidence" or probability for the rows of M
"""
function findM(param::StrainReconParam,w::Vector;nsol::Int64=1,pwr::Float64=param.pwr,probM=false)
    Rp = diag(param.R.^pwr)
    d  = param.d
    n  = param.n
    p  = param.p
    m  = param.m

    B  = getB(param)
    Ba = reshape(B*w,p-1,:)'
    Bs = reshape(param.lambda * vec(sum(B,2)), p-1,:)'

    if nsol > 2^n
        println("nsol can only be <= 2^n = $(2^n), only the MAP estimator will be returned")
        nsol = 1
    end

    pM = zeros(m,nsol) # array to store p(M) for each M

    if nsol == 1
        M  = falses(length(d),n)
        for k=1:m
            blockidx = (k-1)*(p-1)+1 : k*(p-1)
            Bdiff = sum(Rp[blockidx]'.*abs.(Ba.-d[blockidx]').^pwr,2) + sum(Bs,2) # |B(ik)*w - d(k)|_R^pwr, size(2^n,1)
            ik = indmin(Bdiff) # index ik in 1:2^n
            mi = B[(ik-1)*(p-1)+1 : ik*(p-1),:] # row(s) of B with lowest difference B[ik]*w - d[k]
            M[blockidx,:] = mi

            # compute p(M_i)

            # println("ik $ik mi $mi Bdiff $Bdiff)")
            # avoid underflow by finding min(Bdiff) and subtracting that from all numbers before taking exp
            minbdiff = minimum(Bdiff)
            pmi = exp.(-(1/pwr)*((Rp[blockidx]'.*abs.(mi*w.-d[blockidx]').^pwr + Bs[ik]) .- minbdiff)) # pmi should always = 1
            #opmi = (Rp[blockidx]'.*abs.(mi*w.-d[blockidx]').^pwr + Bs[ik])
            #println("pmi $pmi \n opmi $opmi minbdiff $minbdiff")
            normconst = sum(exp.(-(1/pwr)*(Bdiff .- minbdiff))) # normalization constant
            #println("normconst $normconst")
            pM[k,nsol] = pmi[1]/normconst
        end
    else
        M  = falses(length(d),n,nsol)
        for k=1:m
            blockidx = (k-1)*(p-1)+1 : k*(p-1)
            Bdiff = vec(sum(Rp[blockidx]'.*abs.(Ba.-d[blockidx]').^pwr,2) + sum(Bs,2))
            ik = sortperm(Bdiff)
            minbdiff = minimum(Bdiff)
            normconst = sum(exp.(-(1/pwr)*(Bdiff .- minbdiff))) # normalization constant for each row
            for j=1:nsol
                # nth best row
                mj = B[(ik[j]-1)*(p-1)+1 : ik[j]*(p-1),:]
                M[blockidx,:,j] = mj

                # compute p(M_i) for each matrix
                ij = ik[j]
                # println("ij $ij mj $mj Bdiff $Bdiff)")
                pmj = exp.(-(1/pwr)*((Rp[blockidx]'.*abs.(mj*w.-d[blockidx]').^pwr + Bs[ij]) .- minbdiff))
                # println("j $j pmj $pmj")
                # println("normconst $normconst")
                pM[k,j] = pmj[1]/normconst
            end
        end
    end

    if probM
        return M, pM
    else
        return M
    end
end


text:
file = matopen("temp.mat","w")
#title: "Max Throughput Prediction"

lenOfLegends=length(legends)
write(file,"lenOfLegends",lenOfLegends)

for i=1:lenOfLegends
	write(file,string("legends",i), legends[i])
end

lenOfXdata=length(Xdata)
write(file,"lenOfXdata",lenOfXdata)
for i=1:lenOfXdata
	write(file,string("Xdata",i),float(Xdata[i]))
end

lenOfYdata=length(Ydata)
write(file,"lenOfYdata",lenOfYdata)
for i=1:lenOfYdata
	write(file,string("Ydata",i),float(Ydata[i]))
end

#Ylabel = "TPS";
#Xlabel = "Time";

lenOfMeanAbsError=length(meanAbsError)
write(file,"lenOfMeanAbsError",lenOfMeanAbsError)
for i=1:lenOfMeanAbsError
	write(file,string("meanAbsError",i),float(meanAbsError[i]))
end

lenOfMeanRelError=length(meanRelError)
write(file,"lenOfMeanRelError",lenOfMeanRelError)
for i=1:lenOfMeanRelError
	write(file,string("meanRelError",i),float(meanRelError[i]))
end

lenOfErrorHeader=length(errorHeader)
write(file,"lenOfErrorHeader",lenOfErrorHeader)
for i=1:lenOfErrorHeader
	if errorHeader[i]=="Max Throughput based on adjusted LR for CPU+classification"
		write(file,string("errorHeader",i),3)
	elseif errorHeader[i]=="Max Throughput on LR for CPU+classification"
		write(file,string("errorHeader",i),4)
	elseif errorHeader[i]=="Max Throughput on adjusted LR for CPU"
		write(file,string("errorHeader",i),5)
	elseif errorHeader[i]=="Max Throughput based on LR for CPU"
		write(file,string("errorHeader",i),6)
	elseif errorHeader[i]=="Max Throughput based on our flush rate model"
		write(file,string("errorHeader",i),7)
	elseif errorHeader[i]=="Max Throughput based on LR for flush rate"
		write(file,string("errorHeader",i),8)
	elseif errorHeader[i]=="Max Throughput based on our contention model"
		write(file,string("errorHeader",i),9)
	end
end

lenOfExtra=length(extra)
write(file,"lenOfExtra",lenOfExtra)
for i=1:lenOfExtra
	write(file,string("extra",i),extra[i])
end

close(file)

max_stars_repo_name: barzan/dbseer

max_issues_repo_name: barzan/dbseer

max_forks_repo_name: barzan/dbseer


text:
struct GadgetPhysical{T}

    x_cgs::T         # position in cm
    x_physical::T    # position in kpc

    v_cgs::T         # velocity in cm/s
    v_physical::T    # velocity in km/s

    m_cgs::T         # mass in g
    m_msun::T        # mass in Msun
    m_physical::T    # mass in 10^10 Msun

    t_s::T           # time in sec
    t_Myr::T         # time in Myr

    E_cgs::T         # energy in erg
    E_eV::T          # energy in eV

    B_cgs::T         # magnetic field in Gauss

    rho_physical::T   # density in 10^10 Msun/kpc^3
    rho_cgs::T       # density in g/cm^3
    rho_ncm3::T      # density in N_p/cm^3

    T_K::T           # temperature in K
    T_eV::T          # temperature in eV

    P_th_cgs::T      # thermal pressure in Ba
    P_CR_cgs::T      # cosmic ray pressure in Ba
end

"""
    GadgetPhysical(l_unit::T=3.085678e21, m_unit::T=1.989e43, v_unit::T=1.e5;
                a_scale::T=1.0, hpar::T=1.0,
                γ_th::T=5.0/3.0, γ_CR::T=4.0/3.0, xH::T=0.76) where T

Creates a datatype GadgetPhysical which holds the conversion factors between comoving code units and physical units, without unit information.

Keyword arugments specify:
# Arguments
- `a_scale::T = 1.0`:  Cosmological scale factor of the simulation. Can be passed with the header `h` as `h.time`.
- `hpar::T = 1.0`:     Hubble constant as 'little h'. Can be passed with header `h` as `h.h0`.
- `γ_th::T = 5.0/3.0`: Adiabatic index of gas.
- `γ_CR::T = 4.0/3.0`: Adiabatic index of cosmic ray component.
- `xH::T = 0.76`:      Hydrogen fraction of the simulation, if run without chemical model.

# Fields

|Name | Meaning |
|:--- |:--- |
|`x_cgs::T` | position in cm |
|`x_physical::T` | position in kpc |
|`v_cgs::T` | velocity in cm/s |
|`v_physical::T` | velocity in km/s |
|`m_cgs::T` | mass in g |
|`m_msun::T` | mass in Msun |
|`m_physical::T` | mass in 10^10 Msun |
|`t_s::T` | time in sec |
|`t_Myr::T` | time in Myr |
|`E_cgs::T` | energy in erg |
|`E_eV::T` | energy in eV |
|`B_cgs::T` | magnetic field in Gauss |
|`rho_physical::T` | density in 10^10 Msun/kpc^3 |
|`rho_cgs::T` | density in ``g/cm^3`` |
|`rho_ncm3::T` | density in ``n_p/cm^3`` |
|`T_K::T` | temperature in K |
|`T_eV::T` | temperature in eV |
|`P_th_cgs::T` | thermal pressure in Ba |
|`P_CR_cgs::T` | cosmic ray pressure in Ba |

"""
function GadgetPhysical(l_unit::T=3.085678e21, m_unit::T=1.989e43, v_unit::T=1.e5;
                        a_scale::T=1.0, hpar::T=1.0,
                        γ_th::T=5.0/3.0, γ_CR::T=4.0/3.0, xH::T=0.76) where T

    # some basic constants
    kB      = 1.38066e-16
    mp      = 1.6726e-24
    eV2cgs  = 1.602e-12

    yhelium = ( 1.0 - xH ) / ( 4.0 * xH )
    mean_mol_weight = (1.0 + 4.0 * yhelium) / (1.0 + 3.0 * yhelium + 1.0)

    n2ne =  (  xH + 0.5 * ( 1.0 - xH ) ) /
            ( 2.0 * xH + 0.75 * ( 1.0 - xH ) )       # conversion n_pat -> n_electrons
    umu  =  4.0 / ( 5.0 * xH + 3.0 )                 # mean molucular weight in hydr. mass

    # convert comoving output to physical units
    x_cgs      = l_unit * a_scale / hpar
    x_physical = a_scale / hpar

    v_cgs      = v_unit * sqrt(a_scale)
    v_physical = sqrt(a_scale)

    m_cgs      = m_unit / hpar
    m_physical = 1.0 / hpar

    t_unit  = l_unit / v_unit
    t_s     = t_unit * sqrt(a_scale) / hpar  # in sec
    t_Myr   = t_s / 3.15576e13

    E_cgs = m_cgs * v_cgs^2
    E_eV  = E_cgs * 6.242e+11

    B_cgs = 1.0   # gadget outputs in cgs

    rho_physical = m_physical / x_physical^3
    rho_cgs      = m_unit/l_unit^3 * hpar^2 / a_scale^3
    rho_ncm3     = rho_cgs * n2ne/( umu * mp )

    T_cgs = (γ_th - 1.0) * v_unit^2 * mean_mol_weight * mp / kB
    T_eV  = T_cgs * kB / eV2cgs

    P_th_cgs = a_scale^(-3) * E_cgs / l_unit^3 * hpar^2
    P_CR_cgs = a_scale^(-4) * E_cgs / l_unit^3 * hpar^2

    GadgetPhysical{T}(x_cgs, x_physical,
        v_cgs, v_physical,
        m_cgs, m_cgs/T(1.989e33), m_physical,
        t_s, t_Myr,
        E_cgs, E_eV,
        B_cgs,
        rho_physical, rho_cgs, rho_ncm3,
        T_cgs, T_eV,
        P_th_cgs,
        P_CR_cgs
        )

end

"""
    GadgetPhysical( DT::DataType,
                    l_unit::Real=3.085678e21, m_unit::Real=1.989e43, v_unit::Real=1.e5;
                    a_scale::Real=1.0, hpar::Real=1.0,
                    γ_th::Real=5.0/3.0, γ_CR::Real=4.0/3.0, xH::Real=0.76)

Set up a unit struct with a given `DataType`.
"""
GadgetPhysical( DT::DataType,
                l_unit::Real=3.085678e21, m_unit::Real=1.989e43, v_unit::Real=1.e5;
                a_scale::Real=1.0, hpar::Real=1.0,
                γ_th::Real=5.0/3.0, γ_CR::Real=4.0/3.0, xH::Real=0.76) =
    GadgetPhysical( DT(l_unit), DT(m_unit), DT(v_unit),
                    a_scale=DT(a_scale), hpar=DT(hpar),
                    γ_th=DT(γ_th), γ_CR=DT(γ_CR), xH=DT(xH) )


text:
function allzeros(::Type{T}) where T
    if jlsizeof(T) > 0
        first(reinterpret(T,zeros(UInt8, jlsizeof(T))))
    else
        T()
    end
end

"""
    InlineUnionEl{T1,T2}(mask::UInt8, t1::T1, t2::T2)
Custom serialization struct for two member isbits union
fields e.g. in other structs or arrays.
To indicate that t1 is relevant the mask takes the value `UInt8(0)`
and for t2 `UInt8(255)`
"""
struct InlineUnionEl{T1,T2}
    mask::UInt8
    t1::T1
    t2::T2
    InlineUnionEl{T1,T2}(mask::UInt8, x::T1, y::T2) where {T1,T2} = new{T1,T2}(mask, x, y)
    InlineUnionEl{T1,T2}(x::T1) where {T1,T2} = new{T1,T2}(UInt8(0), x, allzeros(T2))
    InlineUnionEl{T1,T2}(x::T2) where {T1,T2} = new{T1,T2}(UInt8(255), allzeros(T1), x)
end

#convert2union(::Union, x::InlineUnionEl) = iszero(x.mask) ? x.t1 : x.t2
# The above convert method is ambiguous for Union{Nothing, Int}
# in julia v1.0
convert2union(x::InlineUnionEl) = iszero(x.mask) ? x.t1 : x.t2

function writeasbits(T::Union)
    types = Base.uniontypes(T)
    length(types) == 2 && isbitstype(types[1]) && isbitstype(types[2])
end

function write_dataset(f::JLDFile, x::Array{T}, wsession::JLDWriteSession, compress=f.compress) where {T}
    if T isa Union && writeasbits(T)
        # Conversion has to be done earlier here because
        # vectors are special cased in dispatch
        y = InlineUnionEl{Base.uniontypes(T)...}.(x)
    else
        y = x
    end
    odr = objodr(y)
    write_dataset(f, WriteDataspace(f, y, odr), h5type(f, y), odr, y, wsession, compress)::RelOffset
end

# This function is identical to the one in data.jl
# exept for the ReadRepresentation and the very last line where the data is
# converted back into a Union Array
function read_array(f::JLDFile, dataspace::ReadDataspace,
                    rr::ReadRepresentation{InlineUnionEl{T1,T2},RR}, data_length::Int,
                    filter_id::UInt16, header_offset::RelOffset,
                    attributes::Union{Vector{ReadAttribute},Nothing}) where {T1, T2,RR}
    io = f.io
    data_offset = position(io)
    ndims, offset = get_ndims_offset(f, dataspace, attributes)
    seek(io, offset)
    v = construct_array(io, InlineUnionEl{T1,T2}, Val(Int(ndims)))
    n = length(v)
    seek(io, data_offset)
    if !iszero(filter_id)
        read_compressed_array!(v, f, rr, data_length, filter_id)
    else
        read_array!(v, f, rr)
    end

    # Union{T1, T2}[v;]
    # The above syntax is not compatible to julia v1.0
    u = Union{T1, T2}[convert2union.(v);]
    header_offset !== NULL_REFERENCE && (f.jloffset[header_offset] = WeakRef(u))
    return u
end


text:
using Pkg
Pkg.activate(".")

using Genie, HTTP
import Genie.Router: route

route("/hello") do
  "Welcome to Genie!"
end
Genie.AppServer.startup(; open_browser = false)

HTTP.get("http://localhost:8000/hello")

exit(0)


text:
using AWSLambda

image_name = "octech/$(replace(basename(pwd()), "_", "")):$VERSION"

if length(ARGS) == 0 || ARGS[1] == "build"
    run(`docker build --build-arg JL_VERSION=$VERSION -t $image_name .`)
end

module LambdaTest

    using JSON

    import ..image_name
    import ..AWSLambda.serialize64

    function test_jl_eval_lambda(input)
        p = Pipe()
        @async (write(p, JSON.json(input)); close(p))
        docker = `docker run --rm -i -e DOCKER_LAMBDA_USE_STDIN=1 $image_name`
        run(pipeline(p, docker))
    end

    function invoke_jl_lambda(f)
        args = (f,)
        test_jl_eval_lambda(Dict("jl_data" => serialize64(args)))
    end

    lambda_call(f) =
        (a...) -> invoke_jl_lambda(eval(Main,:(()->$f($a...))))

    lambda_eval(expr) = invoke_jl_lambda(expr)

    macro lambda_eval(expr)
        if expr.head == :block
            expr = [e for e in expr.args]
        else
            expr = QuoteNode(expr)
        end
        :(lambda_eval($expr))
    end
end

if length(ARGS) > 0 && ARGS[1] == "test"

    LambdaTest.test_jl_eval_lambda("println(VERSION)")
    LambdaTest.test_jl_eval_lambda(
        Dict("jl_data" => AWSLambda.serialize64((()->println(VERSION),))))

    LambdaTest.lambda_call(println)("Foo")

    LambdaTest.lambda_eval(:(println("Foo")))

    LambdaTest.@lambda_eval println("Foo")

    LambdaTest.@lambda_eval begin
        module Foo

            export foo

            using HTTP
            using JSON

            const url = "http://httpbin.org/ip"

            function foo()
                JSON.parse(String(HTTP.get(url).body))
            end
        end

        using .Foo

        println(foo())
    end

    LambdaTest.lambda_eval([
        :(module Foo

            export foo

            using HTTP
            using JSON

            const url = "http://httpbin.org/ip"

            function foo()
                JSON.parse(String(HTTP.get(url).body))
            end
        end),
        :(
            using .Foo;
            println(foo())
        )])
end


text:
const NAIF_IDS = Dict{ASCIIString, Int}(
    "SOLAR_SYSTEM_BARYCENTER" => 0,
    "SSB"                     => 0,
    "SOLAR SYSTEM BARYCENTER" => 0,
    "MERCURY_BARYCENTER"      => 1,
    "MERCURY BARYCENTER"      => 1,
    "VENUS_BARYCENTER"        => 2,
    "VENUS BARYCENTER"        => 2,
    "EARTH_BARYCENTER"        => 3,
    "EMB"                     => 3,
    "EARTH MOON BARYCENTER"   => 3,
    "EARTH-MOON BARYCENTER"   => 3,
    "EARTH BARYCENTER"        => 3,
    "MARS_BARYCENTER"         => 4,
    "MARS BARYCENTER"         => 4,
    "JUPITER_BARYCENTER"      => 5,
    "JUPITER BARYCENTER"      => 5,
    "SATURN_BARYCENTER"       => 6,
    "SATURN BARYCENTER"       => 6,
    "URANUS_BARYCENTER"       => 7,
    "URANUS BARYCENTER"       => 7,
    "NEPTUNE_BARYCENTER"      => 8,
    "NEPTUNE BARYCENTER"      => 8,
    "PLUTO_BARYCENTER"        => 9,
    "PLUTO BARYCENTER"        => 9,
    "SUN"                     => 10,
    "MERCURY"    => 199,
    "VENUS"      => 299,
    "EARTH"      => 399,
    "MOON"       => 301,
    "MARS"       => 499,
    "PHOBOS"     => 401,
    "DEIMOS"     => 402,
    "JUPITER"    => 599,
    "IO"         => 501,
    "EUROPA"     => 502,
    "GANYMEDE"   => 503,
    "CALLISTO"   => 504,
    "AMALTHEA"   => 505,
    "HIMALIA"    => 506,
    "ELARA"      => 507,
    "PASIPHAE"   => 508,
    "SINOPE"     => 509,
    "LYSITHEA"   => 510,
    "CARME"      => 511,
    "ANANKE"     => 512,
    "LEDA"       => 513,
    "THEBE"      => 514,
    "ADRASTEA"   => 515,
    "METIS"      => 516,
    "CALLIRRHOE" => 517,
    "THEMISTO"   => 518,
    "MAGACLITE"  => 519,
    "TAYGETE"    => 520,
    "CHALDENE"   => 521,
    "HARPALYKE"  => 522,
    "KALYKE"     => 523,
    "IOCASTE"    => 524,
    "ERINOME"    => 525,
    "ISONOE"     => 526,
    "PRAXIDIKE"  => 527,
    "AUTONOE"    => 528,
    "THYONE"     => 529,
    "HERMIPPE"   => 530,
    "AITNE"      => 531,
    "EURYDOME"   => 532,
    "EUANTHE"    => 533,
    "EUPORIE"    => 534,
    "ORTHOSIE"   => 535,
    "SPONDE"     => 536,
    "KALE"       => 537,
    "PASITHEE"   => 538,
    "HEGEMONE"   => 539,
    "MNEME"      => 540,
    "AOEDE"      => 541,
    "THELXINOE"  => 542,
    "ARCHE"      => 543,
    "KALLICHORE" => 544,
    "HELIKE"     => 545,
    "CARPO"      => 546,
    "EUKELADE"   => 547,
    "CYLLENE"    => 548,
    "KORE"       => 549,
    "HERSE"      => 550,
    "SATURN"     => 699,
    "MIMAS"      => 601,
    "ENCELADUS"  => 602,
    "TETHYS"     => 603,
    "DIONE"      => 604,
    "RHEA"       => 605,
    "TITAN"      => 606,
    "HYPERION"   => 607,
    "IAPETUS"    => 608,
    "PHOEBE"     => 609,
    "JANUS"      => 610,
    "EPIMETHEUS" => 611,
    "HELENE"     => 612,
    "TELESTO"    => 613,
    "CALYPSO"    => 614,
    "ATLAS"      => 615,
    "PROMETHEUS" => 616,
    "PANDORA"    => 617,
    "PAN"        => 618,
    "YMIR"       => 619,
    "PAALIAQ"    => 620,
    "TARVOS"     => 621,
    "IJIRAQ"     => 622,
    "SUTTUNGR"   => 623,
    "KIVIUQ"     => 624,
    "MUNDILFARI" => 625,
    "ALBIORIX"   => 626,
    "SKATHI"     => 627,
    "ERRIAPUS"   => 628,
    "SIARNAQ"    => 629,
    "THRYMR"     => 630,
    "NARVI"      => 631,
    "METHONE"    => 632,
    "PALLENE"    => 633,
    "POLYDEUCES" => 634,
    "DAPHNIS"    => 635,
    "AEGIR"      => 636,
    "BEBHIONN"   => 637,
    "BERGELMIR"  => 638,
    "BESTLA"     => 639,
    "FARBAUTI"   => 640,
    "FENRIR"     => 641,
    "FORNJOT"    => 642,
    "HATI"       => 643,
    "HYRROKKIN"  => 644,
    "KARI"       => 645,
    "LOGE"       => 646,
    "SKOLL"      => 647,
    "SURTUR"     => 648,
    "ANTHE"      => 649,
    "JARNSAXA"   => 650,
    "GREIP"      => 651,
    "TARQEQ"     => 652,
    "AEGAEON"    => 653,
    "URANUS"     => 799,
    "ARIEL"      => 701,
    "UMBRIEL"    => 702,
    "TITANIA"    => 703,
    "OBERON"     => 704,
    "MIRANDA"    => 705,
    "CORDELIA"   => 706,
    "OPHELIA"    => 707,
    "BIANCA"     => 708,
    "CRESSIDA"   => 709,
    "DESDEMONA"  => 710,
    "JULIET"     => 711,
    "PORTIA"     => 712,
    "ROSALIND"   => 713,
    "BELINDA"    => 714,
    "PUCK"       => 715,
    "CALIBAN"    => 716,
    "SYCORAX"    => 717,
    "PROSPERO"   => 718,
    "SETEBOS"    => 719,
    "STEPHANO"   => 720,
    "TRINCULO"   => 721,
    "FRANCISCO"  => 722,
    "MARGARET"   => 723,
    "FERDINAND"  => 724,
    "PERDITA"    => 725,
    "MAB"        => 726,
    "CUPID"      => 727,
    "NEPTUNE"    => 899,
    "TRITON"     => 801,
    "NEREID"     => 802,
    "NAIAD"      => 803,
    "THALASSA"   => 804,
    "DESPINA"    => 805,
    "GALATEA"    => 806,
    "LARISSA"    => 807,
    "PROTEUS"    => 808,
    "HALIMEDE"   => 809,
    "PSAMATHE"   => 810,
    "SAO"        => 811,
    "LAOMEDEIA"  => 812,
    "NESO"       => 813,
    "PLUTO"      => 999,
    "CHARON"     => 901,
    "NIX"        => 902,
    "HYDRA"      => 903,
    "KERBEROS"   => 904,
    "STYX"       => 905,
    "GEOTAIL"                             => -1,
    "MOM"                                 => -3,
    "MARS ORBITER MISSION"                => -3,
    "AKATSUKI"                            => -5,
    "VCO"                                 => -5,
    "PLC"                                 => -5,
    "PLANET-C"                            => -5,
    "P6"                                  => -6,
    "PIONEER-6"                           => -6,
    "P7"                                  => -7,
    "PIONEER-7"                           => -7,
    "WIND"                                => -8,
    "VENUS ORBITER"                       => -12,
    "P12"                                 => -12,
    "PIONEER 12"                          => -12,
    "LADEE"                               => -12,
    "POLAR"                               => -13,
    "MGN"                                 => -18,
    "MAGELLAN"                            => -18,
    "LCROSS"                              => -18,
    "P8"                                  => -20,
    "PIONEER-8"                           => -20,
    "SOHO"                                => -21,
    "P10"                                 => -23,
    "PIONEER-10"                          => -23,
    "P11"                                 => -24,
    "PIONEER-11"                          => -24,
    "LP"                                  => -25,
    "LUNAR PROSPECTOR"                    => -25,
    "VK1"                                 => -27,
    "VIKING 1 ORBITER"                    => -27,
    "STARDUST"                            => -29,
    "SDU"                                 => -29,
    "NEXT"                                => -29,
    "VK2"                                 => -30,
    "VIKING 2 ORBITER"                    => -30,
    "DS-1"                                => -30,
    "VG1"                                 => -31,
    "VOYAGER 1"                           => -31,
    "VG2"                                 => -32,
    "VOYAGER 2"                           => -32,
    "CLEMENTINE"                          => -40,
    "MEX"                                 => -41,
    "MARS EXPRESS"                        => -41,
    "BEAGLE2"                             => -44,
    "BEAGLE 2"                            => -44,
    "MS-T5"                               => -46,
    "SAKIGAKE"                            => -46,
    "PLANET-A"                            => -47,
    "SUISEI"                              => -47,
    "GNS"                                 => -47,
    "GENESIS"                             => -47,
    "HUBBLE SPACE TELESCOPE"              => -48,
    "HST"                                 => -48,
    "MARS PATHFINDER"                     => -53,
    "MPF"                                 => -53,
    "MARS ODYSSEY"                        => -53,
    "MARS SURVEYOR 01 ORBITER"            => -53,
    "ARM"                                 => -54,
    "ASTEROID RETRIEVAL MISSION"          => -54,
    "ULYSSES"                             => -55,
    "VSOP"                                => -58,
    "HALCA"                               => -58,
    "RADIOASTRON"                         => -59,
    "JUNO"                                => -61,
    "ORX"                                 => -64,
    "OSIRIS-REX"                          => -64,
    "VEGA 1"                              => -66,
    "VEGA 2"                              => -67,
    "MMO"                                 => -68,
    "MERCURY MAGNETOSPHERIC ORBITER"      => -68,
    "MPO"                                 => -69,
    "MERCURY PLANETARY ORBITER"           => -69,
    "DEEP IMPACT IMPACTOR SPACECRAFT"     => -70,
    "MRO"                                 => -74,
    "MARS RECON ORBITER"                  => -74,
    "MSL"                                 => -76,
    "MARS SCIENCE LABORATORY"             => -76,
    "GLL"                                 => -77,
    "GALILEO ORBITER"                     => -77,
    "GIOTTO"                              => -78,
    "SPITZER"                             => -79,
    "SPACE INFRARED TELESCOPE FACILITY"   => -79,
    "SIRTF"                               => -79,
    "CASSINI ITL"                         => -81,
    "CAS"                                 => -82,
    "CASSINI"                             => -82,
    "PHOENIX"                             => -84,
    "LRO"                                 => -85,
    "LUNAR RECON ORBITER"                 => -85,
    "LUNAR RECONNAISSANCE ORBITER"        => -85,
    "CH1"                                 => -86,
    "CHANDRAYAAN-1"                       => -86,
    "CASSINI SIMULATION"                  => -90,
    "NEAR EARTH ASTEROID RENDEZVOUS"      => -93,
    "NEAR"                                => -93,
    "MO"                                  => -94,
    "MARS OBSERVER"                       => -94,
    "MGS"                                 => -94,
    "MARS GLOBAL SURVEYOR"                => -94,
    "MGS SIMULATION"                      => -95,
    "SPP"                                 => -96,
    "SOLAR PROBE PLUS"                    => -96,
    "TOPEX/POSEIDON"                      => -97,
    "NEW HORIZONS"                        => -98,
    "TROPICAL RAINFALL MEASURING MISSION" => -107,
    "TRMM"                                => -107,
    "ICE"                                 => -112,
    "MARS POLAR LANDER"                   => -116,
    "MPL"                                 => -116,
    "BEPICOLOMBO"                         => -121,
    "MARS CLIMATE ORBITER"                => -127,
    "MCO"                                 => -127,
    "MUSES-C"                             => -130,
    "HAYABUSA"                            => -130,
    "SELENE"                              => -131,
    "KAGUYA"                              => -131,
    "DRTS-W"                              => -135,
    "EPOCH"                               => -140,
    "DIXI"                                => -140,
    "EPOXI"                               => -140,
    "DEEP IMPACT FLYBY SPACECRAFT"        => -140,
    "TERRA"                               => -142,
    "EOS-AM1"                             => -142,
    "SOLO"                                => -144,
    "SOLAR ORBITER"                       => -144,
    "LUNAR-A"                             => -146,
    "CASSINI PROBE"                       => -150,
    "HUYGENS PROBE"                       => -150,
    "CASP"                                => -150,
    "AXAF"                                => -151,
    "CHANDRA"                             => -151,
    "AQUA"                                => -154,
    "EUROPA ORBITER"                      => -159,
    "YOHKOH"                              => -164,
    "SOLAR-A"                             => -164,
    "MAP"                                 => -165,
    "IMAGE"                               => -166,
    "JWST"                                => -170,
    "JAMES WEBB SPACE TELESCOPE"          => -170,
    "GRAIL-A"                             => -177,
    "PLANET-B"                            => -178,
    "NOZOMI"                              => -178,
    "GRAIL-B"                             => -181,
    "CLUSTER 1"                           => -183,
    "CLUSTER 2"                           => -185,
    "MUSES-B"                             => -188,
    "NSYT"                                => -189,
    "INSIGHT"                             => -189,
    "SIM"                                 => -190,
    "CLUSTER 3"                           => -194,
    "CLUSTER 4"                           => -196,
    "INTEGRAL"                            => -198,
    "CONTOUR"                             => -200,
    "MAVEN"                               => -202,
    "DAWN"                                => -203,
    "SOIL MOISTURE ACTIVE AND PASSIVE"    => -205,
    "SMAP"                                => -205,
    "STV51"                               => -212,
    "STV52"                               => -213,
    "STV53"                               => -214,
    "ROSETTA"                             => -226,
    "KEPLER"                              => -227,
    "GLL PROBE"                           => -228,
    "GALILEO PROBE"                       => -228,
    "STEREO AHEAD"                        => -234,
    "STEREO BEHIND"                       => -235,
    "MESSENGER"                           => -236,
    "SMART1"                              => -238,
    "SM1"                                 => -238,
    "S1"                                  => -238,
    "SMART-1"                             => -238,
    "VEX"                                 => -248,
    "VENUS EXPRESS"                       => -248,
    "OPPORTUNITY"                         => -253,
    "MER-1"                               => -253,
    "SPIRIT"                              => -254,
    "MER-2"                               => -254,
    "RADIATION BELT STORM PROBE A"        => -362,
    "RBSP_A"                              => -362,
    "RADIATION BELT STORM PROBE B"        => -363,
    "RBSP_B"                              => -363,
    "RSAT"                                => -500,
    "SELENE Relay Satellite"              => -500,
    "SELENE Rstar"                        => -500,
    "Rstar"                               => -500,
    "VSAT"                                => -502,
    "SELENE VLBI Radio Satellite"         => -502,
    "SELENE VRAD Satellite"               => -502,
    "SELENE Vstar"                        => -502,
    "Vstar"                               => -502,
    "MARS-96"                             => -550,
    "M96"                                 => -550,
    "MARS 96"                             => -550,
    "MARS96"                              => -550,
    "SPRINT-A"                            => -750,
    "AREND"                               => 1000001,
    "AREND-RIGAUX"                        => 1000002,
    "ASHBROOK-JACKSON"                    => 1000003,
    "BOETHIN"                             => 1000004,
    "BORRELLY"                            => 1000005,
    "BOWELL-SKIFF"                        => 1000006,
    "BRADFIELD"                           => 1000007,
    "BROOKS 2"                            => 1000008,
    "BRORSEN-METCALF"                     => 1000009,
    "BUS"                                 => 1000010,
    "CHERNYKH"                            => 1000011,
    "67P/CHURYUMOV-GERASIMENKO (1969 R1)" => 1000012,
    "CHURYUMOV-GERASIMENKO"               => 1000012,
    "CIFFREO"                             => 1000013,
    "CLARK"                               => 1000014,
    "COMAS SOLA"                          => 1000015,
    "CROMMELIN"                           => 1000016,
    "D""ARREST"                           => 1000017,
    "DANIEL"                              => 1000018,
    "DE VICO-SWIFT"                       => 1000019,
    "DENNING-FUJIKAWA"                    => 1000020,
    "DU TOIT 1"                           => 1000021,
    "DU TOIT-HARTLEY"                     => 1000022,
    "DUTOIT-NEUJMIN-DELPORTE"             => 1000023,
    "DUBIAGO"                             => 1000024,
    "ENCKE"                               => 1000025,
    "FAYE"                                => 1000026,
    "FINLAY"                              => 1000027,
    "FORBES"                              => 1000028,
    "GEHRELS 1"                           => 1000029,
    "GEHRELS 2"                           => 1000030,
    "GEHRELS 3"                           => 1000031,
    "GIACOBINI-ZINNER"                    => 1000032,
    "GICLAS"                              => 1000033,
    "GRIGG-SKJELLERUP"                    => 1000034,
    "GUNN"                                => 1000035,
    "HALLEY"                              => 1000036,
    "HANEDA-CAMPOS"                       => 1000037,
    "HARRINGTON"                          => 1000038,
    "HARRINGTON-ABELL"                    => 1000039,
    "HARTLEY 1"                           => 1000040,
    "HARTLEY 2"                           => 1000041,
    "HARTLEY-IRAS"                        => 1000042,
    "HERSCHEL-RIGOLLET"                   => 1000043,
    "HOLMES"                              => 1000044,
    "HONDA-MRKOS-PAJDUSAKOVA"             => 1000045,
    "HOWELL"                              => 1000046,
    "IRAS"                                => 1000047,
    "JACKSON-NEUJMIN"                     => 1000048,
    "JOHNSON"                             => 1000049,
    "KEARNS-KWEE"                         => 1000050,
    "KLEMOLA"                             => 1000051,
    "KOHOUTEK"                            => 1000052,
    "KOJIMA"                              => 1000053,
    "KOPFF"                               => 1000054,
    "KOWAL 1"                             => 1000055,
    "KOWAL 2"                             => 1000056,
    "KOWAL-MRKOS"                         => 1000057,
    "KOWAL-VAVROVA"                       => 1000058,
    "LONGMORE"                            => 1000059,
    "LOVAS 1"                             => 1000060,
    "MACHHOLZ"                            => 1000061,
    "MAURY"                               => 1000062,
    "NEUJMIN 1"                           => 1000063,
    "NEUJMIN 2"                           => 1000064,
    "NEUJMIN 3"                           => 1000065,
    "OLBERS"                              => 1000066,
    "PETERS-HARTLEY"                      => 1000067,
    "PONS-BROOKS"                         => 1000068,
    "PONS-WINNECKE"                       => 1000069,
    "REINMUTH 1"                          => 1000070,
    "REINMUTH 2"                          => 1000071,
    "RUSSELL 1"                           => 1000072,
    "RUSSELL 2"                           => 1000073,
    "RUSSELL 3"                           => 1000074,
    "RUSSELL 4"                           => 1000075,
    "SANGUIN"                             => 1000076,
    "SCHAUMASSE"                          => 1000077,
    "SCHUSTER"                            => 1000078,
    "SCHWASSMANN-WACHMANN 1"              => 1000079,
    "SCHWASSMANN-WACHMANN 2"              => 1000080,
    "SCHWASSMANN-WACHMANN 3"              => 1000081,
    "SHAJN-SCHALDACH"                     => 1000082,
    "SHOEMAKER 1"                         => 1000083,
    "SHOEMAKER 2"                         => 1000084,
    "SHOEMAKER 3"                         => 1000085,
    "SINGER-BREWSTER"                     => 1000086,
    "SLAUGHTER-BURNHAM"                   => 1000087,
    "SMIRNOVA-CHERNYKH"                   => 1000088,
    "STEPHAN-OTERMA"                      => 1000089,
    "SWIFT-GEHRELS"                       => 1000090,
    "TAKAMIZAWA"                          => 1000091,
    "TAYLOR"                              => 1000092,
    "TEMPEL_1"                            => 1000093,
    "TEMPEL 1"                            => 1000093,
    "TEMPEL 2"                            => 1000094,
    "TEMPEL-TUTTLE"                       => 1000095,
    "TRITTON"                             => 1000096,
    "TSUCHINSHAN 1"                       => 1000097,
    "TSUCHINSHAN 2"                       => 1000098,
    "TUTTLE"                              => 1000099,
    "TUTTLE-GIACOBINI-KRESAK"             => 1000100,
    "VAISALA 1"                           => 1000101,
    "VAN BIESBROECK"                      => 1000102,
    "VAN HOUTEN"                          => 1000103,
    "WEST-KOHOUTEK-IKEMURA"               => 1000104,
    "WHIPPLE"                             => 1000105,
    "WILD 1"                              => 1000106,
    "WILD 2"                              => 1000107,
    "WILD 3"                              => 1000108,
    "WIRTANEN"                            => 1000109,
    "WOLF"                                => 1000110,
    "WOLF-HARRINGTON"                     => 1000111,
    "LOVAS 2"                             => 1000112,
    "URATA-NIIJIMA"                       => 1000113,
    "WISEMAN-SKIFF"                       => 1000114,
    "HELIN"                               => 1000115,
    "MUELLER"                             => 1000116,
    "SHOEMAKER-HOLT 1"                    => 1000117,
    "HELIN-ROMAN-CROCKETT"                => 1000118,
    "HARTLEY 3"                           => 1000119,
    "PARKER-HARTLEY"                      => 1000120,
    "HELIN-ROMAN-ALU 1"                   => 1000121,
    "WILD 4"                              => 1000122,
    "MUELLER 2"                           => 1000123,
    "MUELLER 3"                           => 1000124,
    "SHOEMAKER-LEVY 1"                    => 1000125,
    "SHOEMAKER-LEVY 2"                    => 1000126,
    "HOLT-OLMSTEAD"                       => 1000127,
    "METCALF-BREWINGTON"                  => 1000128,
    "LEVY"                                => 1000129,
    "SHOEMAKER-LEVY 9"                    => 1000130,
    "HYAKUTAKE"                           => 1000131,
    "HALE-BOPP"                           => 1000132,
    "C/2013 A1"                           => 1003228,
    "SIDING SPRING"                       => 1003228,
    "GASPRA"            => 9511010,
    "IDA"               => 2431010,
    "DACTYL"            => 2431011,
    "CERES"             => 2000001,
    "PALLAS"            => 2000002,
    "VESTA"             => 2000004,
    "LUTETIA"           => 2000021,
    "KLEOPATRA"         => 2000216,
    "EROS"              => 2000433,
    "DAVIDA"            => 2000511,
    "MATHILDE"          => 2000253,
    "STEINS"            => 2002867,
    "1992KD"            => 2009969,
    "BRAILLE"           => 2009969,
    "WILSON-HARRINGTON" => 2004015,
    "TOUTATIS"          => 2004179,
    "ITOKAWA"           => 2025143,
    "NOTO"       => 398989,
    "NEW NORCIA" => 398990,
    "GOLDSTONE"  => 399001,
    "CANBERRA"   => 399002,
    "MADRID"     => 399003,
    "USUDA"      => 399004,
    "DSS-05"     => 399005,
    "PARKES"     => 399005,
    "DSS-12"     => 399012,
    "DSS-13"     => 399013,
    "DSS-14"     => 399014,
    "DSS-15"     => 399015,
    "DSS-16"     => 399016,
    "DSS-17"     => 399017,
    "DSS-23"     => 399023,
    "DSS-24"     => 399024,
    "DSS-25"     => 399025,
    "DSS-26"     => 399026,
    "DSS-27"     => 399027,
    "DSS-28"     => 399028,
    "DSS-33"     => 399033,
    "DSS-34"     => 399034,
    "DSS-42"     => 399042,
    "DSS-43"     => 399043,
    "DSS-45"     => 399045,
    "DSS-46"     => 399046,
    "DSS-49"     => 399049,
    "DSS-53"     => 399053,
    "DSS-54"     => 399054,
    "DSS-55"     => 399055,
    "DSS-61"     => 399061,
    "DSS-63"     => 399063,
    "DSS-64"     => 399064,
    "DSS-65"     => 399065,
    "DSS-66"     => 399066,
)

function naifid(str::AbstractString)
    NAIF_IDS[uppercase(str)]
end

function name_from_naifid(searchid::Int)
    if searchid == 0
        return "SOLAR SYSTEM BARYCENTER"
    elseif searchid == 3
        return "EARTH-MOON BARYCENTER"
    end
    for (name, id) in NAIF_IDS
        if searchid == id && !contains(name, "_")
            return name
        end
    end
end


text:
"""
    License(; name="MIT", path=nothing, destination="LICENSE")

Creates a license file.

## Keyword Arguments
- `name::AbstractString`: Name of a license supported by PkgTemplates.
  Available licenses can be seen
  [here](https://github.com/invenia/PkgTemplates.jl/tree/master/templates/licenses).
- `path::Union{AbstractString, Nothing}`: Path to a custom license file.
  This keyword takes priority over `name`.
- `destination::AbstractString`: File destination, relative to the repository root.
  For example, `"LICENSE.md"` might be desired.
"""
struct License <: FilePlugin
    path::String
    destination::String
end

function License(;
    name::AbstractString="MIT",
    path::Union{AbstractString, Nothing}=nothing,
    destination::AbstractString="LICENSE",
)
    if path === nothing
        path = default_file("licenses", name)
        isfile(path) || throw(ArgumentError("License '$(basename(path))' is not available"))
    end
    return License(path, destination)
end

defaultkw(::Type{License}, ::Val{:path}) = nothing
defaultkw(::Type{License}, ::Val{:name}) = "MIT"
defaultkw(::Type{License}, ::Val{:destination}) = "LICENSE"

source(p::License) = p.path
destination(p::License) = p.destination
view(::License, t::Template, ::AbstractString) = Dict(
    "AUTHORS" => join(t.authors, ", "),
    "YEAR" => year(today()),
)

function prompt(::Type{License}, ::Type, ::Val{:name})
    options = readdir(default_file("licenses"))
    # Move MIT to the top.
    deleteat!(options, findfirst(==("MIT"), options))
    pushfirst!(options, "MIT")
    menu = RadioMenu(options; pagesize=length(options))
    println("Select a license:")
    idx = request(menu)
    return options[idx]
end

customizable(::Type{License}) = (:name => String,)


text:
"""
   module CovidRt

Compute time and area specific estimates of the reproductive number of Covid.
"""
module CovidRt

using DynamicHMC, TransformVariables, LogDensityProblems, Parameters, Distributions
using LinearAlgebra, Plots, StatsPlots, MCMCChains
using StaticArrays, DataFrames, Random

include("utils.jl")
export smooth, lagdiff

include("kalman.jl")
export kalman

include("rt.jl")
export RtModel, plotpostr

end # module


text:
#=
run a CBLIB instance
cblib_dir (defined in JuMP_test.jl) is the directory of CBLIB files
=#

struct CBLIBJuMP{T <: Real} <: ExampleInstanceJuMP{T}
    name::String # filename of CBLIB instance
end

function build(inst::CBLIBJuMP{T}) where {T <: Float64}
    # read in model from file
    model = JuMP.read_from_file(joinpath(cblib_dir, inst.name * ".cbf.gz"))

    # delete integer constraints
    JuMP.delete.(model, JuMP.all_constraints(model, JuMP.VariableRef, MOI.Integer))

    return model
end


text:
# ------------ Utilities ------------ #

function trace_retained(vcs::VectorizedCallSite,
                        s::K,
                        ks::Set,
                        min::Int,
                        o_len::Int,
                        n_len::Int,
                        args...) where K <: ConstrainedSelection
    w_adj = -sum(map(vcs.trace.subrecords[n_len + 1 : end]) do cl
                     get_score(cl)
                 end)
    new = vcs.trace.subrecords[1 : min - 1]
    new_ret = vcs.ret[1 : min - 1]

    # Start at min
    ss = get_sub(s, min)
    prev_cl = get_sub(vcs, min)
    if min == 1
        ret, u_cl, u_w, rd, ds = update(ss, prev_cl, UndefinedChange(), args...)
    else
        ret, u_cl, u_w, rd, ds = update(ss, prev_cl, UndefinedChange(), new_ret[min - 1]...)
    end
    push!(new_ret, ret)
    push!(new, u_cl)
    w_adj += u_w

    for i in min + 1 : n_len
        ss = get_sub(s, i)
        prev_cl = get_sub(vcs, i)
        ret, u_cl, u_w, rd, ds = update(ss, prev_cl, UndefinedChange(), new_ret[i - 1]...)
        push!(new_ret, ret)
        push!(new, u_cl)
        w_adj += u_w
    end
    return w_adj, new, new_ret
end

# TODO: finish.
function trace_new(vcs::VectorizedCallSite,
                   s::K,
                   ks::Set,
                   min::Int,
                   o_len::Int,
                   n_len::Int,
                   args...) where K <: ConstrainedSelection
    w_adj = 0.0
    new = vcs.trace.subrecords[1 : min - 1]
    new_ret = vcs.ret[1 : min - 1]

    # Start at min, check if it's less than old length. Otherwise, constraints will be applied during generate.
    if min <= o_len
        ss = get_sub(s, min)
        prev_cl = get_sub(vcs, min)
        if min == 1
            ret, u_cl, u_w, rd, ds = update(ss, prev_cl, UndefinedChange(), args...)
        else
            ret, u_cl, u_w, rd, ds = update(ss, prev_cl, UndefinedChange(), new_ret[min - 1]...)
        end
        push!(new_ret, ret)
        push!(new, u_cl)
        w_adj += u_w

        # From min, apply constraints and compute updates to weight.
        for i in min + 1 : o_len
            ss = get_sub(s, i)
            prev_cl = get_sub(vcs, i)
            ret, u_cl, u_w, rd, ds = update(ss, prev_cl, UndefinedChange(), new_ret[i - 1]...)
            push!(new_ret, ret)
            push!(new, u_cl)
            w_adj += u_w
        end
    end

    # Now, generate new call sites with constraints.
    for i in o_len + 1 : n_len
        ss = get_sub(s, i)
        ret, g_cl, g_w = generate(ss, vcs.fn, new_ret[i - 1]...)
        push!(new_ret, ret)
        push!(new, g_cl)
        w_adj += g_w
    end

    return w_adj, new, new_ret
end

# TODO: finish.
function trace_new(vcs::VectorizedCallSite,
                   s::ConstrainedEmptySelection,
                   ks::Set,
                   min::Int,
                   o_len::Int,
                   n_len::Int,
                   args...)
    w_adj = 0.0
    new = vcs.trace.subrecords[1 : min - 1]
    new_ret = vcs.ret[1 : min - 1]

    for i in o_len + 1 : n_len
        ret, g_cl = simulate(vcs.fn, new_ret[i - 1]...)
        push!(new_ret, ret)
        push!(new, g_cl)
    end

    return w_adj, new, new_ret
end

# ------------ Call sites ------------ #

@inline function (ctx::UpdateContext{C, T})(c::typeof(markov),
                                            addr::Address,
                                            call::Function,
                                            len::Int,
                                            args...) where {C <: HierarchicalCallSite, T <: HierarchicalTrace}
    vcs = get_prev(ctx, addr)
    n_len, o_len = len, length(vcs.ret)
    s = get_subselection(ctx, addr)
    min, ks = keyset(s, n_len)
    if n_len <= o_len
        w_adj, new, new_ret = trace_retained(vcs, s, ks, min, o_len, n_len, args...)
    else
        w_adj, new, new_ret = trace_new(vcs, s, ks, min, o_len, n_len, args...)
    end
    add_call!(ctx, addr, VectorizedCallSite{typeof(markov)}(VectorizedTrace(new), get_score(vcs) + w_adj, call, n_len, args, new_ret))
    increment!(ctx, w_adj)

    return new_ret
end

@inline function (ctx::UpdateContext{C, T})(c::typeof(markov),
                                            addr::Address,
                                            call::Function,
                                            len::Int,
                                            args...) where {C <: VectorizedCallSite, T <: VectorizedTrace}
    vcs = ctx.prev
    n_len, o_len = len, length(vcs.ret)
    s = get_subselection(ctx, addr)
    min, ks = keyset(s, n_len)
    if n_len <= o_len
        w_adj, new, new_ret = trace_retained(vcs, s, ks, min, o_len, n_len, args...)
    else
        w_adj, new, new_ret = trace_new(vcs, s, ks, min, o_len, n_len, args...)
    end

    # TODO: fix - allocate full vector.
    for n in new
        add_call!(ctx, n)
    end
    increment!(ctx, w_adj)

    return new_ret
end


text:
const FloatSigned = Union{IEEEFloat, Signed}

Base.:(+)(x::DoubleFloat{T}, y::FloatSigned, z::FloatSigned) where {T<:IEEEFloat}  = +(x, DoubleFloat{T}(y), DoubleFloat{T}(z))
Base.:(*)(x::DoubleFloat{T}, y::FloatSigned, z::FloatSigned) where {T<:IEEEFloat}  = *(x, DoubleFloat{T}(y), DoubleFloat{T}(z))
Base.:(+)(x::FloatSigned, y::DoubleFloat{T}, z::FloatSigned) where {T<:IEEEFloat}  = +(DoubleFloat{T}(x), y, DoubleFloat{T}(z))
Base.:(*)(x::FloatSigned, y::DoubleFloat{T}, z::FloatSigned) where {T<:IEEEFloat}  = *(DoubleFloat{T}(x), y, DoubleFloat{T}(z))
Base.:(+)(x::FloatSigned, y::FloatSigned, z::DoubleFloat{T}) where {T<:IEEEFloat}  = +(DoubleFloat{T}(x), DoubleFloat{T}(y), z)
Base.:(*)(x::FloatSigned, y::FloatSigned, z::DoubleFloat{T}) where {T<:IEEEFloat}  = *(DoubleFloat{T}(x), DoubleFloat{T}(y), z)


text:
module SymbolicML

using CategoricalArrays
using CSV
using DataFrames
using ExprRules
using ExprOptimization
# using MultivariateTimeSeries
using Plots
using StatsPlots
using Random
# using GBDTs

# include("dataset.jl")
include("ds.jl")
include("siemens.jl")
include("functions.jl")

export discrete_derivative, discrete_derivatives
export siemensDataInfo, siemensData

export select_attributes
export abs_energy
export absolute_maximum
export absolute_sum_of_changes
export agg_autocorrelation
export autocorrelation
export benford_correlation
export binned_entropy
export c3
export change_quantiles
export cid_ce
export count_above
export count_above_mean
export count_below
export count_below_mean
export first_location_of_maximum
export first_location_of_minimum
export has_duplicate
export has_duplicate_max
export has_duplicate_min
export large_standard_deviation
export last_location_of_maximum
export last_location_of_minimum
export mean_abs_change
export mean_change
export mean_n_absolute_max
export longest_strike_above_mean
export longest_strike_below_mean
export mean_second_derivative_central
export number_crossing_m
export percentage_of_reoccurring_datapoints_to_all_datapoints
export percentage_of_reoccurring_values_to_all_values
export range_count
export ratio_beyond_r_sigma
export ratio_value_number_to_time_series_length
export root_mean_square
export sample_entropy
export sum_of_reoccurring_data_points

export ClassificationDataset
export ModalFrame
export ModalInstance

export attributes

end


text:
# *****************************************************************************
# Written by Ritchie Lee, ritchie.lee@sv.cmu.edu
# *****************************************************************************
# Copyright ã 2015, United States Government, as represented by the
# Administrator of the National Aeronautics and Space Administration. All
# rights reserved.  The Reinforcement Learning Encounter Simulator (RLES)
# platform is licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. You
# may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0. Unless required by applicable
# law or agreed to in writing, software distributed under the License is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the specific language
# governing permissions and limitations under the License.
# _____________________________________________________________________________
# Reinforcement Learning Encounter Simulator (RLES) includes the following
# third party software. The SISLES.jl package is licensed under the MIT Expat
# License: Copyright (c) 2014: Youngjun Kim.
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
# "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# *****************************************************************************

include("../helpers/TikzUtils.jl")
include("groupattributes.jl")

using RunCases
using Obj2Dict

using CPUTime
using TikzPictures
import PGFPlots: Plots,Axis
using RLESUtils, PGFPlotUtils

function cts_2ac_mcts_script(encounters::Vector{Int64}, maxtimes::Vector{Float64})
  #maxtimes are in seconds for the entire run (not per step)

  cases = generate_cases(("sim_params.encounter_number",
                          encounters),
                         ("mcts_params.maxtime_s",
                          maxtimes / 50.0),
                         ("mcts_params.n",
                          [typemax(Int64)]))

  add_field!(cases, "study_params.fileroot", t -> "trajSaveMCTS_$(50.0 * t)s",
             ["mcts_params.maxtime_s"])

  trajSave(MCTSStudy(), cases)

end

function cts_2ac_mcbest_script(encounters::Vector{Int64}, maxtimes::Vector{Float64})
  #maxtimes are in seconds for the entire run

  cases = generate_cases(("sim_params.encounter_number",
                          encounters),
                         ("study_params.nsamples",
                          [typemax(Int64)]),
                         ("study_params.maxtime_s",
                          maxtimes))

  add_field!(cases, "study_params.fileroot", t -> "trajSaveMCBEST_$(t)s", ["study_params.maxtime_s"])

  trajSave(MCBestStudy(), cases)

end

#TODO: implement saving these case gen dicts to/from json

function cts_vis{T<:AbstractString}(files::Vector{T}; outfileroot::AbstractString="cts_vis", format::Symbol=:TEXPDF)

  td = TikzDocument()

  ## This part for compute_time vs reward overlay
  d = groupattributes(files, sv_run_type, gettime, sv_reward)

  names = collect(keys(d))
  times = Vector{Float64}[]
  means = Vector{Float64}[]
  sems = Vector{Float64}[]
  ntrials = Int64[]

  for (runtype, xyvecs) in d

    #xyvecs is [(x,[y...])...]
    #t = x[1]
    #rewards = x[2]

    push!(times, map(x -> x[1], xyvecs))
    push!(means, map(x -> mean(x[2]), xyvecs))
    push!(sems, map(x -> std(x[2]) / sqrt(length(x[2])), xyvecs))

    lengths = map(x -> length(x[2]), xyvecs)
    push!(ntrials, Int(median(lengths)))

  end

  pgfplotcts_reward!(td, names, times, means, sems, ntrials)

  ## This part for compute_time vs number of nmacs overlay
  d = groupattributes(files, sv_run_type, gettime, sv_nmac)

  names = collect(keys(d))
  empty!(times)
  nmacs = Vector{Float64}[]
  empty!(ntrials)

  for (runtype, xyvecs) in d

    #xyvecs is [(x,[y...])...]
    #t = x[1]
    #nmac = x[2]

    push!(times, map(x -> x[1], xyvecs))
    push!(nmacs, map(x -> sum(x[2]), xyvecs))

    lengths = map(x -> length(x[2]), xyvecs)
    push!(ntrials, Int(median(lengths)))

  end
  pgfplotcts_nmacs!(td, names, times, nmacs, ntrials)
  plot_tikz(outfileroot, td, format=format)
  nothing
end

function gettime(d::SaveDict)

  runtype = sv_run_type(d)

  if runtype == "MCTS"
    sim_params = Obj2Dict.to_obj(d["sim_params"])
    dpw_params = Obj2Dict.to_obj(d["dpw_params"])
    t = dpw_params.maxtime_s * sim_params.max_steps #since maxtime for mctsdpw is per step
  elseif runtype == "MCBEST"
    p = Obj2Dict.to_obj(d["study_params"])
    t = p.maxtime_s
  else
    error("gettime::No such run type $(runtype)")
  end

  return t
end

function pgfplotcts_reward!{T<:AbstractString}(td::TikzDocument,
                            names::Vector{T},
                            times::Array{Vector{Float64}, 1},
                            means::Array{Vector{Float64}, 1},
                            sems::Array{Vector{Float64}, 1},
                            ntrials::Vector{Int64})

  plotArray = Plots.Plot[]

  n = length(times)
  for i = 1:length(times)
    push!(plotArray, Plots.ErrorBars(times[i], means[i], sems[i],
                                    #style="mark options={color=blue}",
                                    #mark="*",
                                    legendentry = "$(names[i])"))
  end

  tp = PGFPlots.plot(Axis(plotArray,
                          xlabel="Computation Time (s)",
                          ylabel="Reward",
                          title="Reward vs. Computation Time",
                          legendPos="south east"))

  cap = string("Reward vs. Computation Time Study. ntrials=$(ntrials[1]).") #TODO: make this more robust

  add_to_document!(td, tp, cap)

end

function pgfplotcts_nmacs!{T<:AbstractString}(td::TikzDocument,
                           names::Vector{T},
                           times::Array{Vector{Float64}, 1},
                           nmacs::Array{Vector{Float64}, 1},
                           ntrials::Vector{Int64})

  plotArray = Plots.Plot[]

  n = length(times)
  for i = 1:length(times)
    push!(plotArray,Plots.Linear(times[i], nmacs[i],
                                 #style="mark options={color=blue}",
                                 #mark="*",
                                 legendentry = "$(names[i])"))
  end

  tp = PGFPlots.plot(Axis(plotArray,
                          xlabel = "Computation Time (s)",
                          ylabel = "NMAC Count",
                          title = "NMAC Count vs. Computation Time",
                          legendPos = "north west"))

  cap = string("NMAC Count vs. Computation Time Study. ntrials=$(ntrials[1]).") #TODO: make this more robust

  add_to_document!(td, tp, cap)

end

max_stars_repo_name: sisl/RLESCAS

max_issues_repo_name: sisl/RLESCAS

max_forks_repo_name: sisl/RLESCAS


text:
using Gtk.ShortNames, Gtk.GConstants
using Winston
using RawFile
import Color

export viewer, ImageViewer

type ImageViewer <: Gtk.GtkWindow
  handle::Ptr{Gtk.GObject}
end

const uifile = joinpath( dirname(Base.source_path()), "Viewer.ui" )

function ImageViewer()

  println( uifile )

  c1 = @Canvas()
  builder = @Builder(filename=uifile)

  btnOpenFile = G_.object(builder, "btnOpenFile")
  cbDomain = G_.object(builder, "cbDomain")

  choices = ["Abs", "Phase", "Real", "Imag"]
  for c in choices
    push!(cbDomain, c)
  end
  setproperty!(cbDomain,:active,0)

  scSlice = G_.object(builder, "scSlice")
  adjSlice = @Adjustment(scSlice)
  setproperty!(adjSlice,:lower,1)
  setproperty!(adjSlice,:step_increment,1)

  sbX = G_.object(builder, "sbX")
  adjX = @Adjustment(sbX)
  setproperty!(adjX,:lower,1)
  setproperty!(adjX,:upper,1024)
  setproperty!(adjX,:value,68)
  setproperty!(adjX,:step_increment,1)

  sbY = G_.object(builder, "sbY")
  adjY = @Adjustment(sbY)
  setproperty!(adjY,:lower,1)
  setproperty!(adjY,:upper,1024)
  setproperty!(adjY,:value,40)
  setproperty!(adjY,:step_increment,1)

  signal_connect(btnOpenFile, "clicked") do widget
    dlg = @FileChooserDialog("Select file", @Null(), GtkFileChooserAction.OPEN, "gtk-open", GtkResponseType.OK)
    res = run(dlg)
    filename = ""
    if res == GtkResponseType.OK
      filename = Gtk.bytestring(G_.filename(FileChooser(dlg)),true)
      if isfile(filename)
        loadData(filename)
      end
    end
    destroy(dlg)
  end

  NX = 1
  NY = 1
  NZ = 1
  data = nothing
  function loadData(filename)
    println(filename)
    if isfile(filename)

      f = Rawfile(filename)
      data = f[]

      NX = size(data,1)
      NY = size(data,2)
      NZ = size(data,3)

      setproperty!(adjSlice,:upper,size(data,3))
      updateImages( nothing )
    end
  end

  canvasInitialized = false
  function initCanvas()
    println("Init Canvas ...")

    gridCanvas = G_.object(builder, "gridCanvas")
    gridCanvas[2,2] = c1

    canvasInitialized = true

    showall(gridCanvas)
  end

  plotting = false
  function updateImages( widget )
    println("Updating Image ...")

    if plotting
      return
    end

    plotting = true

    if data != nothing
      if !canvasInitialized
        initCanvas()
      end

      sl = int( getproperty(adjSlice, :value, Float64) )
      println(sl)
      sl = min(max(sl,1),NZ)

      #colormap("jet")
      colormap(reverse(Color.colormap("grays",256)))
      activeDomainText = bytestring( G_.active_text(cbDomain))
      if activeDomainText == "Abs"
        p1 = imagesc( abs( data[:,:,sl]' ) )
      elseif activeDomainText == "Real"
        p1 = imagesc( real( data[:,:,sl]' ) )
      elseif activeDomainText == "Imag"
        p1 = imagesc( imag( data[:,:,sl]' ) )
      else
        p1 = imagesc( angle( data[:,:,sl]' ) )
      end

      display(c1,p1)
    end

    plotting = false
  end

  signal_connect(updateImages, adjSlice, "value_changed")
  signal_connect(cbDomain, "changed") do w, other...
    updateImages( w )
  end

  win = G_.object(builder, "mainWindow")
  show(win)

  view = ImageViewer(win.handle)

  signal_connect(win,"destroy") do object, args...
   exit()
  end

  Gtk.gc_move_ref(view, win)
end

#ViewerWindow()
#if !isinteractive()
#  wait(Condition())
#end