text:
module button_

using IUP

export
	button

include("../src/libiup_h.jl")

#------------------ example html/examples/C/button.c --------------------------------------------
function button()
	IupOpen()	#Initializes IUP

	IupSetGlobal("UTF8MODE", "Yes")

	text = IupText("")	# Creates a text

	# Turns on read-only mode
	IupSetAttribute(text, "READONLY", "YES")

	# Associates text with handle "text"
	IupSetHandle ("text", text)

	pixmap_release = uint8([
		1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
		1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,4,4,3,3,3,3,2,2,
		1,1,3,3,3,3,3,4,4,4,4,3,3,3,2,2,
		1,1,3,3,3,3,3,4,4,4,4,3,3,3,2,2,
		1,1,3,3,3,3,3,3,4,4,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
		2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2])

	pixmap_press = uint8([
		1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
		1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,4,4,3,3,3,3,3,2,2,
		1,1,3,3,3,3,4,4,4,4,3,3,3,3,2,2,
		1,1,3,3,3,3,4,4,4,4,3,3,3,3,2,2,
		1,1,3,3,3,3,3,4,4,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
		2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2])

	pixmap_inactive = uint8([
		1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
		1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,4,4,3,3,3,3,2,2,
		1,1,3,3,3,3,3,4,4,4,4,3,3,3,2,2,
		1,1,3,3,3,3,3,4,4,4,4,3,3,3,2,2,
		1,1,3,3,3,3,3,3,4,4,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
		1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
		2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2])

	#Defines released button's image size
	img_release = IupImage (16, 16, pixmap_release);

	# Defines released button's image colors
	IupSetAttribute (img_release, "1", "215 215 215")
	IupSetAttribute (img_release, "2", "40 40 40")
	IupSetAttribute (img_release, "3", "30 50 210")
	IupSetAttribute (img_release, "4", "240 0 0")

	# Associates img_release with handle "img_release"
	IupSetHandle ("img_release", img_release)

	# Defines pressed button's image size
	img_press = IupImage (16, 16, pixmap_press)

	# Defines pressed button's image colors
	IupSetAttribute (img_press, "1", "40 40 40")
	IupSetAttribute (img_press, "2", "215 215 215")
	IupSetAttribute (img_press, "3", "0 20 180")
	IupSetAttribute (img_press, "4", "210 0 0")

	# Associates img_press with handle "img_press"
	IupSetHandle ("img_press", img_press)

	# Defines inactive button's image size
	img_inactive = IupImage (16, 16, pixmap_inactive)

	# Defines inactive button's image colors
	IupSetAttribute (img_inactive, "1", "215 215 215")
	IupSetAttribute (img_inactive, "2", "40 40 40")
	IupSetAttribute (img_inactive, "3", "100 100 100")
	IupSetAttribute (img_inactive, "4", "200 200 200")

	# Associates img_inactive with handle "img_inactive"
	IupSetHandle ("img_inactive", img_inactive)

	# Creates a button
	btn_image = IupButton("Button with image", "btn_image")

	# Sets released, pressed and inactive button images
	IupSetAttribute (btn_image, "IMAGE", "img_release")
	IupSetAttribute (btn_image, "IMPRESS", "img_press")
	IupSetAttribute (btn_image, "IMINACTIVE", "img_inactive")

	# Associates button callback with action bti_button_act
	IupSetAttribute (btn_image, "BUTTON_CB", "btn_image_button")

	# Associates btn_image with handle "btn_image"
	IupSetHandle ("btn_image", btn_image)

	# Creates a button
	btn_big = IupButton ("Big useless button", "")

	# Sets big button size
	IupSetAttribute (btn_big, "SIZE", "EIGHTHxEIGHTH")

	# Creates a button entitled Exit associated with action exit_act
	btn_exit = IupButton ("Exit", "btn_exit")

	# Creates a button entitled on/off associated with action onoff_act
	btn_on_off = IupButton("on/off", "btn_on_off")

	# Creates dialog with the four buttons and the text
	dlg = IupDialog (IupVbox (
							IupHbox (btn_image, btn_on_off, btn_exit, C_NULL),
							text,
							btn_big,
							C_NULL
							)
					);

	# Sets dialogs title to IupButton turns resize, maximize, minimize and menubox off
	IupSetAttributes (dlg, "EXPAND = YES, TITLE = IupButton, RESIZE = NO")
	IupSetAttributes (dlg, "MENUBOX = NO, MAXBOX = NO, MINBOX = NO")

	# Registers callbacks
	IupSetCallback (btn_exit,   "ACTION", cfunction(btn_exit_cb,   Int, (),))
	IupSetCallback (btn_on_off, "ACTION", cfunction(btn_on_off_cb, Int, (),))
	IupSetCallback (btn_image,  "ACTION", cfunction(btn_image_button_cb, Int, (Ptr{Ihandle}, Cint, Cint, Cint, Cint, Ptr{Uint8})))

	IupSetAttribute(btn_big, "BUTTON_CB", "bigtest");
	IupSetFunction("bigtest", cfunction(btn_big_button_cb, Int, (Ptr{Ihandle}, Cint, Cint)))

	# Shows dialog on the center of the screen
	IupShowXY (dlg, IUP_CENTER, IUP_CENTER)

	IupMainLoop()		# Initializes IUP main loop
	IupClose()			# And close it when ready
end

function btn_image_button_cb(self::Ptr{Ihandle}, b::Cint, e::Cint, x::Cint, y::Cint, t::Ptr{Uint8})
	# If the left button changed its state...
	if (b == IUP_BUTTON1)

		# Recovers "text" handle
		text = IupGetHandle("text")

		# If the button was pressed...
		if (e == 1)
			IupSetAttribute (text, "VALUE", "Red button pressed")
		else		# the button was released
			IupSetAttribute (text, "VALUE", "Red button released")
		end
	end

	# Executed function successfully
	return IUP_DEFAULT
end

function btn_on_off_cb()
	btn_image = IupGetHandle("btn_image")		#Recovers "btn_image" handle

	# If the button with with image is active...
	if (bytestring(IupGetAttribute (btn_image, "ACTIVE")) == "YES")
		# Deactivates the button with image */
		IupSetAttribute (btn_image, "ACTIVE","NO")
	else
		# Activates the button with image */
		IupSetAttribute (btn_image, "ACTIVE", "YES")
	end

	return IUP_DEFAULT
end

function btn_exit_cb()
  	return IUP_CLOSE		# Exits the program
end

function btn_big_button_cb(self::Ptr{Ihandle}, button::Cint, press::Cint)
	@printf("BUTTON_CB(button=%d, press=%d)\n", button, press)
	return IUP_DEFAULT
end

end 	# module


text:
using GeoData, Test, Statistics, Dates, Plots
using GeoData.LookupArrays, GeoData.Dimensions
import NCDatasets, ArchGDAL
using GeoData: FileArray, GRDfile, GDALfile

testpath = joinpath(dirname(pathof(GeoData)), "../test/")
include(joinpath(testpath, "test_utils.jl"))
const DD = DimensionalData

maybedownload("https://raw.githubusercontent.com/rspatial/raster/master/inst/external/rlogo.grd", "rlogo.grd")
maybedownload("https://github.com/rspatial/raster/raw/master/inst/external/rlogo.gri", "rlogo.gri")
stem = joinpath(testpath, "data/rlogo")
@test isfile(stem * ".grd")
@test isfile(stem * ".gri")
path = stem * ".gri"

@testset "Grd array" begin
    @time grdarray = GeoArray(path)

    @testset "open" begin
        @test all(open(A -> A[Y=1], grdarray) .=== grdarray[:, 1, :])
        tempfile = tempname()
        cp(stem * ".grd", tempfile * ".grd")
        cp(stem * ".gri", tempfile * ".gri")
        grdwritearray = GeoArray(tempfile * ".gri")
        open(grdwritearray; write=true) do A
            A .*= 2
        end
        @test GeoArray(tempfile * ".gri") == grdarray .* 2
    end

    @testset "read" begin
        A = read(grdarray)
        @test A isa GeoArray
        @test parent(A) isa Array
        A2 = zero(A)
        @time read!(grdarray, A2);
        A3 = zero(A)
        @time read!(path, A3);
        @test A == A2 == A3
    end

    @testset "array properties" begin
        @test grdarray isa GeoArray{Float32,3}
    end

    @testset "dimensions" begin
        @test length(val(dims(dims(grdarray), X))) == 101
        @test ndims(grdarray) == 3
        @test dims(grdarray) isa Tuple{<:X,<:Y,<:Band}
        @test refdims(grdarray) == ()
        @test bounds(grdarray) == ((0.0, 101.0), (0.0, 77.0), (1, 3))
    end

    @testset "other fields" begin
        @test missingval(grdarray) == -3.4f38
        @test metadata(grdarray) isa Metadata{GRDfile}
        @test name(grdarray) == Symbol("red:green:blue")
        @test label(grdarray) == "red:green:blue"
        @test units(grdarray) == nothing
        customgrdarray = GeoArray(path; name=:test, mappedcrs=EPSG(4326));
        @test name(customgrdarray) == :test
        @test label(customgrdarray) == "test"
        @test mappedcrs(dims(customgrdarray, Y)) == EPSG(4326)
        @test mappedcrs(dims(customgrdarray, X)) == EPSG(4326)
        @test mappedcrs(customgrdarray) == EPSG(4326)
        proj = ProjString("+proj=merc +datum=WGS84")
        @test crs(dims(customgrdarray, Y)) == proj
        @test crs(dims(customgrdarray, X)) == proj
        @test crs(customgrdarray) == proj
    end

    @testset "getindex" begin
        @test grdarray[Band(1)] isa GeoArray{Float32,2}
        @test grdarray[Y(1), Band(1)] isa GeoArray{Float32,1}
        @test grdarray[X(1), Band(1)] isa GeoArray{Float32,1}
        @test grdarray[X(50), Y(30), Band(1)] == 115.0f0
        @test grdarray[1, 1, 1] == 255.0f0
        @test grdarray[Y(At(20.0; atol=1e10)), X(At(20; atol=1e10)), Band(3)] == 255.0f0
        @test grdarray[Y(Contains(60)), X(Contains(20)), Band(1)] == 255.0f0
    end

    @testset "methods" begin
        @test mean(grdarray; dims=Y) == mean(parent(grdarray); dims=2)
        @testset "trim, crop, extend" begin
            a = read(grdarray)
            a[X(1:20)] .= missingval(a)
            trimmed = trim(a)
            @test size(trimmed) == (81, 77, 3)
            cropped = crop(a; to=trimmed)
            @test size(cropped) == (81, 77, 3)
            @test all(collect(cropped .== trimmed))
            extended = extend(cropped; to=a);
            @test all(collect(extended .== a))
        end

        @testset "mask and mask! to disk" begin
            msk = replace_missing(grdarray, missing)
            msk[X(1:73), Y([1, 5, 77])] .= missingval(msk)
            @test !any(grdarray[X(1:73)] .=== missingval(msk))
            masked = mask(grdarray; to=msk)
            @test all(masked[X(1:73), Y([1, 5, 77])] .=== missingval(masked))
            tn = tempname()
            tempgrd = tn * ".grd"
            tempgri = tn * ".gri"
            cp(stem * ".grd", tempgrd)
            cp(stem * ".gri", tempgri)
            @test !all(GeoArray(tempgrd)[X(1:73), Y([1, 5, 77])] .=== missingval(grdarray))
            open(GeoArray(tempgrd); write=true) do A
                mask!(A; to=msk, missingval=missingval(A))
            end
            @test all(GeoArray(tempgri)[X(1:73), Y([1, 5, 77])] .=== missingval(grdarray))
            rm(tempgrd)
            rm(tempgri)
        end

        @testset "classify! to disk" begin
            tn = tempname()
            tempgrd = tn * ".grd"
            tempgri = tn * ".gri"
            cp(stem * ".grd", tempgrd)
            cp(stem * ".gri", tempgri)
            extrema(GeoArray(tempgrd))
            open(GeoArray(tempgrd); write=true) do A
                classify!(A, [0.0f0 100.0f0 100.0f0; 100 300 255.0f0])
            end
            A = GeoArray(tempgrd)
            @test count(==(100.0f0), A) + count(==(255.0f0), A) == length(A)
        end

        @testset "mosaic" begin
            @time grdarray = GeoArray(path)
            A1 = grdarray[X(1:40), Y(1:30)]
            A2 = grdarray[X(27:80), Y(25:60)]
            tn = tempname()
            tempgrd = tn * ".grd"
            tempgri = tn * ".gri"
            cp(stem * ".grd", tempgrd)
            cp(stem * ".gri", tempgri)
            Afile = mosaic(first, A1, A2; missingval=0.0f0, atol=1e-1, filename=tempgrd)
            Amem = mosaic(first, A1, A2; missingval=0.0f0, atol=1e-1)
            Atest = grdarray[X(1:80), Y(1:60)]
            Atest[X(1:26), Y(31:60)] .= 0.0f0
            Atest[X(41:80), Y(1:24)] .= 0.0f0
            @test size(Atest) == size(Afile) == size(Amem)
            @test all(Atest .=== Amem .== Afile)
        end

        @testset "rasterize" begin
            A = read(grdarray)
            R = rasterize(A; to=A)
            # Currently the relation makes this upside-down
            # This will be fixed in another branch.
            @test all(A .=== R .== grdarray)
            B = rebuild(read(grdarray) .= 0x00; missingval=0x00)
            rasterize!(B, read(grdarray))
            @test all(B .=== grdarray |> collect)
        end

        @testset "chunk_series" begin
            @test GeoData.chunk_series(grdarray) isa GeoSeries
            @test size(GeoData.chunk_series(grdarray)) == (1, 1, 1)
        end
    end

    @testset "selectors" begin
        geoA = grdarray[Y(Contains(3)), X(:), Band(1)]
        @test geoA isa GeoArray{Float32,1}
        @test grdarray[X(Contains(20)), Y(Contains(10)), Band(1)] isa Float32
    end

    @testset "conversion to GeoArray" begin
        geoA = grdarray[X(1:50), Y(1:1), Band(1)]
        @test size(geoA) == (50, 1)
        @test eltype(geoA) <: Float32
        @time geoA isa GeoArray{Float32,1}
        @test dims(geoA) isa Tuple{<:X,Y}
        @test refdims(geoA) isa Tuple{<:Band}
        @test metadata(geoA) == metadata(grdarray)
        @test missingval(geoA) == -3.4f38
        @test name(geoA) == Symbol("red:green:blue")
    end

    @testset "write" begin
        @testset "2d" begin
            filename2 = tempname() * ".gri"
            write(filename2, grdarray[Band(1)])
            saved = read(GeoArray(filename2))
            # 1 band is added again on save
            @test size(saved) == size(grdarray[Band(1:1)])
            @test parent(saved) == parent(grdarray[Band(1:1)])
        end

        @testset "3d with subset" begin
            geoA = grdarray[1:100, 1:50, 1:2]
            filename = tempname() * ".grd"
            write(filename, GRDfile, geoA)
            saved = read(GeoArray(filename))
            @test size(saved) == size(geoA)
            @test refdims(saved) == ()
            @test bounds(saved) == bounds(geoA)
            @test size(saved) == size(geoA)
            @test missingval(saved) === missingval(geoA)
            @test metadata(saved) != metadata(geoA)
            @test metadata(saved)["creator"] == "GeoData.jl"
            @test all(metadata.(dims(saved)) .== metadata.(dims(geoA)))
            @test name(saved) == name(geoA)
            @test all(lookup.(dims(saved)) .== lookup.(dims(geoA)))
            @test dims(saved) isa typeof(dims(geoA))
            @test all(val.(dims(saved)) .== val.(dims(geoA)))
            @test all(lookup.(dims(saved)) .== lookup.(dims(geoA)))
            @test all(metadata.(dims(saved)) .== metadata.(dims(geoA)))
            @test dims(saved) == dims(geoA)
            @test all(parent(saved) .=== parent(geoA))
            @test saved isa typeof(geoA)
            @test parent(saved) == parent(geoA)
        end

        @testset "to netcdf" begin
            filename2 = tempname() * ".nc"
            span(grdarray[Band(1)])
            write(filename2, grdarray[Band(1)])
            saved = read(GeoArray(filename2; crs=crs(grdarray)))
            @test size(saved) == size(grdarray[Band(1)])
            @test replace_missing(saved, missingval(grdarray)) ≈ grdarray[Band(1)]
            @test index(saved, X) ≈ index(grdarray, X) .+ 0.5
            @test index(saved, Y) ≈ index(grdarray, Y) .+ 0.5
            @test bounds(saved, Y) == bounds(grdarray, Y)
            @test bounds(saved, X) == bounds(grdarray, X)
        end

        @testset "to gdal" begin
            # No Band
            gdalfilename = tempname() * ".tif"
            write(gdalfilename, GDALfile, grdarray[Band(1)])
            gdalarray = GeoArray(gdalfilename)
            # @test convert(ProjString, crs(gdalarray)) == convert(ProjString, EPSG(4326))
            @test val(dims(gdalarray, X)) ≈ val(dims(grdarray, X))
            @test val(dims(gdalarray, Y)) ≈ val(dims(grdarray, Y))
            @test GeoArray(gdalarray) ≈ permutedims(grdarray[Band(1)], [X(), Y()])
            # 3 Bands
            gdalfilename2 = tempname() * ".tif"
            write(gdalfilename2, grdarray)
            gdalarray2 = GeoArray(gdalfilename2)
            @test all(GeoArray(gdalarray2) .== GeoArray(grdarray))
            @test val(dims(gdalarray2, Band)) == 1:3
        end

        @testset "write missing" begin
            A = replace_missing(grdarray, missing)
            filename = tempname() * ".grd"
            write(filename, A)
            @test missingval(GeoArray(filename)) === typemin(Float32)
            rm(filename)
        end

    end

    @testset "show" begin
        sh = sprint(show, MIME("text/plain"), grdarray)
        # Test but don't lock this down too much
        @test occursin("GeoArray", sh)
        @test occursin("Y", sh)
        @test occursin("X", sh)
        @test occursin("Band", sh)
    end

    @testset "plot" begin
        grdarray |> plot
        grdarray[Band(1)] |> plot
    end

end

@testset "Grd stack" begin
    grdstack = GeoStack((a=path, b=path))

    @test length(grdstack) == 2
    @test dims(grdstack) isa Tuple{<:X,<:Y,<:Band}

    @testset "read" begin
        st = read(grdstack)
        @test st isa GeoStack
        @test st.data isa NamedTuple
        @test first(st.data) isa Array
    end

    @testset "indexing" begin
        @test grdstack[:a][Y(20), X(20), Band(3)] == 70.0f0
        @test grdstack[:a][Y([2,3]), X(40), Band(2)] == [240.0f0, 246.0f0]
    end

    @testset "child array properties" begin
        @test size(grdstack[:a]) == size(GeoArray(grdstack[:a])) == (101, 77, 3)
        @test grdstack[:a] isa GeoArray{Float32,3}
    end

    # Stack Constructors
    @testset "conversion to GeoStack" begin
        geostack = GeoStack(grdstack)
        @test Symbol.(Tuple(keys(grdstack))) == keys(geostack)
        smallstack = GeoStack(grdstack; keys=(:a,))
        @test keys(smallstack) == (:a,)
    end

    if VERSION > v"1.1-"
        @testset "copy" begin
            geoA = zero(GeoArray(grdstack[:a]))
            copy!(geoA, grdstack, :a)
            # First wrap with GeoArray() here or == loads from disk for each cell.
            # we need a general way of avoiding this in all disk-based sources
            @test geoA == GeoArray(grdstack[:a])
        end
    end

    @testset "write" begin
        geoA = GeoArray(grdstack[:b])
        filename = tempname() * ".grd"
        write(filename, grdstack)
        base, ext = splitext(filename)
        filename_b = string(base, "_b", ext)
        saved = read(GeoArray(filename_b))
        @test typeof(read(geoA)) == typeof(saved)
        @test parent(saved) == parent(geoA)
    end

    @testset "show" begin
        sh = sprint(show, MIME("text/plain"), grdstack)
        # Test but don't lock this down too much
        @test occursin("GeoStack", sh)
        @test occursin("Y", sh)
        @test occursin("X", sh)
        @test occursin("Band", sh)
        @test occursin(":a", sh)
        @test occursin(":b", sh)
    end

end

@testset "Grd Band stack" begin
    grdstack = GeoStack(path)

    @test length(grdstack) == 3
    @test dims(grdstack) isa Tuple{<:X,<:Y}

    @testset "read" begin
        st = read(grdstack)
        @test st isa GeoStack
        @test st.data isa NamedTuple
        @test first(st.data) isa Array
    end

    @testset "indexing" begin
        @test grdstack[:Band_3][Y(20), X(20)] == 70.0f0
        @test grdstack[:Band_2][Y([2,3]), X(40)] == [240.0f0, 246.0f0]
    end

    @testset "child array properties" begin
        @test size(grdstack[:Band_3]) == size(GeoArray(grdstack[:Band_3])) == (101, 77)
        @test grdstack[:Band_1] isa GeoArray{Float32,2}
    end

    # Stack Constructors
    @testset "conversion to GeoStack" begin
        geostack = GeoStack(grdstack)
        @test Symbol.(Tuple(keys(grdstack))) == keys(geostack)
        smallstack = GeoStack(grdstack; keys=(:Band_2,))
        @test keys(smallstack) == (:Band_2,)
    end

    if VERSION > v"1.1-"
        @testset "copy" begin
            geoA = zero(GeoArray(grdstack[:Band_3]))
            copy!(geoA, grdstack, :Band_3)
            # First wrap with GeoArray() here or == loads from disk for each cell.
            # we need a general way of avoiding this in all disk-based sources
            @test geoA == GeoArray(grdstack[:Band_3])
        end
    end

    @testset "save" begin
        geoA = GeoArray(grdstack[:Band_3])
        filename = tempname() * ".grd"
        write(filename, grdstack)
        base, ext = splitext(filename)
        filename_3 = string(base, "_Band_3", ext)
        saved = read(GeoArray(filename_3))
        @test typeof(rebuild(saved[Band(1)], refdims=())) == typeof(read(geoA))
        @test parent(saved[Band(1)]) == parent(geoA)
    end

    @testset "show" begin
        sh = sprint(show, MIME("text/plain"), grdstack)
        # Test but don't lock this down too much
        @test occursin("GeoStack", sh)
        @test occursin("Y", sh)
        @test occursin("X", sh)
        @test occursin(":Band_1", sh)
        @test occursin(":Band_2", sh)
        @test occursin(":Band_3", sh)
    end

end

@testset "Grd series" begin
    grdseries = GeoSeries([path, path], (Ti,); mappedcrs=EPSG(4326))
    @test grdseries[Ti(1)] == GeoArray(path; mappedcrs=EPSG(4326))
    stacks = [GeoStack((a=path, b=path); mappedcrs=EPSG(4326))]

    grdseries2 = GeoSeries(stacks, (Ti,))
    @test all(grdseries2[Ti(1)][:a] .== GeoArray(path; mappedcrs=EPSG(4326), name=:test))
    modified_ser = modify(x -> Array(1.0f0x), grdseries2)
    @test typeof(modified_ser) <: GeoSeries{<:GeoStack{<:NamedTuple{(:a,:b),<:Tuple{<:Array{Float32,3},Vararg}}},1}

    @testset "read" begin
        geoseries = read(grdseries2)
        @test geoseries isa GeoSeries{<:GeoStack}
        @test geoseries.data isa Vector{<:GeoStack}
        @test geoseries.data isa Vector{<:GeoStack}
        @test first(geoseries.data[1].data) isa Array
    end
end

nothing

ext: jl


text:
using IRTools
using IRTools: IR, CFG, Variable, isexpr, stmt, argument!, return!, xcall, block!,
  branch!, blocks, insertafter!, arguments, argtypes, isreturn, stackify, isconditional

struct WTuple
  parts::Vector{WType}
end

WTuple(Ts::WType...) = WTuple([Ts...])

function locals!(ir::IR)
  locals = argtypes(ir)
  ret = []
  env = Dict{Any,Any}(x => Local(i-1) for (i, x) in enumerate(arguments(ir)))
  rename(x::Variable) = env[x]
  rename(x::Real) = Const(x)
  ltype(x) = rename(x) isa Const ? rename(x).typ : locals[rename(x).id+1]
  local!(v, T) = haskey(env, v) ? env[v] :
    (push!(locals, T); env[v] = Local(length(locals)-1))
  for b in blocks(ir)
    for (v, st) in b
      st.expr isa Variable && (delete!(ir, v); env[v] = rename(st.expr); continue)
      isexpr(st.expr) || (delete!(ir, v); env[v] = Const(st.expr); continue)
      for arg in st.expr.args[2:end]
        insert!(ir, v, rename(arg))
      end
      ir[v] = st.expr.args[1]
      insertafter!(ir, v, SetLocal(false, local!(v, st.type).id))
    end
    for br in IRTools.branches(b)
      if isreturn(br)
        ret = ltype.(arguments(br))
        push!(b, rename(arguments(br)[1]))
        push!(b, Return())
      else
        for (x, y) in zip(arguments(br), arguments(IRTools.block(ir, br.block)))
          push!(b, rename(x))
          push!(b, SetLocal(false, local!(y, ltype(x)).id))
        end
        isconditional(br) && push!(b, rename(br.condition))
        push!(b, Branch(isconditional(br), br.block))
      end
    end
    empty!(IRTools.branches(b))
  end
  return ir, locals, ret
end

isbackedge((from, to)) = to <= from

function reloop(ir, cfg)
  scopes = []
  targets = []
  forw, back = stackify(cfg)
  push!(scopes, Block([]))
  block!() = (bl = Block([]); push!(scopes[1].body, bl); pushfirst!(scopes, bl))
  loop!() = (bl = Loop([]); push!(scopes[1].body, bl); pushfirst!(scopes, bl))
  for b in blocks(ir)
    any(br -> br[2] == b.id, forw) && (popfirst!(scopes); popfirst!(targets))
    brs = vcat(filter(br -> br[1] == b.id, forw), filter(br -> br[2] == b.id, back))
    sort!(brs, by = br -> isbackedge(br) ? (br[1], 1) : (br[2], -1), rev = true)
    for br in brs
      isbackedge(br) ? loop!() : block!()
      pushfirst!(targets, br[2])
    end
    for (v, st) in b
      if st.expr isa Branch
        st.expr.cond && push!(scopes[1].body, i32.eqz)
        target = findfirst(b -> b == st.expr.level, targets)-1
        push!(scopes[1].body, Branch(st.expr.cond, target))
      else
        push!(scopes[1].body, st.expr)
      end
    end
    any(br -> br[1] == b.id, back) && (popfirst!(scopes); popfirst!(targets))
  end
  return scopes[end]
end

function irfunc(name, ir)
  cfg = CFG(ir)
  ir, locals, ret = locals!(ir)
  params = locals[1:length(arguments(ir))]
  locals = locals[length(arguments(ir))+1:end]
  Func(name, params, ret, locals, reloop(ir, cfg))
end


text:
function draw_popup_window(app::Model.AppData, sock::Comm.SocClient)
    @c CImGui.Begin("Another Window", &app.show_another_window)  # pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
    CImGui.Text("Hello from another window!")
    CImGui.Button("Close Me") && (app.show_another_window = false;)
    CImGui.End()
end


text:
export scan_chunk

function scan_chunk!(s::IO, max_blocks_per_chunk::Int, mem_block::Int, mem_trace::Int,
                    keys::Array{String,1}, file::String, scan::Array{BlockScan,1}, count::Int)

    # Load chunk into memory and get nblocks in this chunk
    chunk_start = position(s)
    buf = IOBuffer(read(s, max_blocks_per_chunk*mem_block))
    buf_size = position(seekend(buf))
    seekstart(buf)
    nblocks_chunk = Int(ceil(buf_size/mem_block))
    th_byte2sample = SegyIO.th_byte2sample()

    # Scan all blocks in this chunk
    for b in 1:nblocks_chunk
        scan[count] = scan_block(buf, mem_block, mem_trace, keys, chunk_start, file, th_byte2sample)
        count += 1
    end # b

    close(buf)
    return count
end


text:
module TestQueued

using Test
import ThreadPools: QueuePool
using ThreadPools

include("util.jl")

@testset "QueuePool" begin

    @testset "tforeach" begin
        @testset "foreground" begin
            N = 2 * Threads.nthreads()
            objs = [TestObj(x) for x in 1:N]
            primary = Threads.nthreads() == 1
            fn! = (x) -> begin
                Threads.threadid() == 1 && (primary = true)
                x.data += 1
            end
            pool = QueuePool()
            tforeach(fn!, pool, objs)
            @test primary
            @test [x.data for x in objs] == collect(2:N+1)
            @inferred tforeach(fn!, pool, objs)
            close(pool)
        end

        @testset "background" begin
            N = 2 * Threads.nthreads()
            objs = [TestObj(x) for x in 1:N]
            fn! = (x) -> begin
                Threads.nthreads() == 1 || Threads.threadid() == 1 && error("Task on primary")
                x.data += 1
            end
            pool = QueuePool(2)
            tforeach(fn!, pool, objs)
            @test [x.data for x in objs] == collect(2:N+1)
            @inferred tforeach(fn!, pool, objs)
            close(pool)
        end
    end

    @testset "tmap" begin
        @testset "foreground" begin
            N = 2 * Threads.nthreads()
            objs = [TestObj(x) for x in 1:N]
            primary = Threads.nthreads() == 1
            fn! = (x) -> begin
                Threads.threadid() == 1 && (primary = true)
                x.data
            end
            pool = QueuePool()
            @test tmap(fn!, pool, objs) == collect(1:N)
            @test primary
            @inferred tmap(fn!, pool, objs)
            close(pool)
        end

        @testset "background" begin
            N = 2 * Threads.nthreads()
            objs = [TestObj(x) for x in 1:N]
            fn! = (x) -> begin
                Threads.nthreads() == 1 || Threads.threadid() == 1 && error("Task on primary")
                x.data
            end
            pool = QueuePool(2)
            @test tmap(fn!, pool, objs) == collect(1:N)
            @inferred tmap(fn!, pool, objs)
            close(pool)
        end
    end

    @testset "twith" begin
        @testset "foreground" begin
            N = 2 * Threads.nthreads()
            objs = [TestObj(x) for x in 1:N]
            primary = Threads.nthreads() == 1
            twith(QueuePool()) do pool
                tforeach(pool, objs) do x
                    Threads.threadid() == 1 && (primary = true)
                    x.data += 1
                end
            end
            @test [x.data for x in objs] == collect(2:N+1)
            @test primary
        end

        @testset "background" begin
            N = 2 * Threads.nthreads()
            objs = [TestObj(x) for x in 1:N]
            twith(QueuePool(2)) do pool
                tforeach(pool, objs) do x
                    Threads.nthreads() == 1 || Threads.threadid() == 1 && error("Task on primary")
                    x.data += 1
                end
            end
            @test [x.data for x in objs] == collect(2:N+1)
        end
    end

    @testset "@tthreads" begin
        @testset "foreground" begin
            N = 2 * Threads.nthreads()
            objs = [TestObj(x) for x in 1:N]
            primary = Threads.nthreads() == 1
            pool = QueuePool()
            @tthreads pool for obj in objs
                Threads.threadid() == 1 && (primary = true)
                obj.data += 1
            end
            close(pool)
            @test [x.data for x in objs] == collect(2:N+1)
            @test primary
        end

        @testset "background" begin
            N = 2 * Threads.nthreads()
            objs = [TestObj(x) for x in 1:N]
            pool = QueuePool(2)
            @tthreads pool for obj in objs
                Threads.nthreads() == 1 || Threads.threadid() == 1 && error("Task on primary")
                obj.data += 1
            end
            close(pool)
            @test [x.data for x in objs] == collect(2:N+1)
        end
    end

end

end # module


text:
@testset "NumField/NfAbsNS/ConjugatesNS.jl" begin
  Qx, x = QQ["x"]
  K, a = NumberField([x^2 - 2, x^2 - 3, x^2 - 5], "a")
  r, s = @inferred signature(K)
  @test (r, s) == (8, 0)
  Kabs, KabstoK = simple_extension(K)
  b = rand(K, -1:1)

  c = conjugates(b, 64)
  cc = conjugates(KabstoK\b, 64)

  for _c in c
    @test count(_cc -> overlaps(_cc, _c), cc) == count(_cc -> overlaps(_cc, _c), c)
  end

  Kt, t = K["t"]
  L, b = NumberField(t^2 - a[1] * a[2])
  @test signature(L) == (8, 4)
end

@testset "NumField/NfAbsNS/Conjugates.jl" begin
  Qx, x = QQ["x"]
  K, a = wildanger_field(3, 13)
  r, s = @inferred signature(K)
  @test (r, s) == (1, 1)
  b = rand(K, -1:1)

  c = conjugates(b, ComplexField(64))
  cc = conjugates(b, 64)

  for _c in c
    @test count(_cc -> overlaps(_cc, _c), cc) == count(_cc -> overlaps(_cc, _c), c)
  end
end


text:
const psxy  = plot
const psxy! = plot!
const psxyz  = plot3d
const psxyz! = plot3d!

# ---------------------------------------------------------------------------------------------------
function common_plot_xyz(cmd0, arg1, caller::String, first::Bool, is3D::Bool, kwargs...)
	arg3 = nothing
	N_args = (arg1 === nothing) ? 0 : 1
	is_ternary = (caller == "ternary") ? true : false
	if     (is3D)       gmt_proggy = (IamModern[1]) ? "plot3d "  : "psxyz "
	elseif (is_ternary) gmt_proggy = (IamModern[1]) ? "ternary " : "psternary "
	else		        gmt_proggy = (IamModern[1]) ? "plot "    : "psxy "
	end

	(occursin(" -", cmd0)) && return monolitic(gmt_proggy, cmd0, arg1)

	d = KW(kwargs)
	help_show_options(d)				# Check if user wants ONLY the HELP mode
    K, O = set_KO(first)				# Set the K O dance

	cmd = "";	sub_module = ""			# Will change to "scatter", etc... if called by sub-modules
	g_bar_fill = nothing				# May hold a sequence of colors for gtroup Bar plots
	if (caller != "")
		if (occursin(" -", caller))		# some sub-modues use this piggy-backed call
			if ((ind = findfirst("|", caller)) !== nothing)	# A mixed case with "caler|partiall_command"
				sub_module = caller[1:ind[1]-1]
				cmd = caller[ind[1]+1:end]
				caller = sub_module		# Because of parse_BJR()
				if (caller == "events")  gmt_proggy = "events "  end
			else
				cmd = caller
				caller = "others"		# It was piggy-backed
			end
		else
			sub_module = caller
			if (sub_module == "bar")	# Needs to be processed here to destinguish from the more general 'fill'
				gval = find_in_dict(d, [:fill :fillcolor], false)[1]	# Used for group colors
				if     (isa(gval, Array{String}) && length(gval) > 1)  g_bar_fill = gval	# Given an array of fills
				elseif ((isa(gval, Array{Int}) || (isa(gval, Tuple)) && eltype(gval) == Int) && length(gval) > 1)
					g_bar_fill = Vector{String}(undef, length(gval))			# Patterns
					[g_bar_fill[k] = string('p',gval[k]) for k = 1:length(gval)]
				end
			end
		end
	end

	def_J = (is_ternary) ? " -JX12c/0" : ""
	cmd, opt_B, opt_J, opt_R = parse_BJR(d, cmd, caller, O, def_J)
	if (is3D)	cmd, opt_JZ  = parse_JZ(d, cmd)  end
	cmd, = parse_common_opts(d, cmd, [:a :e :f :g :l :p :t :params], first)
	cmd  = parse_these_opts(cmd, d, [[:D :shift :offset], [:I :intens], [:N :no_clip :noclip]])
	if (is_ternary)  cmd = add_opt(d, cmd, 'M', [:M :no_plot])  end
	opt_UVXY = parse_UVXY(d, "")	# Need it separate to not risk to double include it.
	cmd, opt_c = parse_c(d, cmd)	# Need opt_c because we may need to remove it from double calls

	# If a file name sent in, read it and compute a tight -R if this was not provided
	got_usr_R = (opt_R != "") ? true : false		# To know is the user set -R or we guessed it from data
	if (opt_R == "" && sub_module == "bar")  opt_R = "/-0.4/0.4/0"  end	# Make sure y_min = 0
	cmd, arg1, opt_R, lixo, opt_i = read_data(d, cmd0, cmd, arg1, opt_R, is3D)
	if (N_args == 0 && arg1 !== nothing)  N_args = 1  end

	if ((isa(arg1, GMTdataset) && arg1.proj4 != "" || isa(arg1, Vector{GMTdataset}) &&
		     arg1[1].proj4 != "") && opt_J == " -JX" * def_fig_size)
		cmd = replace(cmd, opt_J => "-JX12c/0")		# If projected, it's a axis equal for sure
	end
	if (is3D && isempty(opt_JZ) && length(collect(eachmatch(r"/", opt_R))) == 5)
		cmd *= " -JZ6c"		# Default -JZ
	end

	cmd = add_opt(d, cmd, 'A', [:A :steps :straight_lines], (x="x", y="y", meridian="m", parallel="p"))
	opt_F = add_opt(d, "", "", [:F :conn :connection],
	                (continuous=("c", nothing, 1), net=("n", nothing, 1), network=("n", nothing, 1), refpoint=("r", nothing, 1),  ignore_hdr="_a", single_group="_f", segments="_s", segments_reset="_r", anchor=("", arg2str)))
	if (length(opt_F) > 1 && !occursin("/", opt_F))  opt_F = opt_F[1]  end	# Allow con=:net or con=(1,2)
	if (opt_F != "")  cmd *= " -F" * opt_F  end

	# Error Bars?
	got_Ebars = false
	val, symb = find_in_dict(d, [:E :error :error_bars], false)
	if (val !== nothing)
		cmd, arg1 = add_opt(add_opt, (d, cmd, 'E', [symb]),
                            (x="|x",y="|y",xy="|xy",X="|X",Y="|Y", asym="_+a", colored="_+c", cline="_+cl", csymbol="_+cf", wiskers="|+n",cap="+w",pen=("+p",add_opt_pen)), false, isa(arg1, GMTdataset) ? arg1.data : (isa(arg1, Array{GMTdataset}) ? arg1[1].data : arg1) )
		got_Ebars = true
		del_from_dict(d, [symb])
	end

	# Look for color request. Do it after error bars because they may add a column
	len = length(cmd);	n_prev = N_args;
	cmd, arg1, arg2, N_args = add_opt_cpt(d, cmd, [:C :color :cmap], 'C', N_args, arg1)
	#cmd, arg1, arg2, N_args = add_opt_cpt(d, cmd, [:C :color :cmap], 'C', N_args, arg1, nothing, true, true, "", true)

	cmd, args, n, got_Zvars = add_opt(d, cmd, 'Z', [:Z :level], :data, [arg1, arg2, arg3], (outline="_+l", fill="_+f"))
	if (n > 0)
		arg1, arg2, arg3 = args[:]
		N_args = n
	end

	mcc = false
	if (!got_Zvars)									# Otherwise we don't care about color columns
		# See if we got a CPT. If yes there may be some work to do if no color column provided in input data.
		cmd, arg1, arg2, N_args, mcc = make_color_column(d, cmd, opt_i, len, N_args, n_prev, is3D, got_Ebars, arg1, arg2)
	end

	if (g_bar_fill === nothing)						# Otherwise bar fill colors are dealt somewhere else
		cmd = add_opt_fill(cmd, d, [:G :fill], 'G')
	end
	opt_Gsymb = add_opt_fill("", d, [:G :markerfacecolor :MarkerFaceColor :mc], 'G')	# Filling of symbols

	# To track a still existing bug in sessions management at GMT lib level
	got_pattern = false
	if (occursin("-Gp", cmd) || occursin("-GP", cmd) || occursin("-Gp", opt_Gsymb) || occursin("-GP", opt_Gsymb))
		got_pattern = true
	end

	if (is_ternary)			# Means we are in the psternary mode
		cmd = add_opt(d, cmd, 'L', [:L :labels])
	else
		opt_L = add_opt(d, "", 'L', [:L :close :polygon],
		                (left="_+xl", right="_+xr", x0="+x", bot="_+yb", top="_+yt", y0="+y", sym="_+d", asym="_+D", envelope="_+b", pen=("+p",add_opt_pen)))
		if (length(opt_L) > 3 && !occursin("-G", cmd) && !occursin("+p", cmd))  opt_L *= "+p0.5p"  end
		cmd *= opt_L
	end

	opt_Wmarker = ""
	if ((val = find_in_dict(d, [:markeredgecolor :MarkerEdgeColor])[1]) !== nothing)
		opt_Wmarker = "0.5p," * arg2str(val)		# 0.25p is too thin?
	end

	opt_W = add_opt_pen(d, [:W :pen], "W", true)     # TRUE to also seek (lw,lc,ls)
	if ((occursin("+c", opt_W) || occursin("+c", cmd)) && !occursin("-C", cmd))
		@warn("Color lines (or fill) from a color scale was selected but no color scale provided. Expect ...")
	end

	opt_S = add_opt(d, "", 'S', [:S :symbol], (symb="1", size="", unit="1"))
	if (opt_S == "")			# OK, no symbol given via the -S option. So fish in aliases
		marca, arg1, more_cols = get_marker_name(d, [:marker :Marker :shape], is3D, true, arg1)
		if ((val = find_in_dict(d, [:markersize :MarkerSize :ms :size])[1]) !== nothing)
			if (marca == "")  marca = "c"  end		# If a marker name was not selected, defaults to circle
			if (isa(val, AbstractArray))
				(length(val) != size(arg1,1)) &&
					error("The size array must have the same number of elements rows in the data")
				arg1 = hcat(arg1, val[:])
				#arg1 = hcat(arg1, convert(eltype(arg1), val[:]))
			elseif (string(val) != "indata")
				marca *= arg2str(val);
			end
			opt_S = " -S" * marca
		elseif (marca != "")		# User only selected a marker name but no size.
			opt_S = " -S" * marca
			# If data comes from a file, then no automatic symbol size is added
			op = lowercase(marca[1])
			def_size = (op == 'p') ? "3p" : "7p"	# 'p' here stands for symbol points, not units
			if (!more_cols && arg1 !== nothing && !isa(arg1, GMTcpt) && !occursin(op, "bekmrvw"))  opt_S *= def_size  end
		end
	else
		val, symb = find_in_dict(d, [:markersize :MarkerSize :ms :size])
		(val !== nothing) && @warn("option *$(symb)* is ignored when either *S* or *symbol* options are used")
		val, symb = find_in_dict(d, [:marker :Marker :shape])
		(val !== nothing) && @warn("option *$(symb)* is ignored when either *S* or *symbol* options are used")
	end

	opt_ML = ""
	if (opt_S != "")
		if ((val = find_in_dict(d, [:markerline :MarkerLine :ml])[1]) !== nothing)
			if (isa(val, Tuple))  opt_ML = " -W" * parse_pen(val) # This can hold the pen, not extended atts
			elseif (isa(val, NamedTuple))  opt_ML = add_opt_pen(nt2dict(val), [:pen], "W")
			else                  opt_ML = " -W" * arg2str(val)
			end
			if (opt_Wmarker != "")
				@warn("markerline overrides markeredgecolor");		opt_Wmarker = ""
			end
		end
		(opt_W != "" && opt_ML != "") && @warn("You cannot use both markerline and W or pen keys.")
	end

	# See if any of the scatter, bar, lines, etc... was the caller and if yes, set sensible defaults.
	cmd = check_caller(d, cmd, opt_S, opt_W, sub_module, g_bar_fill, O)

	if (opt_W != "" && opt_S == "") 						# We have a line/polygon request
		cmd *= opt_W * opt_UVXY

	elseif (opt_W == "" && opt_S != "")						# We have a symbol request
		if (opt_Wmarker != "" && opt_W == "") opt_Gsymb *= " -W" * opt_Wmarker  end		# reuse var name
		if (opt_ML != "")  cmd *= opt_ML  end				# If we have a symbol outline pen
		cmd *= opt_S * opt_Gsymb * opt_UVXY

	elseif (opt_W != "" && opt_S != "")						# We have both line/polygon and a symbol
		if (occursin(opt_Gsymb, cmd))  opt_Gsymb = ""  end
		if (opt_S[4] == 'v' || opt_S[4] == 'V' || opt_S[4] == '=')
			cmd *= opt_W * opt_S * opt_Gsymb * opt_UVXY
		else
			if (opt_Wmarker != "")  opt_Wmarker = " -W" * opt_Wmarker  end		# Set Symbol edge color
			cmd1 = cmd * opt_W * opt_UVXY
			cmd2 = replace(cmd, opt_B => "") * opt_S * opt_Gsymb * opt_Wmarker	# Don't repeat option -B
			if (opt_c != "")  cmd2 = replace(cmd2, opt_c => "")  end			# Not in scond call (subplots)
			if (opt_ML != "")  cmd1 = cmd1 * opt_ML  end	# If we have a symbol outline pen
			cmd = [cmd1; cmd2]
		end

	else
		cmd *= opt_UVXY
	end

	# Let matrices with more data columns, and for which Color info was NOT set, plot multiple lines at once
	if (!mcc && opt_S == "" && (caller == "lines" || caller == "plot") && isa(arg1, Array{<:Real,2}) && size(arg1,2) > 2+is3D && size(arg1,1) > 1 && (multi_col[1] || haskey(d, :multicol)) )
		multi_col[1] = false						# Reset because this is a use-only-once option
		penC = "";		penS = "";	cycle=:cycle
		# But if we have a color in opt_W (idiotic) let it overrule the automatic color cycle in mat2ds()
		if (opt_W != "")  penT, penC, penS = break_pen(scan_opt(opt_W, "-W"))  end
		if (penC  != "")  cycle = [penC]  end
		arg1 = mat2ds(arg1, color=cycle, ls=penS, multi=true)	# Convert to multi-segment GMTdataset
		D = gmt("gmtinfo -C", arg1)					# But now also need to update the -R string
		if (isa(cmd, Array))						# Replace old -R by the new one
			cmd[1] = replace(cmd[1], opt_R => " -R" * arg2str(round_wesn(D[1].data)))
		else
			cmd = replace(cmd, opt_R => " -R" * arg2str(round_wesn(D[1].data)))
		end
	#elseif (sub_module == "bar" && ((isa(arg1, Array{<:Real,2}) && size(arg1,2) > 2) || haskey(d, :stacked)) )
	elseif (sub_module == "bar")
		cmd, arg1 = bar_group(d, cmd, opt_R, g_bar_fill, got_Ebars, got_usr_R, arg1)
	end

	(!IamModern[1]) && put_in_legend_bag(d, cmd, arg1)

	cmd = gmt_proggy .* cmd				# In any case we need this
	cmd, K = finish_PS_nested(d, cmd, K, O)

	r = finish_PS_module(d, cmd, "", K, O, true, arg1, arg2, arg3)
	(got_pattern || occursin("-Sk", opt_S)) && gmt("destroy")  # Apparently patterns are screweing the session
	return r
end

# ---------------------------------------------------------------------------------------------------
function bar_group(d::Dict, cmd::String, opt_R::String, g_bar_fill, got_Ebars::Bool, got_usr_R::Bool, arg1)
	# Convert input array into a multi-segment Dataset where each segment is an element of a bar group
	# Example, plot two groups of 3 bars each: bar([0 1 2 3; 1 2 3 4], xlabel="BlaBla")
	if !( isa(arg1, Array{<:Real,2}) || (eltype(arg1) <: GMTdataset &&
		 (isa(arg1, Array{GMTdataset}) ? size(arg1[1],2) > 2 : size(arg1,2))) )
		return cmd, arg1		# No group bars, just plain bars
	end

	if (got_Ebars)
		opt_E = scan_opt(cmd, "-E")
		((ind = findfirst("+", opt_E)) !== nothing) && (opt_E = opt_E[1:ind[1]-1])	# Strip eventual modifiers
		(((ind = findfirst("X", opt_E)) !== nothing) || ((ind = findfirst("Y", opt_E)) !== nothing)) && return cmd, arg1
		n_xy_bars = (findfirst("x", opt_E) !== nothing) + (findfirst("y", opt_E) !== nothing)
		n_cols = size(arg1,2)
		((n_cols - n_xy_bars) == 2) && return cmd, arg1			# Only one-bar groups
		(iseven(n_cols)) && error("Wrong number of columns in error bars array (or prog error)")
		n = Int((n_cols - 1) / 2)
		_arg = arg1[:, 1:(n+1)]				# No need to care with GMTdatasets because case was dealt in 'got_Ebars'
		bars_cols = arg1[:,(n + 2):end]		# We'll use this to appent to the multi-segments
	else
		_arg = isa(arg1, GMTdataset) ? deepcopy(arg1.data) : (isa(arg1, Array{GMTdataset}) ? deepcopy(arg1[1].data) : deepcopy(arg1))
		bars_cols = nothing
	end

	do_multi = true;	do_bar_stack = false		# True for grouped; false for stacked groups
	if ((val = find_in_dict(d, [:stack :stacked])[1]) !== nothing)
		# Take this (two groups of 3 bars) [0 1 2 3; 1 2 3 4]  and compute this (the same but stacked)
		# [0 1 0; 0 3 1; 0 6 3; 1 2 0; 1 5 2; 1 9 4]
		nl = size(_arg,2)-1				# N layers in stack
		tmp = zeros(size(_arg,1)*nl, 3)

		for m = 1:size(_arg, 1)			# Loop over number of groups
			tmp[(m-1)*nl+1,1] = _arg[m,1];		tmp[(m-1)*nl+1,2] = _arg[m,2];	# 3rd col is zero
			for n = 2:nl				# Loop over number of layers (n bars in a group)
				tmp[(m-1)*nl+n,1] = _arg[m,1]
				if (sign(tmp[(m-1)*nl+n-1,2]) == sign(_arg[m,n+1]))		# Because when we have neg & pos, case is diff
					tmp[(m-1)*nl+n,2] = tmp[(m-1)*nl+n-1,2] + _arg[m,n+1]
					tmp[(m-1)*nl+n,3] = tmp[(m-1)*nl+n-1,2]
				else
					tmp[(m-1)*nl+n,2] = _arg[m,n+1]
					tmp[(m-1)*nl+n,3] = 0
				end
			end
		end
		_arg = tmp
		do_multi = false;		do_bar_stack = true
	end

	if (g_bar_fill === nothing && findfirst("-G0/115/190", cmd) !== nothing)	# Remove the auto color
		cmd = replace(cmd, " -G0/115/190" => "")
		g_bar_fill = true			# Just anything non array to trigger the cyclic color schema
	end

	# Convert to a multi-segment GMTdataset. There will be as many segments as elements in a group
	# and as many rows in a segment as the number of groups (number of bars if groups had only one bar)
	alpha = find_in_dict(d, [:alpha :fillalpha :transparency])[1]
	_arg = mat2ds(_arg; fill=g_bar_fill, multi=do_multi, fillalpha=alpha)
	if (do_bar_stack)  _arg = ds2ds(_arg[1], fill=g_bar_fill, color_wrap=nl, fillalpha=alpha)  end
	(g_bar_fill !== nothing) && delete!(d, :fill)

	if (bars_cols !== nothing)		# Loop over number of bars in each group and append the error bar
		for k = 1:length(_arg)
			_arg[k].data = reshape(append!(_arg[k].data[:], bars_cols[:,k]), size(_arg[k].data,1), :)
		end
	end

	# Must fish-and-break-and-rebuild -S option
	opt_S = scan_opt(cmd, "-S")
	sub_b = ((ind = findfirst("+", opt_S)) !== nothing) ? opt_S[ind[1]:end] : ""	# The +Base modifier
	(sub_b != "") && (opt_S = opt_S[1:ind[1]-1])# Strip it because we need to (re)find Bar width
	bw = (isletter(opt_S[end])) ? parse(Float64, opt_S[3:end-1]) : parse(Float64, opt_S[3:end])	# Bar width
	n_in_group = length(_arg)					# Number of bars in the group
	gap = ((val = find_in_dict(d, [:gap])[1]) !== nothing) ? val/100 : 0	# Gap between bars in a group
	new_bw = (do_bar_stack) ? bw : bw / n_in_group * (1 - gap)	# 'width' does not change in bar-stack
	new_opt_S = "-S" * opt_S[1] * "$(new_bw)u"
	cmd = (do_bar_stack) ? replace(cmd, "-S"*opt_S*sub_b => new_opt_S*"+b") : replace(cmd, "-S"*opt_S => new_opt_S)

	if (!do_bar_stack)							# 'Horizontal stack'
		g_shifts = linspace((-bw + new_bw)/2, (bw - new_bw)/2, n_in_group)
		for k = 1:n_in_group
			[_arg[k].data[n,1] += g_shifts[k] for n = 1:size(_arg[k].data,1)]
		end
	end

	if (!got_usr_R)								# Need to recompute -R
		info = gmt("gmtinfo -C", _arg)
		(info[1].data[3] > 0) && (info[1].data[3] = 0)		# If not negative then must be 0
		dx = (info[1].data[2] - info[1].data[1]) * 0.005 + new_bw/2;
		dy = (info[1].data[4] - info[1].data[3]) * 0.005;
		info[1].data[1] -= dx;	info[1].data[2] += dx;	info[1].data[4] += dy;
		(info[1].data[3] != 0) && (info[1].data[3] -= dy);
		info[1].data = round_wesn(info[1].data)		# Add a pad if not-tight
		new_opt_R = @sprintf(" -R%.12g/%.12g/%.12g/%.12g", info[1].data[1], info[1].data[2], info[1].data[3], info[1].data[4])
		cmd = replace(cmd, opt_R => new_opt_R)
	end
	return cmd, _arg
end

# ---------------------------------------------------------------------------------------------------
function make_color_column(d::Dict, cmd::String, opt_i::String, len::Int, N_args::Int, n_prev::Int, is3D::Bool, got_Ebars::Bool, arg1, arg2)
	# See if we got a CPT. If yes, there is quite some work to do if no color column provided in input data.
	# N_ARGS will be == n_prev+1 when a -Ccpt was used. Otherwise they are equal.

	(arg1 === nothing || isa(arg1, GMT.GMTcpt)) && return cmd, arg1, arg2, N_args, false  # Play safe

	mz, the_kw = find_in_dict(d, [:zcolor :markerz :mz])
	if (!(N_args > n_prev || len < length(cmd)) && mz === nothing)	# No color request, so return right away
		return cmd, arg1, arg2, N_args, false
	end

	if (isa(arg1, Array{<:Number}))  n_rows, n_col = size(arg1)
	elseif (isa(arg1,GMTdataset))    n_rows, n_col = size(arg1.data)
	else                             n_rows, n_col = size(arg1[1].data)
	end

	warn1 = string("Probably color column in ", the_kw, " has incorrect dims. Ignoring it.")
	warn2 = "Plotting with color table requires adding one more column to the dataset but your -i
	option didn't do it, so you won't get what you expect. Try -i0-1,1 for 2D or -i0-2,2 for 3D plots"

	if (n_col <= 2+is3D)
		if (mz !== nothing)
			if (length(mz) != n_rows)  @warn(warn1); @goto noway  end
			if (isa(arg1, Array))          arg1 = hcat(arg1, mz[:])
			elseif (isa(arg1,GMTdataset))  arg1.data = hcat(arg1.data, mz[:])
			else                           arg1[1].data = hcat(arg1[1].data, mz[:])
			end
		else
			if (opt_i != "")  @warn(warn2);		@goto noway		end
			cmd *= " -i0-$(1+is3D),$(1+is3D)"
			if ((val = find_in_dict(d, [:markersize :ms :size])[1]) !== nothing)
				cmd *= "-$(2+is3D)"		# Because we know that an extra col will be added later
			end
		end
	else
		if (mz !== nothing)				# Here we must insert the color col right after the coords
			if (length(mz) != n_rows)  @warn(warn1); @goto noway  end
			if     (isa(arg1, Array))      arg1 = hcat(arg1[:,1:2+is3D], mz[:], arg1[:,3+is3D:end])
			elseif (isa(arg1,GMTdataset))  arg1.data = hcat(arg1.data[:,1:2+is3D], mz[:], arg1.data[:,3+is3D:end])
			else                           arg1[1].data = hcat(arg1[1].data[:,1:2+is3D], mz[:], arg1[1].data[:,3+is3D:end])
			end
		elseif (got_Ebars)		# The Error bars case is very multi. Don't try to guess then.
			if (opt_i != "")  @warn(warn2);	@goto noway  end
			cmd *= " -i0-$(1+is3D),$(1+is3D),$(2+is3D)-$(n_col-1)"
		end
	end

	if (N_args == n_prev)		# No cpt transmitted, so need to compute one
		if (GMTver >= 77)		# 7 because this solution is currently still bugged
			#=
			if (mz !== nothing)
				arg2 = gmt("makecpt -E " * cmd[len+2:end], mz[:])
			else
				if (isa(arg1, Array))  arg2 = gmt("makecpt -E " * cmd[len+2:end], arg1)
				else                   arg2 = gmt("makecpt -E " * cmd[len+2:end], arg1.data)
				end
			end
			=#
		else
			if (mz !== nothing)               mi, ma = extrema(mz)
			else
				if     (isa(arg1, Array))     mi, ma = extrema(view(arg1, :, 2+is3D))
				elseif (isa(arg1,GMTdataset)) mi, ma = extrema(view(arg1.data, :, 2+is3D))
				else                          mi, ma = extrema(view(arg1[1].data, :, 2+is3D))
				end
			end
			just_C = cmd[len+2:end];	reset_i = ""
			if ((ind = findfirst(" -i", just_C)) !== nothing)
				reset_i = just_C[ind[1]:end]
				just_C  = just_C[1:ind[1]-1]
			end
			arg2 = gmt(string("makecpt -T", mi-0.001*abs(mi), '/', ma+0.001*abs(ma), " ", just_C))
			if (occursin(" -C", cmd))  cmd = cmd[1:len+3]  end		# Strip the cpt name
			if (reset_i != "")  cmd *= reset_i  end		# Reset -i, in case it existed
		end
		if (!occursin(" -C", cmd))  cmd *= " -C"  end	# Need to inform that there is a cpt to use
		N_args = 2
	end

	@label noway

	return cmd, arg1, arg2, N_args, true
end

# ---------------------------------------------------------------------------------------------------
function get_marker_name(d::Dict, symbs::Array{Symbol}, is3D::Bool, del::Bool=true, arg1=nothing)
	marca = Array{String,1}(undef,1)
	marca = [""];		N = 0
	for symb in symbs
		if (haskey(d, symb))
			t = d[symb]
			if (isa(t, Tuple))				# e.g. marker=(:r, [2 3])
				msg = "";	cst = false
				o = string(t[1])
				if     (startswith(o, "E"))  opt = "E";  N = 3; cst = true
				elseif (startswith(o, "e"))  opt = "e";  N = 3
				elseif (o == "J" || startswith(o, "Rot"))  opt = "J";  N = 3; cst = true
				elseif (o == "j" || startswith(o, "rot"))  opt = "j";  N = 3
				elseif (o == "M" || startswith(o, "Mat"))  opt = "M";  N = 3
				elseif (o == "m" || startswith(o, "mat"))  opt = "m";  N = 3
				elseif (o == "R" || startswith(o, "Rec"))  opt = "R";  N = 3
				elseif (o == "r" || startswith(o, "rec"))  opt = "r";  N = 2
				elseif (o == "V" || startswith(o, "Vec"))  opt = "V";  N = 2
				elseif (o == "v" || startswith(o, "vec"))  opt = "v";  N = 2
				elseif (o == "w" || o == "pie" || o == "web" || o == "wedge")  opt = "w";  N = 2
				elseif (o == "W" || o == "Pie" || o == "Web" || o == "Wedge")  opt = "W";  N = 2
				end
				if (N > 0)  marca[1], arg1, msg = helper_markers(opt, t[2], arg1, N, cst)  end
				(msg != "") && error(msg)
				if (length(t) == 3 && isa(t[3], NamedTuple))
					if (marca[1] == "w" || marca[1] == "W")	# Ex (spiderweb): marker=(:pie, [...], (inner=1,))
						marca[1] *= add_opt(t[3], (inner="/", arc="+a", radial="+r", size=("", arg2str, 1), pen=("+p", add_opt_pen)) )
					elseif (marca[1] == "m" || marca[1] == "M")
						marca[1] *= vector_attrib(t[3])
					end
				end
			elseif (isa(t, NamedTuple))		# e.g. marker=(pie=true, inner=1, ...)
				key = keys(t)[1];	opt = ""
				if     (key == :w || key == :pie || key == :web || key == :wedge)  opt = "w"
				elseif (key == :W || key == :Pie || key == :Web || key == :Wedge)  opt = "W"
				elseif (key == :b || key == :bar)     opt = "b"
				elseif (key == :B || key == :HBar)    opt = "B"
				elseif (key == :l || key == :letter)  opt = "l"
				elseif (key == :K || key == :Custom)  opt = "K"
				elseif (key == :k || key == :custom)  opt = "k"
				elseif (key == :M || key == :Matang)  opt = "M"
				elseif (key == :m || key == :matang)  opt = "m"
				end
				if (opt == "w" || opt == "W")
					marca[1] = opt * add_opt(t, (size=("", arg2str, 1), inner="/", arc="+a", radial="+r", pen=("+p", add_opt_pen)))
				elseif (opt == "b" || opt == "B")
					marca[1] = opt * add_opt(t, (size=("", arg2str, 1), base="+b", Base="+B"))
				elseif (opt == "l")
					marca[1] = opt * add_opt(t, (size=("", arg2str, 1), letter="+t", justify="+j", font=("+f", font)))
				elseif (opt == "m" || opt == "M")
					marca[1] = opt * add_opt(t, (size=("", arg2str, 1), arrow=("", vector_attrib)))
				elseif (opt == "k" || opt == "K")
					marca[1] = opt * add_opt(t, (custom="", size="/"))
				end
			else
				t = string(t)
				if     (t == "-" || t == "x-dash")    marca[1] = "-"
				elseif (t == "+" || t == "plus")      marca[1] = "+"
				elseif (t == "a" || t == "*" || t == "star")  marca[1] = "a"
				elseif (t == "k" || t == "custom")    marca[1] = "k"
				elseif (t == "x" || t == "cross")     marca[1] = "x"
				elseif (t[1] == 'c' || t[1] == 'C')   marca[1] = "c"
				elseif (t == "d" || t == "diamond")   marca[1] = "d"
				elseif (t == "g" || t == "octagon")   marca[1] = "g"
				elseif (t == "h" || t == "hexagon")   marca[1] = "h"
				elseif (t == "i" || t == "v" || t == "inverted_tri")  marca[1] = "i"
				elseif (t == "l" || t == "letter")    marca[1] = "l"
				elseif (t == "n" || t == "pentagon")  marca[1] = "n"
				elseif (t == "p" || t == "." || t == "point")  marca[1] = "p"
				elseif (t == "s" || t == "square")    marca[1] = "s"
				elseif (t == "t" || t == "^" || t == "triangle")  marca[1] = "t"
				elseif (t == "T" || t == "Triangle")  marca[1] = "T"
				elseif (is3D && (t == "u" || t == "cube"))  marca[1] = "u"
				elseif (t == "y" || t == "y-dash")    marca[1] = "y"
				end
				# Still need to check the simpler forms of these
				if (marca[1] == "")  marca[1] = helper2_markers(t, ["e", "ellipse"])   end
				if (marca[1] == "")  marca[1] = helper2_markers(t, ["E", "Ellipse"])   end
				if (marca[1] == "")  marca[1] = helper2_markers(t, ["j", "rotrect"])   end
				if (marca[1] == "")  marca[1] = helper2_markers(t, ["J", "RotRect"])   end
				if (marca[1] == "")  marca[1] = helper2_markers(t, ["m", "matangle"])  end
				if (marca[1] == "")  marca[1] = helper2_markers(t, ["M", "Matangle"])  end
				if (marca[1] == "")  marca[1] = helper2_markers(t, ["r", "rectangle"])   end
				if (marca[1] == "")  marca[1] = helper2_markers(t, ["R", "RRectangle"])  end
				if (marca[1] == "")  marca[1] = helper2_markers(t, ["v", "vector"])  end
				if (marca[1] == "")  marca[1] = helper2_markers(t, ["V", "Vector"])  end
				if (marca[1] == "")  marca[1] = helper2_markers(t, ["w", "pie", "web"])  end
				if (marca[1] == "")  marca[1] = helper2_markers(t, ["W", "Pie", "Web"])  end
			end
			(del) && delete!(d, symb)
			break
		end
	end
	return marca[1], arg1, N > 0
end

function helper_markers(opt::String, ext, arg1, N::Int, cst::Bool)
	# Helper function to deal with the cases where one sends marker's extra columns via command
	# Example that will land and be processed here:  marker=(:Ellipse, [30 10 15])
	# N is the number of extra columns
	marca = Array{String,1}(undef,1)
	marca = [""];	 msg = ""
	if (size(ext,2) == N && arg1 !== nothing)
		S = Symbol(opt)
		marca[1], arg1 = add_opt(add_opt, (Dict(S => (par=ext,)), opt, "", [S]), (par="|",), true, arg1)
	elseif (cst && length(ext) == 1)
		marca[1] = opt * "-" * string(ext)
	else
		msg = string("Wrong number of extra columns for marker (", opt, "). Got ", size(ext,2), " but expected ", N)
	end
	return marca[1], arg1, msg
end

function helper2_markers(opt::String, alias::Vector{String})::String
	marca = [""]
	if (opt == alias[1])			# User used only the one letter syntax
		marca[1] = alias[1]
	else
		for k = 2:length(alias)		# Loop because of cases like ["w" "pie" "web"]
			o2 = alias[k][1:min(2,length(alias[k]))]	# check the first 2 chars and Ro, Rotrect or RotRec are all good
			if (startswith(opt, o2))  marca[1] = alias[1]; break  end		# Good when, for example, marker=:Pie
		end
	end

	# If we still have found nothing, assume that OPT is a full GMT opt string (e.g. W/5+a30+r45+p2,red)
	if (marca[1] == "" && opt[1] == alias[1][1])  marca[1] = opt  end
	return marca[1]
end

# ---------------------------------------------------------------------------------------------------
function check_caller(d::Dict, _cmd::String, opt_S::String, opt_W::String, caller::String, g_bar_fill, O::Bool)::String
	# Set sensible defaults for the sub-modules "scatter" & "bar"
	cmd = Vector{String}(undef,1)
	cmd[1] = _cmd
	if (caller == "scatter")
		if (opt_S == "")  cmd[1] *= " -Sc5p"  end
	elseif (caller == "scatter3")
		if (opt_S == "")  cmd[1] *= " -Su2p"  end
	elseif (caller == "lines")
		if (!occursin("+p", cmd[1]) && opt_W == "") cmd[1] *= " -W0.25p"  end # Do not leave without a pen specification
	elseif (caller == "bar")
		if (opt_S == "")
			if (haskey(d, :bar))
				cmd[1] = parse_bar_cmd(d, :bar, cmd[1], "Sb")
			elseif (haskey(d, :hbar))
				cmd[1] = parse_bar_cmd(d, :hbar, cmd[1], "SB")
			else
				opt = (haskey(d, :width)) ? add_opt(d, "", "",  [:width]) : "0.8"	# The default
				cmd[1] *= " -Sb" * opt * "u"

				optB = (haskey(d, :base)) ? add_opt(d, "", "",  [:base]) : "0"
				cmd[1] *= "+b" * optB
			end
		end
		(g_bar_fill === nothing && !occursin(" -G", cmd[1]) && !occursin(" -C", cmd[1])) && (cmd[1] *= " -G0/115/190")	# Default color
	elseif (caller == "bar3")
		if (haskey(d, :noshade) && occursin("-So", cmd[1]))
			cmd[1] = replace(cmd[1], "-So" => "-SO", count=1);
			delete!(d, :noshade)
		end
		if (!occursin(" -G", cmd[1]) && !occursin(" -C", cmd[1]))  cmd[1] *= " -G0/115/190"	end
		if (!occursin(" -J", cmd[1]))  cmd[1] *= " -JX12c/0"  end
	end

	if (occursin('3', caller))
		if (!occursin(" -B", cmd[1]) && !O)  cmd[1] *= def_fig_axes3  end	# For overlays default is no axes
		if (!occursin(" -p", cmd[1]))  cmd[1] *= " -p200/30"  end
	end

	return cmd[1]
end

# ---------------------------------------------------------------------------------------------------
function parse_bar_cmd(d::Dict, key::Symbol, cmd::String, optS::String, no_u::Bool=false)::String
	# Deal with parsing the 'bar' & 'hbar' keywors of psxy. Also called by plot/bar3. For this
	# later module if input is not a string or NamedTuple the scatter options must be processed in bar3().
	# KEY is either :bar or :hbar
	# OPTS is either "Sb", "SB" or "So"
	# NO_U if true means to NOT automatic adding of flag 'u'
	opt =""
	if (haskey(d, key))
		if (isa(d[key], String))
			cmd *= " -" * optS * d[key];	delete!(d, key)
		elseif (isa(d[key], NamedTuple))
			opt = add_opt(d, "", optS, [key], (width="",unit="1",base="+b",height="+B",nbands="+z",Nbands="+Z"))
		else
			error("Argument of the *bar* keyword can be only a string or a NamedTuple.")
		end
	end

	if (opt != "")				# Still need to finish parsing this
		flag_u = no_u ? "" : 'u'
		if ((ind = findfirst("+", opt)) !== nothing)	# See if need to insert a 'u'
			if (!isletter(opt[ind[1]-1]))  opt = opt[1:ind[1]-1] * flag_u * opt[ind[1]:end]  end
		else
			pb = (optS != "So") ? "+b0" : ""		# The default for bar3 (So) is set in the bar3() fun
			if (!isletter(opt[end]))  opt *= flag_u	  end	# No base set so default to ...
			opt *= pb
		end
		cmd *= opt
	end
	return cmd
end


text:
export Problem

Float64OrVoid = Union{Float64, Void}
SumSquaresExprOrVoid = Union{SumSquaresExpr, Void}

type Problem
  head::Symbol
  objective::SumSquaresExpr
  constraints::Array{EqConstraint, 1}
  status::String
  optval::Float64OrVoid

  function Problem(head::Symbol, objective::SumSquaresExprOrVoid, constraints::Array{EqConstraint, 1})
    this = new(head, objective, constraints, "not yet solved", nothing)
    return this
  end
end


text:
# This file was generated, do not modify it. # hide
r = range(xgb, :num_round, lower=10, upper=500)
curve = learning_curve!(xgbm, resampling=CV(),
                        range=r, resolution=25,
                        measure=cross_entropy)

max_stars_repo_name: vdayanand/MLJTutorials

max_issues_repo_name: vdayanand/MLJTutorials

max_forks_repo_name: vdayanand/MLJTutorials


text:
const allocated = Dict{Ptr{Int8},Tuple{Mem.VEBuffer,Int}}()

function allocate(bytes::Int)
    # 0-byte allocations shouldn't hit the pool
    bytes == 0 && return VE_NULL

    #buf = Mem.device_alloc(bytes)
    buf = Mem.VEBuffer(bytes)

    @assert !haskey(allocated, pointer(buf))
    allocated[pointer(buf)] = buf, 1

    return buf
end

function alias(ptr)
    # 0-byte allocations shouldn't hit the pool
    ptr == VE_NULL && return

    buf, refcount = allocated[ptr]
    allocated[ptr] = buf, refcount+1

    return
end

function release(buf::Mem.VEBuffer)
    # 0-byte allocations shouldn't hit the pool
    pointer(buf) == VE_NULL && return

    buf, refcount = allocated[pointer(buf)]
    if refcount == 1
        delete!(allocated, pointer(buf))
    else
        allocated[pointer(buf)] = buf, refcount-1
        return
    end
    finalize(buf)
    return
end


text:
#=
BFSLevels:
- Julia version: 1.6.2
- Author: samuel
- Date: 2021-09-10
=#

using SuiteSparseGraphBLAS
using SparseArrays

function updateVisited(f, visited)
    for i=1:length(f)
        if(f[i]!=false)
            visited[i] = true
        end
    end

    return visited

end

#A is the input matrix, s is the source node, and n is the number of nodes
function bfs_level(A, s, n)

    #vector init
    frontier = GBVector{Bool}(n)
        for i = 1:n
            frontier[i] = false
        end

    #init result vector
    distance = GBVector{Int64}(n)
        for i = 1:n
            distance[i] = 0
        end

    #visited vector -> v[s]=1 because the source is already visited
    visited = GBVector{Bool}(n)
    visited[s] = true

    #putting source node inside the frontier
    frontier[s]= true

    print("starting from source node\n\n")
    for level = 1:n
            visited = updateVisited(frontier, visited)
            print("current nodes in frontier:\n\n")
            print(frontier)
            print("\n")
            print("vector distances:\n\n")
            print(distance)
            print("\n")
            pastdistance = distance
            distance[frontier] .= level
            frontier = mul(frontier, A, Semirings.LOR_LAND)
            unvisited = filter(x -> x!=true, visited)
            if(isempty(unvisited))
                break
            end
    end

    print(distance)
    return distance

end


text:
# example of a unit test in Julia
# runs a test for a certain module
# to run the tests, first open the package manager (`]` in REPL),
# activate the project if not done so and then enter `test`

# wrap all your tests and subgroups in a `@testset` block
@testset "Example" begin
    using STMOZOO.Example  # load YOUR module

    @testset "solve quadratic" begin
        # test some cases
        @test solve_quadratic_system(8.0, -2.0, 3.0) == 0.25

        # test for type
        @test solve_quadratic_system(7.0, 27.4, 3.0) isa Number

        # test for type stability
        @test solve_quadratic_system(1//2 , -2//1, 3//1) isa Rational

        P = [10 1; 1 5]
        q = [100, -7]

        # test for a result
        # use ≈ (`\approx<TAB>`) to check approximate equality
        # useful for rounding errors
        # NOTE: does NOT work on ≈ 0!
        @test solve_quadratic_system(P, q) ≈  - P \ q
        @test solve_quadratic_system(P, q, testPD=true) isa Vector

        # test if a certain error is thrown
        @test_throws AssertionError solve_quadratic_system(-P, q, testPD=true)
    end

    @testset " quadratic function" begin
        f_scalar = quadratic_function(3, 4, 8)

        @test f_scalar isa Function
        @test f_scalar(2) isa Number
        @test f_scalar(2) ≈ 0.5 * 3 * 2^2 + 4 * 2 + 8

        P = [9.0 -2; -2 3]
        q = [-3, -4]
        r = -π
        x = [-2.0, 2.8]

        f_vect = quadratic_function(P, q, r)
        @test f_vect isa Function
        @test f_vect(x) isa Number
        @test f_vect(x) ≈ 0.5x' * P * x + q' * x + r
    end
end


text:
module TestCSerd
using Test
using Serd.CSerd

import ..TurtleEx1

# Reader
########

# Test read of triples from file.
stmts = SerdStatement[]
statement_sink = stmt -> push!(stmts, stmt)
reader = serd_reader_new(SERD_TURTLE, nothing, nothing, statement_sink, nothing)
serd_reader_read_file(reader, TurtleEx1.turtle_path)
@test stmts == TurtleEx1.serd_triples

# Test read of triples from string.
stmts = SerdStatement[]
statement_sink = stmt -> push!(stmts, stmt)
reader = serd_reader_new(SERD_TURTLE, nothing, nothing, statement_sink, nothing)
serd_reader_read_string(reader, TurtleEx1.turtle)
@test stmts == TurtleEx1.serd_triples

# Test error handling.
@test_throws SerdException serd_reader_read_string(reader, "XXX")
errors = SerdStatus[]
serd_reader_set_error_sink(reader, status -> push!(errors, status))
@test_throws SerdException serd_reader_read_string(reader, "XXX")
@test errors == [ SERD_ERR_BAD_SYNTAX ]

# Test manual free of reader (not necessary but allowed).
serd_reader_free(reader)
@test reader.ptr == C_NULL

# Test read of quads with default graph.
stmts = SerdStatement[]
statement_sink = stmt -> push!(stmts, stmt)
reader = serd_reader_new(SERD_TURTLE, nothing, nothing, statement_sink, nothing)
serd_reader_set_default_graph(reader, SerdNode("ex:graph", SERD_CURIE))
serd_reader_read_string(reader, TurtleEx1.turtle)
@test stmts == TurtleEx1.serd_quads

# Test read of base, prefix, and triples.
bases, prefixes, stmts = SerdNode[], Tuple{SerdNode,SerdNode}[], SerdStatement[]
base_sink = uri -> push!(bases, uri)
prefix_sink = (name, uri) -> push!(prefixes, (name,uri))
statement_sink = stmt -> push!(stmts, stmt)
reader = serd_reader_new(SERD_TURTLE, base_sink, prefix_sink, statement_sink, nothing)
serd_reader_read_string(reader, TurtleEx1.turtle)
@test bases == []
@test prefixes == TurtleEx1.serd_prefixes
@test stmts == TurtleEx1.serd_triples

# Writer
########

function normalize_whitespace(text::AbstractString)
  text = replace(replace(text, r"\n+" => "\n"), r"\t" => "  ")
  string(strip(text), "\n") # Exactly one trailing newline.
end

# Test write of single triple.
buf = IOBuffer()
writer = serd_writer_new(SERD_TURTLE, SerdStyles(0), buf)
serd_writer_write_statement(writer, TurtleEx1.serd_triples[1])
serd_writer_finish(writer)
text = String(take!(buf))
@test normalize_whitespace(text) == """
<http://www.w3.org/TR/rdf-syntax-grammar>
  dc:title \"RDF/XML Syntax Specification (Revised)\" .
"""

# Test write of single quad.
serd_writer_write_statement(writer, TurtleEx1.serd_quads[1])
serd_writer_finish(writer)
text = String(take!(buf))
@test normalize_whitespace(text) == """
ex:graph {
   <http://www.w3.org/TR/rdf-syntax-grammar>
    dc:title \"RDF/XML Syntax Specification (Revised)\" .
 }
"""

# Test write of base URI and prefix.
serd_writer_set_base_uri(writer,
  SerdNode("http://example.org/stuff/1.0/", SERD_URI))
text = String(take!(buf))
@test text == "@base <http://example.org/stuff/1.0/> .\n"

serd_writer_set_prefix(writer,
  SerdNode("rdf", SERD_LITERAL),
  SerdNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#", SERD_URI))
text = String(take!(buf))
@test text == "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n"

# Test manual free of writer (not necessary but allowed).
serd_writer_free(writer)
@test writer.ptr == C_NULL
@test writer.env == C_NULL

end


text:
export factorize_qr,
       factorize_lq,
       factorize_svd_right,
       factorize_svd_left

"""
    factorize_qr(M::Array{<:Number, 3})

QR factorization of M tensor.
"""
function factorize_qr(M::Array{<:Number, 3})
    m1, m2, m3 = size(M)
    M = reshape(M, m1*m2, m3)
    Q, R = qr(M)
    Q = Matrix(Q)
    Q = reshape(Q, m1, m2, size(Q, 2))
    return Q, R
end

"""
    factorize_lq(M::Array{<:Number, 3})

LQ factorization of M tensor.
"""
function factorize_lq(M::Array{<:Number, 3})
    m1, m2, m3 = size(M)
    M = reshape(M, m1, m2*m3)
    L, Q = lq(M)
    Q = Matrix(Q)
    Q = reshape(Q, size(Q, 1), m2, m3)
    return L, Q
end

"""
    do_svd_with_options(M::AbstractMatrix{<:Number},
                        cutoff::Float64,
                        dimcutoff::Int,
                        normalize_S::Bool)

Do SVD with cutoff truncation and normalization of singular values.
"""
function do_svd_with_options(M::AbstractMatrix{<:Number};
                             cutoff::Float64=1e-8,
                             dimcutoff::Int=1000,
                             normalize_S::Bool=true)
    F = svd(M)
    S = F.S
    ix_cutoff = min(findlast(S .> cutoff), dimcutoff)

    S = Diagonal(S[1:ix_cutoff])
    if normalize_S
        S ./= norm(S)
    end
    U = F.U[:, 1:ix_cutoff]
    Vt = F.Vt[1:ix_cutoff, :]
    return U, S, Vt
end

"""
    factorize_svd_right(M::AbstractMatrix{<:Number}; kwargs...)

SVD factorization of M matrix (U unitary).

 -- M -- = -- U -- SVt --
"""
function factorize_svd_right(M::AbstractMatrix{<:Number}; kwargs...)
    m1, m2 = size(M)
    U, S, Vt = do_svd_with_options(M; kwargs...)
    SVt = S*Vt
    return U, SVt
end

"""
    factorize_svd_left(M::AbstractMatrix{<:Number}; kwargs...)

SVD factorization of M matrix (Vt unitary).

 -- M -- = -- US -- Vt --
"""
function factorize_svd_left(M::AbstractMatrix{<:Number}; kwargs...)
    m1, m2 = size(M)
    U, S, Vt = do_svd_with_options(M; kwargs...)
    US = U*S
    return US, Vt
end

"""
    factorize_svd_right(M::Array{<:Number, 3}; kwargs...)

SVD factorization of M tensor (U unitary).

 -- M -- = -- U -- SVt --
    |         |
"""
function factorize_svd_right(M::Array{<:Number, 3}; kwargs...)
    m1, m2, m3 = size(M)
    U, SVt = factorize_svd_right(reshape(M, m1*m2, m3); kwargs...)
    U = reshape(U, m1, m2, size(U, 2))
    return U, SVt
end

"""
    factorize_svd_left(M::Array{<:Number, 3}; kwargs...)

SVD factorization of M tensor (Vt unitary).

 -- M -- = -- US -- Vt --
    |               |
"""
function factorize_svd_left(M::Array{<:Number, 3}; kwargs...)
    m1, m2, m3 = size(M)
    US, Vt = factorize_svd_left(reshape(M, m1, m2*m3); kwargs...)
    Vt = reshape(Vt, size(Vt, 1), m2, m3)
    return US, Vt
end

"""
    factorize_svd_right(M::Array{<:Number, 4}; kwargs...)

SVD factorization of M tensor (U unitary).

 -- M -- = -- U -- SVt --
   | |        |     |
"""
function factorize_svd_right(M::Array{<:Number, 4}; kwargs...)
    m1, m2, m3, m4 = size(M)
    U, SVt = factorize_svd_right(reshape(M, m1*m2, m3*m4); kwargs...)
    U = reshape(U, m1, m2, size(U, 2))
    SVt = reshape(SVt, size(SVt, 1), m3, m4)
    return U, SVt
end

"""
    factorize_svd_left(M::Array{<:Number, 4}; kwargs...)

SVD factorization of M tensor (Vt unitary).

 -- M -- = -- US -- Vt --
   | |        |     |
"""
function factorize_svd_left(M::Array{<:Number, 4}; kwargs...)
    m1, m2, m3, m4 = size(M)
    US, Vt = factorize_svd_left(reshape(M, m1*m2, m3*m4); kwargs...)
    US = reshape(US, m1, m2, size(US, 2))
    Vt = reshape(Vt, size(Vt, 1), m3, m4)
    return US, Vt
end


text:
module MyJuliaProject
using NetCDF
using Statistics
sst = ncread("sst.mon.anom.nc","sst")
print(size(mean(sst,dims=[1,2])))
greet() = print("Hello World!")

end # module

max_stars_repo_name: braaannigan/makeYourOwnBinary

max_issues_repo_name: braaannigan/makeYourOwnBinary

max_forks_repo_name: braaannigan/makeYourOwnBinary


text:
rng = StableRNG(51803)
using LinearAlgebra

const Vec = AbstractVector

@testset "AUC" begin
    # this is random binary and random scores generated with numpy
    # then using roc_auc_score from sklearn to get the AUC
    # we check that we recover a comparable AUC and that it's invariant
    # to ordering.
    c = ["neg", "pos"]
    y = categorical(c[[0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,
                     1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1,
                     1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
                     1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0,
                     1, 0] .+ 1])
    probs = [
        0.90237535, 0.41276349, 0.94511611, 0.08390761, 0.55847392,
        0.26043136, 0.78565351, 0.20133953, 0.7404382 , 0.15307601,
        0.59596716, 0.8169512 , 0.88200483, 0.23321489, 0.94050483,
        0.27593662, 0.60702176, 0.36427036, 0.35481784, 0.06416543,
        0.45576954, 0.12354048, 0.79830435, 0.15799818, 0.20981099,
        0.43451663, 0.24020098, 0.11401055, 0.25785748, 0.86490263,
        0.75715379, 0.06550534, 0.12628999, 0.18878245, 0.1283757 ,
        0.76542903, 0.8780248 , 0.86891113, 0.24835709, 0.06528076,
        0.72061354, 0.89451634, 0.95634394, 0.07555979, 0.16345437,
        0.43498831, 0.37774708, 0.31608861, 0.41369339, 0.95691113]

    ŷ = UnivariateFinite(y[1:2], probs, augment=true)
    # ŷ = [UnivariateFinite(y[1:2], [1.0 - p, p]) for p in [
    #     0.90237535, 0.41276349, 0.94511611, 0.08390761, 0.55847392,
    #     0.26043136, 0.78565351, 0.20133953, 0.7404382 , 0.15307601,
    #     0.59596716, 0.8169512 , 0.88200483, 0.23321489, 0.94050483,
    #     0.27593662, 0.60702176, 0.36427036, 0.35481784, 0.06416543,
    #     0.45576954, 0.12354048, 0.79830435, 0.15799818, 0.20981099,
    #     0.43451663, 0.24020098, 0.11401055, 0.25785748, 0.86490263,
    #     0.75715379, 0.06550534, 0.12628999, 0.18878245, 0.1283757 ,
    #     0.76542903, 0.8780248 , 0.86891113, 0.24835709, 0.06528076,
    #     0.72061354, 0.89451634, 0.95634394, 0.07555979, 0.16345437,
    #     0.43498831, 0.37774708, 0.31608861, 0.41369339, 0.95691113]]
    @test isapprox(auc(ŷ, y), 0.455716, rtol=1e-4)
    ŷ_unwrapped = [ŷ...]
    @test isapprox(auc(ŷ_unwrapped, y), 0.455716, rtol=1e-4)

    # reversing the roles of positive and negative should return very
    # similar score
    y2 = deepcopy(y);
    levels!(y2, reverse(levels(y2)));
    @test y == y2
    @test levels(y) != levels(y2)
    ŷ2 = UnivariateFinite(y2[1:2], probs, augment=true) # same probs
    @test isapprox(auc(ŷ2, y2), auc(ŷ, y), rtol=1e-4)

end

@testset "Log, Brier, Spherical - finite case" begin
    y = categorical(collect("abb"))
    L = [y[1], y[2]]
    d1 = UnivariateFinite(L, [0.1, 0.9]) # a
    d2 = UnivariateFinite(L, Float32[0.4, 0.6]) # b
    d3 = UnivariateFinite(L, [0.2, 0.8]) # b
    yhat = [d1, d2, d3]
    ym = vcat(y, [missing,])
    yhatm = vcat(yhat, [d3, ])

    @test mean(log_loss(yhat, y)) ≈
        Float32(-(log(0.1) + log(0.6) + log(0.8))/3)
    @test mean(skipmissing(log_loss(yhatm, ym))) ≈
        Float32(-(log(0.1) + log(0.6) + log(0.8))/3)
    yhat = UnivariateFinite(L, [0.1 0.9;
                                0.4 0.6;
                                0.2 0.8])
    @test isapprox(mean(log_loss(yhat, y)),
                   -(log(0.1) + log(0.6) + log(0.8))/3, atol=eps(Float32))

    @test log_score(yhat, y) ≈ -log_loss(yhat, y)

    # sklearn test
    # >>> from sklearn.metrics import log_loss
    # >>> log_loss(["spam", "ham", "ham", "spam","ham","ham"],
    #    [[.1, .9], [.9, .1], [.8, .2], [.35, .65], [0.2, 0.8], [0.3,0.7]])
    # 0.6130097025803921
    y2 = categorical(["spam", "ham", "ham", "spam", "ham", "ham"])
    L2 = classes(y2[1])
    probs = vcat([.1 .9], [.9 .1], [.8 .2], [.35 .65], [0.2 0.8], [0.3 0.7])
    yhat2 = UnivariateFinite(L2, probs)
    y2m = vcat(y2, [missing,])
    yhat2m = UnivariateFinite(L2, vcat(probs, [0.1 0.9]))
    @test mean(log_loss(yhat2, y2)) ≈ 0.6130097025803921
    @test mean(skipmissing(log_loss(yhat2, y2))) ≈ 0.6130097025803921

    # Brier
    scores = BrierScore()(yhat, y)
    @test size(scores) == size(y)
    @test Float32.(scores) ≈ [-1.62, -0.32, -0.08]
    scoresm = BrierScore()(yhatm, ym)
    @test Float32.((scoresm)[1:3]) ≈ [-1.62, -0.32, -0.08]
    @test ismissing(scoresm[end])
    # sklearn test
    # >>> from sklearn.metrics import brier_score_loss
    # >>> brier_score_loss([1, 0, 0, 1, 0, 0], [.9, .1, .2, .65, 0.8, 0.7])
    # 0.21875 NOTE: opposite orientation
    @test -mean(BrierScore()(yhat2, y2)) / 2 ≈ 0.21875
    probs2 = [[.1, .9], [Float32(0.9), Float32(1) - Float32(0.9)], [.8, .2],
              [.35, .65], [0.2, 0.8], [0.3, 0.7]]
    yhat3 = [UnivariateFinite(L2, prob) for prob in probs2]
    @test -mean(BrierScore()(yhat3, y2) / 2) ≈ 0.21875
    @test mean(BrierLoss()(yhat3, y2) / 2) ≈ -mean(BrierScore()(yhat3, y2) / 2)

    # Spherical
    s = SphericalScore() # SphericalScore(2)
    norms = [norm(probs[i,:]) for i in 1:size(probs, 1)]
    @test (pdf.(yhat2, y2) ./ norms) ≈  s(yhat2, y2)
    # non-performant version:
    yhat4 = [yhat2...]
    @test (pdf.(yhat2, y2) ./ norms) ≈  s(yhat4, y2)
end

@testset "LogScore, BrierScore, SphericalScore - infinite case" begin
    uniform = Distributions.Uniform(2, 5)
    betaprime = Distributions.BetaPrime()
    discrete_uniform = Distributions.DiscreteUniform(2, 5)
    w = [2, 3]

    # brier
    yhat = [missing, uniform]
    @test isapprox(brier_score(yhat, [1.0, 1.0]) |> last, -1/3)
    @test isapprox(brier_score(yhat, [NaN, 4.0]) |> last,  1/3)
    @test isapprox(brier_score(yhat, [1.0, 1.0], w) |> last, -1)
    yhat = [missing, uniform]
    # issue https://github.com/JuliaStats/Distributions.jl/issues/1392
    @test_broken isapprox(brier_score(yhat, [missing, 4.0], w), [1,])
    yhat = [discrete_uniform, discrete_uniform]
    @test isapprox(brier_score(yhat, [NaN, 1.0]), [-1/4, -1/4,])
    @test isapprox(brier_score(yhat, [4.0, 4.0]), [1/4, 1/4,])

    # spherical
    yhat = [uniform, uniform]
    @test isapprox(spherical_score(yhat, [1.0, 1.0]), [0, 0])
    @test isapprox(spherical_score(yhat, [NaN, 4.0]), [0, 1/sqrt(3),])
    # issue https://github.com/JuliaStats/Distributions.jl/issues/1392
    @test_broken isapprox(spherical_score(yhat, [missing, 4.0], w), [sqrt(3),])
    @test isapprox(spherical_score(yhat, [4.0, 4.0], w), [2/sqrt(3), sqrt(3),])
    yhat = [discrete_uniform, discrete_uniform]
    @test isapprox(spherical_score(yhat, [NaN, 1.0]), [0, 0])
    @test isapprox(spherical_score(yhat, [4.0, 4.0]), [1/2, 1/2])

    # log
    yhat = [uniform, uniform]
    @test isapprox(log_score(yhat, [4.0, 4.0]), [-log(3), -log(3),])
    @test isapprox(log_score(yhat, [4.0, 4.0], w), [-2*log(27)/3, -log(27)])
    yhat = [discrete_uniform, discrete_uniform]
    # issue https://github.com/JuliaStats/Distributions.jl/issues/1392
    @test_broken  isapprox(log_score(yhat, [missing, 4.0]), [-log(4),])

    log_score([missing, uniform], [4.0, 4.0])

    # errors
    @test_throws(MLJBase.err_l2_norm(brier_score),
                 brier_score([betaprime, betaprime], [1.0, 1.0]))
    s = SphericalScore(alpha=1)
    @test_throws MLJBase.ERR_UNSUPPORTED_ALPHA s(yhat, [1.0, 1.0])
end

true


text:
#=
Copyright (c) 2015, Intel Corporation
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
  this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
=#

module Stencil

import Base: getindex, setindex!
import CompilerTools
export runStencil, @runStencil

type AbstractStencilArray
  dimension :: Int
  sizes :: Array{Int, 1}
  baseIdx :: Array{Int, 1}
  src :: Any
  borderStyle :: Symbol
end

function getindex(asa::AbstractStencilArray, idx...)
  idx = [idx...]
  local n = length(idx)
  assert(n == asa.dimension)
  for i = 1:n
    idx[i] = idx[i] + asa.baseIdx[i]
    if (idx[i] < 1 || idx[i] > asa.sizes[i])
      if asa.borderStyle == :oob_src_zero
        return 0
      elseif asa.borderStyle == :oob_wraparound
        idx[i] = mod(idx[i] - 1, asa.sizes[i]) + 1
      else
        return NaN         # TODO: better ways to symbolize out-of-bounds
      end
    end
  end
  asa.src[idx...]
end

function setindex!(asa::AbstractStencilArray, value, idx...)
  idx = [idx...]
  local n = length(idx)
  assert(n == asa.dimension)
  for i = 1:n
    idx[i] = idx[i] + asa.baseIdx[i]
    if idx[i] < 1 || idx[i] > asa.sizes[i]
      throw(string("Index ", idx, " is out of bounds!"))
    end
  end
  if is(value, NaN)
    if asa.borderStyle == :oob_dst_zero
      asa.src[idx...] = 0
    end
  else
    asa.src[idx...] = value
  end
end

"""
"runStencil" takes arguments in the form of "(kernel_function, A, B, C, ...,
iteration, border_style)" where "kernel_function" is a lambda that represent
stencil kernel, and "A", "B", "C", ... are arrays (of same dimension and size)
that will be traversed by the stencil, and they must match the number of
arguments of the stencil kernel. "iteration" and "border_style" are optional,
and if present, "iteration" is the number of steps to repeat the stencil
computation, and "border_style" is a symbol of the following:

    :oob_src_zero, returns zero from a read when it is out-of-bound.

    :oob_dst_zero, writes zero to destination array in an assigment should any read in its right-hand-side become out-of-bound.

    :oob_wraparound, wraps around the index (with respect to source array dimension and sizes) of a read operation when it is out-of-bound.

    :oob_skip, skips write to destination array in an assignment should any read in its right-hand-side become out-of-bound.

The "kernel_function" should take a set of arrays as input, and in the function
body only index them with relative indices as if there is a cursor (at index 0)
traversing them. It may contain more than one assignment to any input arrays,
but such writes must always be indexed at 0 to guarantee write operation never
goes out-of-bound. Also care must be taken when the same array is both read
from and written into in the kernel function, as they'll result in
non-deterministic behavior when the stencil is parallelized by ParallelAccelerator.

The "kernel_function" may optionally access scalar variables from outerscope,
but no write is permitted.  It may optinally contain a return statement, which
acts as a specification for buffer swapping when it is an interative stencil
loop (ISL). The number of arrays returned must match the input arrays.  If it
is not an ISL, it should always return nothing.

This function is a reference implementation of stencil in native Julia for two
purposes: to verify expected return result, and to make sure user code type
checks. It runs very very slow, so any real usage should go through ParallelAccelerator
optimizations.

"runStencil" always returns nothing.
"""
function runStencil(inputs...)
  #  (func, buf, ..., iterations, border)
  arrs = Array[]
  assert(length(inputs) >= 3)
  kernelFunc = inputs[1]
  iterations = 1
  borderStyle = nothing
  for i = 2:length(inputs)
    typ = typeof(inputs[i])
    if typ <: AbstractArray
      push!(arrs, inputs[i])
    elseif is(typ, Int)
      iterations = inputs[i]
    else
      borderStyle = inputs[i]
    end
  end
  narrs = length(arrs)
  assert(narrs > 1)
  local sizes = [size(arrs[1])...]
  local n = length(sizes)
  local indices = Array(Int, n)
  local bufs = [ AbstractStencilArray(n, sizes, indices, arr, borderStyle) for arr in arrs ]
  for steps = 1 : iterations
    for i = 1:n
      indices[i] = 1
    end
    local done = false
    local ret = nothing
    while !done
      try
        ret = kernelFunc(bufs...)
      catch e
        #ignore
      end
      i=1
      while i<=n
        if indices[i] < sizes[i]
          indices[i] = indices[i] + 1
          break
        else
          indices[i] = 1
          if i < n
            i = i + 1
          else
            done = true
            break
          end
        end
      end
    end
    if isa(ret, Tuple) bufs = ret end
  end
  return nothing
end

type KernelStat
  dimension :: Int             # number of dimensions of the stencil
  shapeMax  :: Array{Int,1}    # max extent of the stencil for each dimension
  shapeMin  :: Array{Int,1}    # min extent of the stencil for each dimension
  idxSym    :: Array{Symbol,1} # (fresh) symbol of index variable
  bufSym    :: Array{Symbol,1} # (fresh) symbol of buffer variables
  swapSym   :: Union{Void, Array{Symbol, 1}}
end

# Analyze a stencil kernel specified as a lambda expression.
# Return both the kernel stat, and the modified kernel LHS expression.
# Note that the input kernel is modified in-place.
function analyze_kernel(krn, esc)
  assert(krn.head == :(->))
  local stat = ()
  local params = krn.args[1]  # parameter of the kernel lambda, must be a tuple of symbols
  local bufs
  if isa(params, Expr) && is(params.head, :tuple)
    bufs = Symbol[ arg for arg in params.args ] # all buffers, must be an array of symbols
  else isa(params, Symbol)
    bufs = Symbol[ params ]
  end
  local nbufs = length(bufs)
  bufSym = Symbol[ gensym(string("b", i)) for i=1:nbufs ]
  bufMap = Dict{Symbol,Symbol}(zip(bufs, bufSym))
  local expr = krn.args[2]
  function traverse(expr)     # traverse expr to find the places where arrSym is refernced
    assert(isa(expr, Expr))
    if is(expr.head, :ref)
      if haskey(bufMap, expr.args[1]) # one of input bufers
        expr.args[1] = bufMap[expr.args[1]] # modify the reference to actual source array
        local dim = length(expr.args) - 1
        @assert (dim <= 10) "the dimension must be no greater than 10"
        if is(stat, ())         # create stat if not already exists
          local idxSym = [ gensym(string("i", i)) for i in 1:dim ]
          stat = KernelStat(dim, zeros(dim), zeros(dim), idxSym, bufSym, nothing)
        else                    # if stat already exists, check if the dimension matches
          @assert (dim == stat.dimension) "number of dimensions do not match"
        end
        for i = 1:dim           # update extents and index calculation in expr
          @assert (isa(expr.args[i+1], Int)) "array indices must be int literals"
          local idx = Int(expr.args[i+1])
          stat.shapeMax[i] = max(idx, stat.shapeMax[i])
          stat.shapeMin[i] = min(idx, stat.shapeMin[i])
          expr.args[i+1] = :($(stat.idxSym[i]) + $(expr.args[i+1]))
        end
      end
    elseif is(expr.head, :return)
      swapSym = Symbol[]
      args = expr.args[1]
      if isa(args, Expr) && is(args.head, :tuple)
        args = args.args
      elseif isa(args, Symbol)
        args = Symbol[args]
      end
      for s in args
        @assert (isa(s, Symbol)) "return value must be plain variable"
        i = 1
        while i <= nbufs
          if bufs[i] == s break end
          i += 1
        end
        @assert (i <= nbufs) "return value must be one of the kernel parameters"
        push!(swapSym, bufSym[i])
      end
      @assert (length(swapSym) == nbufs) "number of return values must match number parameters"
      stat.swapSym = swapSym
       # turn it into something harmless
      expr.head = :block
      expr.args = Any[]
    else                        # recurse when expr is not array ref
      for i in 1:length(expr.args)
        e = expr.args[i]
        if isa(e, Expr)
          traverse(e)
        elseif isa(e, Symbol)
          if !(expr.head == :line || expr.head == :method) && !(expr.head == :call && i == 1) && !haskey(bufMap, e)
            expr.args[i] = esc(e)
          end
        end
      end
    end
  end
  traverse(expr)
  @assert (stat != ()) "Fail to analyze stencil kernel"
  return stat, expr, nbufs
end

# Helper function to create nested loops with an innermost body
function nestedLoop(dim, indices, iters, body)
  function mkLoop(i, body)
    if i > dim
      body
    else
        mkLoop(i+1, :(for $(indices[i]) = $(iters[i]); $(body); end))
    end
  end
  mkLoop(1, body)
end

# turn an array of Expr blocks into an a single block of Exprs
function liftQuote(exprs::Array{Expr,1})
  args = vcat([ is(expr.head, :block) ? expr.args : expr for expr in exprs ]...)
  Expr(:block, args...)
end

function specializeBorder(borderSty, borderCheckF, modF, krnExpr)
  oob_dst_zero = borderSty == :oob_dst_zero
  oob_src_zero = borderSty == :oob_src_zero
  oob_wraparound = borderSty == :oob_wraparound
  function traverse(expr)
    if is(expr.head, :(=)) && isa(expr.args[1], Expr) && is(expr.args[1].head, :ref)
      lhs = expr.args[1]
      rhs = expr.args[2]
      if oob_dst_zero
        rhs = 0
      elseif isa(rhs, Expr)
        rhs = traverse(rhs)
      end
      return Expr(expr.head, lhs, rhs)
    elseif is(expr.head, :ref)
      if oob_src_zero
        return Expr(:if, borderCheckF(expr.args[2:end]), expr, 0)
      elseif oob_wraparound
        return Expr(expr.head, expr.args[1], modF(expr.args[2:end])...)
      end
    end
    args = [ isa(e, Expr) ? traverse(e) : e for e in expr.args ]
    return Expr(expr.head, args...)
  end
  traverse(krnExpr)
end

# A macro version of runStencil that unfolds stencil call into nested sequential loops.
# Note that it has yet to handle border settings.
macro runStencil(krn, args...)
  translateStencil(krn, Any[x for x in args], esc)
end

function translateStencil(krn, args::Array, esc)
  local steps = 1
  local borderSty = :oob_skip
  stat, krnExpr, nbufs = analyze_kernel(krn, esc)
  @assert (length(args) >= nbufs) "Expect number of array arguments to runStencil to be no less than that of the kernel"
  # get the real buffer arguments
  bufs = args[1:nbufs]
  # get iteration and border style from args
  args = args[(nbufs+1):end]
  if length(args) == 2
    steps = args[1]
    borderSty = args[2]
  elseif length(args) == 1
    if isa(args[1], Expr) && args[1].head == :quote
      borderSty = args[1]
    else
      steps = args[1]
    end
  end
  # check border style
  if isa(borderSty, Expr)
    try
      borderSty = eval(borderSty)
    catch e
      error("Expect border style to be :oob_src_zero, :oob_dst_zero, :oob_wraparound, or :oob_skip")
    end
  end
  @assert isa(borderSty, Symbol) "Expect border style to be :oob_src_zero, :oob_dst_zero, :oob_wraparound, or :oob_skip"
  # produce the expanded stencil loop
  local tmpSym  = [ gensym("tmp") for i = 1:nbufs ]
  local idxSym  = stat.idxSym
  local bufSym  = stat.bufSym
  local swapSym = stat.swapSym
  local sizeSym = [ gensym(string("len", i)) for i = 1:stat.dimension ]
  local stepSym = gensym("step")
  local bufInitExpr = liftQuote([ :($(bufSym[i]) = $(esc(bufs[i]))) for i = 1:nbufs ])
  local sizeTuple = Expr(:tuple, sizeSym...)
  local sizeInitExpr = :($(sizeTuple) = size($(bufSym[1])))
  # border region
  local innerIterExpr = [ :((1-$(stat.shapeMin[i])) : ($(sizeSym[i]) - $(stat.shapeMax[i]))) for i = 1:stat.dimension ]
  local borderIterExpr = [ :(1:$(sizeSym[i])) for i = 1:stat.dimension ]
  local innerCheckF(idx) = Expr(:call, GlobalRef(Base,:&), [ Expr(:call, GlobalRef(Base,:in), idx[i], innerIterExpr[i]) for i = 1:stat.dimension ]...)
  local borderCheckF(idx) = Expr(:call, GlobalRef(Base,:&), [ Expr(:call, GlobalRef(Base,:in), idx[i], borderIterExpr[i]) for i = 1:stat.dimension ]...)
  local modF(idx) = [ :((($(idx[i]) + $(sizeSym[i]) - 1) % $(sizeSym[i])) + 1) for i = 1:stat.dimension ]
  local borderKrnExpr = specializeBorder(borderSty, borderCheckF, modF, krnExpr)
  local borderExpr = borderSty == :oob_skip ? :() :
                    nestedLoop(stat.dimension, idxSym, borderIterExpr, :(if $(innerCheckF(idxSym)) else $(borderKrnExpr) end))
  # inner region
  local loopExpr = nestedLoop(stat.dimension, stat.idxSym, innerIterExpr, krnExpr)
  local swapExpr = is(swapSym, nothing) ? :() :
                     liftQuote(vcat([ :($(tmpSym[i]) = $(swapSym[i])) for i = 1:nbufs ],
                                    [ :($(bufSym[i]) = $(tmpSym[i])) for i = 1:nbufs ]))
  local expr = quote
    $(bufInitExpr)
    $(sizeInitExpr)
    for $(stepSym) = 1:$(esc(steps))
      $(borderExpr)
      @inbounds $(loopExpr)
      $(swapExpr)
    end
  end
  return expr
end

"""
This function is a AstWalker callback.
"""
function process_node(node, state, top_level_number, is_top_level, read)
  if !isa(node,Expr)
    return CompilerTools.AstWalker.ASTWALK_RECURSE
  end
  if node.head == :call && node.args[1] == :runStencil
    return translateStencil(node.args[2], node.args[3:end], x -> x)
  else
    return CompilerTools.AstWalker.ASTWALK_RECURSE
  end
end

"""
Translate all comprehension in an AST into equivalent code that uses cartesianarray call.
"""
macro comprehend(ast)
  AstWalker.AstWalk(ast, process_node, nothing)
  Core.eval(current_module(), ast)
end

end


text:
module day02
using Pipe: @pipe
using DataStructures

include("inputs.jl")
ex = inputs.ex_d2() # Lines are pairs of policy & passwords
input = inputs.input_d2()

struct pol_pw
    min::Int
    max::Int
    letter::Char
    password::String
end

# Part 1
function parse_line(line)
    policy, password = split(line, ": ")
    range, letter = split(policy, ' ')
    min_n, max_n = parse.(Int, split(range, '-'))
    return pol_pw(min_n, max_n, first(letter), password)
end

function is_valid(pp)
    counts = counter(pp.password)
    return pp.min <= counts[pp.letter] <= pp.max
end

count_valids(input) = count(is_valid, parse_line.(input))

@assert count_valids(ex) == 2
@info "Day 2, Part 1 answer: $(count_valids(input))"

# Part 2
function is_valid_p2(pp)
    return xor(pp.password[pp.min] == pp.letter,
    pp.password[pp.max] == pp.letter)
end

count_valids_p2(input) = count(is_valid_p2, parse_line.(input))
@assert count_valids_p2(ex) == 1
@info "Day 2, Part 2 answer: $(count_valids_p2(input))"

end


text:
"""
    welcome(customer)

Return the welcome message for the customer.
"""
welcome(customer) = "Welcome to the Tech Palace, " * uppercase(customer)

"""
    add_border(message, n)

Return the welcome message with a border of stars.
"""
add_border(message, n) = "*"^n * "\n" * message * "\n" * "*"^n

"""
    clean(message)

Return the cleaned up marketing message.
"""
clean(message) = strip(message)

max_stars_repo_name: stepinski/julia

max_issues_repo_name: stepinski/julia

max_forks_repo_name: stepinski/julia


text:
@defcomp neteconomy begin

    ABATECOST   = Variable(index=[time])    #Cost of emissions reductions  (trillions 2005 USD per year)
    C           = Variable(index=[time])    #Consumption (trillions 2005 US dollars per year)
    CPC         = Variable(index=[time])    #Per capita consumption (thousands 2005 USD per year)
    CPRICE      = Variable(index=[time])    #Carbon price (2005$ per ton of CO2)
    I           = Variable(index=[time])    #Investment (trillions 2005 USD per year)
    MCABATE     = Variable(index=[time])    #Marginal cost of abatement (2005$ per ton CO2)
    Y           = Variable(index=[time])    #Gross world product net of abatement and damages (trillions 2005 USD per year)
    YNET        = Variable(index=[time])    #Output net of damages equation (trillions 2005 USD per year)

    cost1       = Parameter(index=[time])   #Abatement cost function coefficient
    DAMAGES     = Parameter(index=[time])   #Damages (Trillion $)
    l           = Parameter(index=[time])   #Level of population and labor
    MIU         = Parameter(index=[time])   #Emission control rate GHGs
    partfract   = Parameter(index=[time])   #Fraction of emissions in control regime
    pbacktime   = Parameter(index=[time])   #Backstop price
    S           = Parameter(index=[time])   #Gross savings rate as fraction of gross world product
    YGROSS      = Parameter(index=[time])   #Gross world product GROSS of abatement and damages (trillions 2005 USD per year)
    expcost2    = Parameter()               #Exponent of control cost function

    function run_timestep(p, v, d, t)
        #Define function for YNET
        v.YNET[t] = p.YGROSS[t] - p.DAMAGES[t]

        #Define function for ABATECOST
        v.ABATECOST[t] = p.YGROSS[t] * p.cost1[t] * (p.MIU[t]^p.expcost2) * (p.partfract[t]^(1 - p.expcost2))

        #Define function for MCABATE (equation from GAMS version)
        v.MCABATE[t] = p.pbacktime[t] * p.MIU[t]^(p.expcost2 - 1)

        #Define function for Y
        v.Y[t] = v.YNET[t] - v.ABATECOST[t]

        #Define function for I
        v.I[t] = p.S[t] * v.Y[t]

        #Define function for C
        v.C[t] = v.Y[t] - v.I[t]

        #Define function for CPC
        v.CPC[t] = 1000 * v.C[t] / p.l[t]

        #Define function for CPRICE (equation from GAMS version of DICE2013)
        v.CPRICE[t] = p.pbacktime[t] * (p.MIU[t] / p.partfract[t])^(p.expcost2 - 1)
    end
end


text:
# This file was generated, do not modify it. # hide
(VtoW ∘ WtoV)(W) ≈ W

max_stars_repo_name: cscherrer/InformativePrior

max_issues_repo_name: cscherrer/InformativePrior

max_forks_repo_name: cscherrer/InformativePrior


text:
@doc """
    print_matrix(solver::DuneIstlSolver)

Print the BCRS matrix in `solver`.

# Examples
```jldoctest
julia> using DuneIstlSolvers

julia> solver = DuneIstlSolver{Float64, Int32(2)}(3)

julia> print_matrix(solver);

```
""" print_matrix

@doc """
    print_rhs(solver::DuneIstlSolver)

Print the right-hand-side vector in `solver`.

# Examples
```jldoctest
julia> using DuneIstlSolvers

julia> solver = DuneIstlSolver{Float64, Int32(2)}(3)

julia> print_rhs(solver);

```
""" print_rhs