text:
#=
This contains all of the pieces needed to add a new code gen target.
The following three functions must be provided.

1. get_external_language_elements() - file extensions, comment chars etc.
2. generate_external_code_layer(var, entities, terms, lorr, vors) - Turns symbolic expressions into code
3. generate_external_files(var, lhs_vol, lhs_surf, rhs_vol, rhs_surf) - Writes all files based on generated code

You will have access to anything in the Femshop module scope because this file will be included there.
=#

function get_external_language_elements()
    file_extension = ".m";
    comment_char = "%";
    block_comment = ["%{"; "%}"];

    return (file_extension, comment_char, block_comment);
end

#=
Translate the symbolic layer into code for the elemental assembly.
var - unknown variable or array of variables.
entities - leaf nodes of the computational graph. Type is SymEntity(see symexpression.jl) or number.
terms - array of additive terms, separated for convenience. [t1, t2, t3] for expression t1+t2+t3 (see note below)
lorr - LHS or RHS will have constant values LHS or RHS which are "lhs", "rhs"
vors - volume or surface will have values "volume" or "surface"

Note on terms: Each term is a SymExpression(see symexpression.jl) which is essentially a Julia Expr and list of entities.
The Expr holds the computational graph for each term. LHS and RHS are determined by separating terms that involve
unknowns from those that don't. Also, in well formed FEM problems each term should be multiplied by a test function,
and thus quadrature can be done for each term separately.
=#
function generate_external_code_layer(var, entities, terms, lorr, vors)
    # This can be divided up into smaller functions however you wish.
    # The whole body of code is stored in a string that will be inserted in the
    # appropriate function during file writing.
    code = "";

    # Determine if derivative matrices will be required
    need_derivs = false;
    for i=1:length(entities)
        if length(entities[i].derivs) > 0
            need_derivs = true;
            break;
        end
    end
    if need_derivs
        code *= matlabtarget_build_derivative_matrices(lorr, vors);
        code *= "\n";
    end

    # Allocate/Evaluate or fetch the values for each needed entity.
    # Note: This could be staged and interleaved with the calculation part for complex problems. TODO
    code *= matlabtarget_prepare_needed_values(entities, var, lorr, vors);
    code *= "\n";

    # Form the final elemental calculation
    code *= matlabtarget_make_elemental_computation(terms, var, lorr, vors);

    return code;
end

# Create all of the code files.
# The input are code strings generated above. They will be inserted into their appropriate files.
function generate_external_files(var, lhs_vol, lhs_surf, rhs_vol, rhs_surf)
    # Again, this can be split up into smaller functions as you wish.
    matlab_utils_file();
    matlab_main_file(var);
    matlab_config_file();
    matlab_prob_file(var);
    matlab_mesh_file();
    matlab_genfunction_file();
    matlab_bilinear_file(lhs_vol, var);
    matlab_linear_file(rhs_vol, var);
    # matlab_stepper_file(); # TODO
    matlab_output_file();
end

#########################################################
# code writing utilities
#########################################################

# numbers: 2 -> "2"
# strings: "thing" -> "'thing'"
# arrays: [1 2; 3 4] -> "[1 2; 3 4]"
function matlab_gen_string(v)
    if typeof(v) == String
        return "'"*v*"'";

    elseif typeof(v) <: Number
        return string(v);

    elseif typeof(v) <: Array
        if length(v)>0 && typeof(v[1]) == String
            # need to use a cell array
            bracket1 = "{";
            bracket2 = "}";
        else
            bracket1 = "[";
            bracket2 = "]";
        end
        if ndims(v) == 1 # "[a; b; c]"
            n = length(v);
            str = bracket1;
            for i=1:n
                str = str*matlab_gen_string(v[i]);
                if i < n
                    str = str*"; ";
                end
            end
            str = str*bracket2;
        elseif ndims(v) == 2 # "[a b ; c d]
            (n,m) = size(v);
            str = bracket1;
            for i=1:n
                for j=1:m
                    str = str*matlab_gen_string(v[i,j])*" ";
                end
                if i < n
                    str = str*"; ";
                end
            end
            str = str*bracket2;
        end
        return str;

    elseif typeof(v) == GenFunction
        return v.name;
    else
        return string(v);
    end
end

# Returns a string like "fread(f, [3, 15], 'double')" for an array with size (3,15) and type Float64
function matlab_fread(A)
    if typeof(A) <: Array
        if length(A) == 0
            return "0";
        end
        if typeof(A[1]) == Int
            typ = "\'int64\'";
        else
            typ = "\'double\'";
        end
        if length(size(A)) == 1
            sz = "["*string(length(A))*",1]";
        elseif length(size(A)) == 2
            sz = "["*string(size(A,1))*","*string(size(A,2))*"]";
        else # Matlab's fread can only handle 2D arrays! Just smash the rest together.
            sz = "[" * string(size(A,1));
            second_dim = 1;
            for i=2:length(size(A))
                second_dim = second_dim * size(A,i);
            end
            sz *= ", " * string(second_dim) * "]";
        end
        return "fread(f, "*sz*", "*typ*")"
    else
        if typeof(A) == Int64
            typ = "\'int64\'";
        else
            typ = "\'double\'";
        end
        return "fread(f, [1], "*typ*")"
    end
end

# produces code to read a binary struct into matlab
# The struct is labeled with the name and has the same fieldnames as s
function matlab_struct_reader(name, s)
    code = "";
    for fn in fieldnames(typeof(s))
        f = getfield(s,fn);
        if typeof(f) <: Array && length(f) > 0 && typeof(f[1]) <: Array
            code = code * name * "." * string(fn) * " = cell([" * string(length(f)) * ", 1]);\n";
            for i=1:length(f)
                code = code * name * "." * string(fn) * "{" * string(i) * "} = " * matlab_fread(f[i]) * ";\n";
            end
        else
            code = code * name * "." * string(fn) * " = " * matlab_fread(f) * ";\n";
        end
    end
    return code;
end

#######################################################
# Write code files
#######################################################

function matlab_main_file(var)
    file = add_generated_file(project_name*".m", dir="src");

    println(file, "clear;");
    println(file, "");
    # These are always included
    println(file, "");
    println(file, "Utils;");
    println(file, "Config;");
    println(file, "Mesh;");
    println(file, "Genfunction;");
    println(file, "Problem;");
    println(file, "Bilinear;");
    println(file, "Linear;");
    println(file, "");

    # No time stepping yet
    # Just a simple \ linear solve
    println(file, "result = LHS\\RHS;");

    # place values in named variable arrays
    if typeof(var) <: Array
        counter = 0;
        for vi=1:length(var)
            for i=1:var[vi].total_components
                counter += 1;
                println(file, string(var.symbol) * "_"*string(counter)*" = result("*string(counter)*":dofspernode:length(result));");
            end
        end
        println(file, "total_components = "*string(counter)*";");
    elseif var.total_components > 1
        for i=1:var.total_components
            println(file, string(var.symbol) * "_"*string(i)*" = result("*string(i)*":dofspernode:length(result));");
        end
        println(file, "total_components = "*string(var.total_components)*";");
    else
        # single component
        println(file, string(var.symbol) * " = result;");
        println(file, "total_components = 1;");
    end

    println(file, "");

    println(file, "Output;");

end

# This is a class containing various utility functions like tensor math, geometric factors, linear solve
function matlab_utils_file()
    utilsfile = add_generated_file("Utils.m", dir="src");

    content = "
classdef Utils

    methods(Static)
        % 2D routines
        function y = tensor_IAX (A, x)
            N = size (A, 1);
            y = A * reshape(x, N, N);
            y = y(:);
        end

        function y = tensor_AIX (A, x)
            N = size (A, 1);
            y = A * reshape(x, N, N)';
            y = y';
            y = y(:);
        end

        % 3D routines
        function y = tensor_IIAX (A, x)
            N = size (A, 1);
            y = A * reshape(x, N, N*N);
            y = y(:);
        end

        function y = tensor_IAIX (A, x)
            N = size (A, 1);
            q = reshape(x, N, N, N);
            y = zeros(N,N,N);
            for i=1:N
                y(i,:,:) = A * squeeze( q(i,:,:) );
            end
            y = y(:);
        end

        function y = tensor_AIIX (A, x)
            N = size (A, 1);
            y = reshape(x, N*N, N) * A';
            y = y(:);
        end

        function du = tensor_grad(refel, u)
            du = zeros(length(u), refel.dim);
            if (refel.dim == 2)
                du(:,1) = Utils.tensor_IAX (refel.Dr, u);
                du(:,2) = Utils.tensor_AIX (refel.Dr, u);
            else
                du(:,1) = Utils.tensor_IIAX (refel.Dr, u);
                du(:,2) = Utils.tensor_IAIX (refel.Dr, u);
                du(:,3) = Utils.tensor_AIIX (refel.Dr, u);
            end
        end

        function [dx, dy] = tensor_grad2(A, x)
            dx = Utils.tensor_IAX (A, x);
            dy = Utils.tensor_AIX (A, x);
        end

        function [dx, dy, dz] = tensor_grad3(A, x)
            dx = Utils.tensor_IIAX (A, x);
            dy = Utils.tensor_IAIX (A, x);
            dz = Utils.tensor_AIIX (A, x);
        end

        function [J, D] = geometric_factors(refel, pts)

            if (refel.dim == 0)
                xr  = [1];
                J = xr;
            elseif (refel.dim == 1)
                xr  = refel.Dr*pts;
                J = xr;
            elseif (refel.dim == 2)
                if refel.Nfaces == 3 % triangle
                    xr = refel.Ddr*pts(1,:)';
                    xs = refel.Dds*pts(1,:)';
                    yr = refel.Ddr*pts(2,:)';
                    ys = refel.Dds*pts(2,:)';
                    J = -xs.*yr + xr.*ys;
                    J = J(1);
                else % quad
                    [xr, xs] = Utils.tensor_grad2 (refel.Dg, pts(1,:));
                    [yr, ys] = Utils.tensor_grad2 (refel.Dg, pts(2,:));

                    J = -xs.*yr + xr.*ys;
                end

            else
                [xr, xs, xt] = Utils.tensor_grad3 (refel.Dg, pts(1,:));
                [yr, ys, yt] = Utils.tensor_grad3 (refel.Dg, pts(2,:));
                [zr, zs, zt] = Utils.tensor_grad3 (refel.Dg, pts(3,:));

                J = xr.*(ys.*zt-zs.*yt) - yr.*(xs.*zt-zs.*xt) + zr.*(xs.*yt-ys.*xt);
            end

            if (nargout > 1)
                if (refel.dim == 1)
                    D.rx = 1./J;
                elseif (refel.dim == 2)
                    if refel.Nfaces == 3 % triangle
                        D.rx =  ys./J;
                        D.sx = -yr./J;
                        D.ry = -xs./J;
                        D.sy =  xr./J;
                    else % quad
                        D.rx =  ys./J;
                        D.sx = -yr./J;
                        D.ry = -xs./J;
                        D.sy =  xr./J;
                    end

                else
                    D.rx =  (ys.*zt - zs.*yt)./J;
                    D.ry = -(xs.*zt - zs.*xt)./J;
                    D.rz =  (xs.*yt - ys.*xt)./J;

                    D.sx = -(yr.*zt - zr.*yt)./J;
                    D.sy =  (xr.*zt - zr.*xt)./J;
                    D.sz = -(xr.*yt - yr.*xt)./J;

                    D.tx =  (yr.*zs - zr.*ys)./J;
                    D.ty = -(xr.*zs - zr.*xs)./J;
                    D.tz =  (xr.*ys - yr.*xs)./J;
                end

            end
        end

        % pack and unpack variables into a global vector
        % packed vars are in a vector, unpacked are in a cell table
        function pk = pack_vars(upk, pk)
            for i=1:Nvars
                pk(i:Nvars:length(pk)) = upk{i};
            end
        end

        function upk = unpack_vars(pk)
            upk = cell(Nvars,1);
            for i=1:Nvars
                upk{i} = pk(i:Nvars:length(pk));
            end
        end
    end
end

"
    println(utilsfile, content);
end

function matlab_config_file()
    file = add_generated_file("Config.m", dir="src");
    # Duplicate the config struct
    for f in fieldnames(Femshop.Femshop_config)
        println(file, "config."*string(f)*" = "*matlab_gen_string(getfield(Femshop.config, f))*";");
    end
    println(file, "order = config.basis_order_min;");
end

function matlab_prob_file(var)
    file = add_generated_file("Problem.m", dir="src");
    # Duplicate the prob struct
    for f in fieldnames(Femshop.Femshop_prob)
        println(file, "prob."*string(f)*" = "*matlab_gen_string(getfield(Femshop.prob, f))*";");
    end
    # count dofs per node
    multivar = typeof(var) <:Array;
    dofsper = 0;
    if multivar
        dofsper = var[1].total_components;
        for i=2:length(var)
            dofsper = dofsper + var[i].total_components;
        end
    else
        dofsper = var.total_components;
    end
    println(file, "dofspernode = "*string(dofsper)*";");
end

#=
The mesh file contains any code related to setting up the mesh.
The meshdata file contains all of the data from the Refel, MeshData and Grid structs
These are to be read into matlab by a matlab matlab function in the mesh file.
=#
function matlab_mesh_file()
    file = add_generated_file("Mesh.m", dir="src");

    println(file, "f = fopen('MeshData','r');");
    println(file, "% Reference element");
    println(file, matlab_struct_reader("refel", refel));
    println(file, "% mesh data");
    println(file, matlab_struct_reader("mesh_data", mesh_data));
    println(file, "% grid data");
    println(file, matlab_struct_reader("grid_data", grid_data));
    println(file, "fclose(f);");

    datfile = add_generated_file("MeshData", dir="src", make_header_text=false);
    # refel
    Femshop.CodeGenerator.write_binary_struct(datfile, refel);
    # mesh_data
    Femshop.CodeGenerator.write_binary_struct(datfile, mesh_data);
    # grid_data
    Femshop.CodeGenerator.write_binary_struct(datfile, grid_data);
end

# Functions for boundary conditions, coeficients, etc.
function matlab_genfunction_file()
    file = add_generated_file("Genfunction.m", dir="src");

    for i = 1:length(genfunctions)
        println(file, genfunctions[i].name*"_fun = @(x,y,z,t) ("*genfunctions[i].str*");");
        # Evaluate them at grid points and make them vectors. Make sense???
        println(file, genfunctions[i].name*" = evaluate_genfun("*genfunctions[i].name*"_fun, grid_data.allnodes, 0);");
    end

    # assign variable and coefficient symbols to these vectors
    nvars = 0
    for v in variables
        println(file, string(v.symbol)*" = '"*string(v.symbol)*"';");
        nvars += size(v.values,1);
    end
    println(file, "Nvars = " * string(nvars) * ";");
    for v in coefficients
        if typeof(v.value[1]) == GenFunction
            println(file, string(v.symbol)*" = "*v.value[1].name*";");
        else
            println(file, string(v.symbol)*" = "*string(v.value[1])*";");
        end
    end

    evalgenfun =
"""
function u = evaluate_genfun(genfun, pts, t)
    n = size(pts,2);
    dim = size(pts,1);
    u = zeros(n,1);
    x = 0;
    y = 0;
    z = 0;
    for i=1:n
        x = pts(1,i);
        if dim > 1
            y = pts(2,i);
            if dim > 2
                z = pts(3,i);
            end
        end
        u(i) = genfun(x,y,z,t);
    end
end
"""
    println(file, evalgenfun);
end

# This is the matrix assembly loop.
# It requires code that was generated for this target.
function matlab_bilinear_file(code, var)
    file = add_generated_file("Bilinear.m", dir="src");

    Ddotn_part = "
                                Ddotn = RD1(bdrylocal(j),:) * normal(1)";

    if config.dimension > 1
        Ddotn_part *= " + ...
                                RD2(bdrylocal(j),:) * normal(2)";
    end
    if config.dimension > 2
        Ddotn_part *= " + ...
                                RD3(bdrylocal(j),:) * normal(3)";
    end
    Ddotn_part *= ";";

    # insert the code part into this skeleton
    content =
"
dof = size(grid_data.allnodes,2);
ne  = mesh_data.nel;
Np = refel.Np;
glbdof = zeros(Np*dofspernode,1);
I = zeros(ne * Np*Np*dofspernode*dofspernode, 1);
J = zeros(ne * Np*Np*dofspernode*dofspernode, 1);
val = zeros(ne * Np*Np*dofspernode*dofspernode, 1);

%temporary
time = 0;
dt = 1;
var = 0;

% loop over elements
for e=1:ne
    glb = grid_data.loc2glb(:,e)\';
    nodex = grid_data.allnodes(:,glb);
    [detJ, Jac]  = Utils.geometric_factors(refel, nodex);
    wdetj = refel.wg .* detJ;

    for di=1:dofspernode
        glbdof(((di-1)*Np + 1):(di*Np)) = (glb - 1).*dofspernode + di;
    end

    ind1 = repmat(glbdof,Np*dofspernode,1);
    ind2 = reshape(repmat(glbdof',Np*dofspernode,1),Np*Np*dofspernode*dofspernode,1);

    st = (e-1)*Np*Np*dofspernode*dofspernode+1;
    en = e*Np*Np*dofspernode*dofspernode;
    I(st:en) = ind1;
    J(st:en) = ind2;

    % Generated elemental computation ############################
"*code*"
    % End generated elemental computation ########################

    % handle boundary conditions
    for f=1:length(grid_data.element2face(:,e))
        fid = grid_data.element2face(f,e);
        bid = grid_data.facebid(fid);
        if bid > 0
            % boundary face
            for di=1:dofspernode
                bdrylocaldof = refel.face2local{f} + Np*(di-1);
                bdrylocal = refel.face2local{f};
                % zero those rows in element_matrix
                element_matrix(bdrylocaldof, :) = 0;
                if prob.bc_type{bid}(1) == 'D'
                    for j=1:length(bdrylocaldof)
                        element_matrix(bdrylocaldof(j), bdrylocaldof(j)) = 1;
                    end
                elseif prob.bc_type{bid}(1) == 'N'
                    normal = grid_data.facenormals(:,fid);
                    for j=1:length(bdrylocal)
"*Ddotn_part*"
                        element_matrix(bdrylocaldof(j), ((di-1)*Np+1):(di*Np)) = Ddotn;
                    end
                end
            end
        end
    end

    val(st:en) = element_matrix(:);
end
LHS = sparse(I,J,val,dof*dofspernode,dof*dofspernode);";

    println(file, content)
    println(file, "");
end

# This is the vector assembly loop.
# It requires code that was generated for this target.
function matlab_linear_file(code, var)
    file = add_generated_file("Linear.m", dir="src");
    # insert the code part into this skeleton
    content =
"
nnodes= size(grid_data.allnodes,2);
ne  = mesh_data.nel;
Np = refel.Np;
dofspernode = 3;
RHS = zeros(nnodes*dofspernode,1);
glbdof = zeros(Np*dofspernode,1);

%temporary
time = 0;
dt = 1;
var = 0;

% loop over elements
for e=1:ne
    glb = grid_data.loc2glb(:,e)\';
    nodex = grid_data.allnodes(:,glb);
    [detJ, Jac]  = Utils.geometric_factors(refel, nodex);
    wdetj = refel.wg .* detJ;

    for di=1:dofspernode
        glbdof(((di-1)*Np + 1):(di*Np)) = (glb - 1).*dofspernode + di;
    end

"*code*"

    RHS(glbdof) = element_vector;
end
";
    println(file, content);

    # boundary condition
    println(file, "
    for i=1:length(grid_data.bdry)
        bdrynode = grid_data.bdry{i};
        for di=1:dofspernode
            bdrydof = (bdrynode-1)*dofspernode + di;
            RHS(bdrydof) = prob.bc_func(di, i);
        end
    end");

end

# Nothing here yet. TODO: time stepper
function matlab_stepper_file()
    file = add_generated_file("Stepper.m", dir="src");
end

# Right now this just tries to plot
function matlab_output_file()
    file = add_generated_file("Output.m", dir="src");

    if config.dimension == 1
        content = "
gxy = grid_data.allnodes';

X = gxy(:,1);

for figi = 1:total_components
    figure(figi);
    plot(X, result(figi:dofspernode:length(result)));
end
"
    elseif config.dimension == 2
        content = "
gxy = grid_data.allnodes';

X = gxy(:,1);
Y = gxy(:,2);

DT = delaunay(gxy);

for figi = 1:total_components
    figure(figi);
    trisurf(triangulation(DT, X, Y, result(figi:dofspernode:length(result))), 'edgecolor', 'none')
    view(2);
end
"
    else
        content = "% figure output not ready for 3D."
    end

    println(file, content)
    println(file, "");
end

###########################################################################################################
# Symbolic to code generation
###########################################################################################################

# If needed, build derivative matrices
function matlabtarget_build_derivative_matrices(lorr, vors)
    code =
"
% Note on derivative matrices:
% RQn are vandermond matrices for the derivatives of the basis functions
% with Jacobian factors. They are made like this.
% |RQ1|   | rx sx tx || Qx |
% |RQ2| = | ry sy ty || Qy |
% |RQ3|   | rz sz tz || Qz |

"
    if config.dimension == 1
        if vors == "volume"
            code *= "RQ1 = diag(Jac.rx) * refel.Qr;\n";
            code *= "RD1 = diag(Jac.rx) * refel.Ddr;\n";
            code *= "TRQ1 = RQ1';\n"
        else
            # TODO see DG
        end

    elseif config.dimension == 2
        if vors == "volume"
            code *= "RQ1 = [diag(Jac.rx) diag(Jac.sx)] * [refel.Qr; refel.Qs];\n";
            code *= "RQ2 = [diag(Jac.ry) diag(Jac.sy)] * [refel.Qr; refel.Qs];\n";
            code *= "RD1 = [diag(Jac.rx) diag(Jac.sx)] * [refel.Ddr; refel.Dds];\n";
            code *= "RD2 = [diag(Jac.ry) diag(Jac.sy)] * [refel.Ddr; refel.Dds];\n";
            code *= "TRQ1 = RQ1';\n"
            code *= "TRQ2 = RQ2';\n"
        else
            # TODO see DG
        end

    elseif config.dimension == 3
        if vors == "volume"
            code *= "RQ1 = [diag(Jac.rx) diag(Jac.sx) diag(Jac.tx)] * [refel.Qr; refel.Qs; refel.Qt];\n";
            code *= "RQ2 = [diag(Jac.ry) diag(Jac.sy) diag(Jac.ty)] * [refel.Qr; refel.Qs; refel.Qt];\n";
            code *= "RQ3 = [diag(Jac.rz) diag(Jac.sz) diag(Jac.tz)] * [refel.Qr; refel.Qs; refel.Qt];\n";
            code *= "RD1 = [diag(Jac.rx) diag(Jac.sx) diag(Jac.tx)] * [refel.Ddr; refel.Dds; refel.Ddt];\n";
            code *= "RD2 = [diag(Jac.ry) diag(Jac.sy) diag(Jac.ty)] * [refel.Ddr; refel.Dds; refel.Ddt];\n";
            code *= "RD3 = [diag(Jac.rz) diag(Jac.sz) diag(Jac.tz)] * [refel.Ddr; refel.Dds; refel.Ddt];\n";
            code *= "TRQ1 = RQ1';\n"
            code *= "TRQ2 = RQ2';\n"
            code *= "TRQ3 = RQ3';\n"
        else
            # TODO see DG
        end
    end

    return code;
end

# Allocate, compute, or fetch all needed values
function matlabtarget_prepare_needed_values(entities, var, lorr, vors)
    code = "";
    for i=1:length(entities)
        cname = CodeGenerator.make_coef_name(entities[i]);
        if CodeGenerator.is_test_function(entities[i])
            # Assign it a transpose quadrature matrix
            if length(entities[i].derivs) > 0
                xyzchar = ["x","y","z"];
                for di=1:length(entities[i].derivs)
                    code *= cname * " = TRQ"*string(entities[i].derivs[di])*"; % d/d"*xyzchar[entities[i].derivs[di]]*" of test function\n";
                end
            else
                code *= cname * " = refel.Q'; % test function.\n";
            end
        elseif CodeGenerator.is_unknown_var(entities[i], var) && lorr == LHS
            if length(entities[i].derivs) > 0
                xyzchar = ["x","y","z"];
                for di=1:length(entities[i].derivs)
                    code *= cname * " = RQ"*string(entities[i].derivs[di])*"; % d/d"*xyzchar[entities[i].derivs[di]]*" of trial function\n";
                end
            else
                code *= cname * " = refel.Q; % trial function.\n";
            end
        else
            # Is coefficient(number or function) or variable(array)?
            (ctype, cval) = CodeGenerator.get_coef_val(entities[i]);
            if ctype == -1
                # It was a special symbol like dt
            elseif ctype == 0
                # It was a number, do nothing?
            elseif ctype == 1 # a constant wrapped in a coefficient
                # This generates something like: coef_k_i = 4;
                if length(entities[i].derivs) > 0
                    code *= cname * " = 0; % NOTE: derivative applied to constant coefficient = 0\n";
                else
                    code *= cname * " = " * string(cval) * ";\n";
                end

            elseif ctype == 2 # a coefficient function
                # This generates something like:
                ######################################
                # coef_n_i = zeros(refel.Np);
                # for coefi = 1:refel.Np
                #     coef_k_i[coefi] = func(x[1,coefi], x[2,coefi],x[3,coefi],time);
                # end
                ######################################
                cargs = "(nodex(coefi), 0, 0, time)";
                if config.dimension == 2
                    cargs = "(nodex(1, coefi), nodex(2, coefi), 0, time)";
                elseif config.dimension == 3
                    cargs = "(nodex(1, coefi), nodex(2, coefi), nodex(3, coefi), time)";
                end
                if vors == "volume"
                    code *= cname * " = zeros(refel.Np,1);\n";cname*" = "*genfunctions[cval].name*"(idx);\n";
                    code *= "for coefi = 1:refel.Np\n\t" * cname * "(coefi) = "*genfunctions[cval].name*"_fun" * cargs * ";\nend\n";
                    # Apply any needed derivative operators. Interpolate at quadrature points.
                    if length(entities[i].derivs) > 0
                        xyzchar = ["x","y","z"];
                        for di=1:length(entities[i].derivs)
                            code *= cname * " = RQ"*string(entities[i].derivs[di])*" * " * cname *
                                    "; % Apply d/d"*xyzchar[entities[i].derivs[di]]*" and interpolate at quadrature points.\n";
                        end
                    else
                        code *= cname * " = refel.Q * " * cname * "; % Interpolate at quadrature points.\n";
                    end
                else
                    #TODO surface
                end

            elseif ctype == 3 # a known variable value
                # This generates something like: coef_u_1 = copy((Femshop.variables[1]).values[1, glb])
                if vors == "volume"
                    code *= cname * " = variables("*string(cval)*")("*string(entities[i].index)*", glb);\n";
                    # Apply any needed derivative operators.
                    if length(entities[i].derivs) > 0
                        xyzchar = ["x","y","z"];
                        for di=1:length(entities[i].derivs)
                            code *= cname * " = RQ"*string(entities[i].derivs[di])*" * " * cname *
                                    "; % Apply d/d"*xyzchar[entities[i].derivs[di]]*"\n";
                        end
                    else
                        code *= cname * " = refel.Q * " * cname * "; % Interpolate at quadrature points.\n";
                    end
                else
                    #TODO surface
                end

            end
        end # if coefficient
    end # entity loop

    return code;
end

function matlabtarget_make_elemental_computation(terms, var, lorr, vors)
    # Here is where I make some assumption about the form of the expression.
    # Since it was expanded by the parser it should look like a series of terms: t1 + t2 + t3...
    # Where each term is multiplied by one test function component, and if LHS, involves one unknown component.
    # The submatrix modified by a term is determined by these, so go through the terms and divide them
    # into their submatrix expressions.
    # Each term will look something like
    # LHS: test_part * diagm(weight_part .* coef_part) * trial_part
    # RHS: test_part * (weight_part .* coef_part)

    # find some useful numbers
    dofsper = 0;
    offset_ind = [0];
    if typeof(var) <:Array
        offset_ind = zeros(Int, varcount);
        dofsper = length(var[1].symvar);
        for i=2:length(var)
            offset_ind[i] = dofsper;
            dofsper = dofsper + length(var[i].symvar);
        end
    else
        dofsper = length(var.symvar);
    end

    code = "";

    # Allocate the vector or matrix to be returned if needed
    if dofsper > 1
        if lorr == RHS
            code *= "element_vector = zeros(refel.Np * "*string(dofsper)*", 1); % Allocate the returned vector.\n"
        else
            code *= "element_matrix = zeros(refel.Np * "*string(dofsper)*", refel.Np * "*string(dofsper)*"); % Allocate the returned matrix.\n"
        end
    end

    # Separate the factors of each term into test, trial, coef and form the calculation
    if dofsper > 1
        # Submatrices or subvectors for each component
        if lorr == LHS
            submatrices = Array{String, 2}(undef, dofsper, dofsper);
        else # RHS
            submatrices = Array{String, 1}(undef, dofsper);
        end
        for smi=1:length(submatrices)
            submatrices[smi] = "";
        end

        if typeof(var) <: Array
            for vi=1:length(var) # variables
                # Process the terms for this variable
                for ci=1:length(terms[vi]) # components
                    for i=1:length(terms[vi][ci])
                        (term_result, test_ind, trial_ind) = matlabtarget_generate_term_calculation(terms[vi][ci][i], var, lorr);

                        # println(terms)
                        # println(terms[vi])
                        # println(terms[vi][ci])
                        # println(terms[vi][ci][i])
                        # println(term_result * " : "*string(test_ind)*", "*string(trial_ind))

                        # Find the appropriate submatrix for this term
                        submati = offset_ind[vi] + test_ind;
                        submatj = trial_ind;
                        if lorr == LHS
                            submat_ind = submati + dofsper * (submatj-1);
                        else
                            submat_ind = submati;
                        end

                        if length(submatrices[submat_ind]) > 1
                            submatrices[submat_ind] *= " + " * term_result;
                        else
                            submatrices[submat_ind] = term_result;
                        end
                    end
                end

            end # vi

        else # only one variable
            # Process the terms for this variable
            for ci=1:length(terms) # components
                for i=1:length(terms[ci])
                    (term_result, test_ind, trial_ind) = matlabtarget_generate_term_calculation(terms[ci][i], var, lorr);

                    # Find the appropriate submatrix for this term
                    if lorr == LHS
                        submat_ind = test_ind + dofsper * (trial_ind-1);
                    else
                        submat_ind = test_ind;
                    end

                    if length(submatrices[submat_ind]) > 1
                        submatrices[submat_ind] *= " + " * term_result;
                    else
                        submatrices[submat_ind] = term_result;
                    end
                end
            end

        end

        # Put the submatrices together into element_matrix or element_vector
        if lorr == LHS
            for emi=1:dofsper
                for emj=1:dofsper
                    if length(submatrices[emi, emj]) > 1
                        rangei = "("*string(emi-1)*"*refel.Np + 1):("*string(emi)*"*refel.Np)";
                        rangej = "("*string(emj-1)*"*refel.Np + 1):("*string(emj)*"*refel.Np)";
                        code *= "element_matrix("*rangei*", "*rangej*") = " * submatrices[emi,emj] * ";\n";
                    end
                end
            end
            #code *= "return element_matrix;\n"

        else # RHS
            for emi=1:dofsper
                if length(submatrices[emi]) > 1
                    rangei = "(("*string(emi-1)*")*refel.Np + 1):("*string(emi)*"*refel.Np)";
                    code *= "element_vector("*rangei*") = " * submatrices[emi] * ";\n";
                end
            end
        end
        #code *= "return element_vector;\n"

    else # one dof
        terms = terms[1];
        if lorr == LHS
            result = "zeros(refel.Np, refel.Np)";
        else
            result = "zeros(refel.Np,1)";
        end

        #process each term
        for i=1:length(terms)
            (term_result, test_ind, trial_ind) = matlabtarget_generate_term_calculation(terms[i], var, lorr);

            if i > 1
                result *= " + " * term_result;
            else
                result = term_result;
            end
        end
        if lorr == LHS
            code *= "element_matrix = " * result * ";\n";
        else
            code *= "element_vector = " * result * ";\n";
        end
        #code *= "return " * result * ";\n";
    end

    return code;
end

function matlabtarget_generate_term_calculation(term, var, lorr)
    result = "";

    if lorr == LHS
        (test_part, trial_part, coef_part, test_ind, trial_ind) = CodeGenerator.separate_factors(term, var);
        # LHS: test_part * diagm(weight_part .* coef_part) * trial_part
        if !(coef_part === nothing)
            result = string(CodeGenerator.replace_entities_with_symbols(test_part)) * " * diag(wdetj .* " *
                    string(CodeGenerator.replace_entities_with_symbols(coef_part)) * ") * " *
                    string(CodeGenerator.replace_entities_with_symbols(trial_part));
        else # no coef_part
            result = string(CodeGenerator.replace_entities_with_symbols(test_part)) * " * diag(wdetj) * " *
                    string(CodeGenerator.replace_entities_with_symbols(trial_part));
        end
    else
        (test_part, trial_part, coef_part, test_ind, trial_ind) = CodeGenerator.separate_factors(term);
        # RHS: test_part * (weight_part .* coef_part)
        if !(coef_part === nothing)
            result = string(CodeGenerator.replace_entities_with_symbols(test_part)) * " * (wdetj .* " *
                    string(CodeGenerator.replace_entities_with_symbols(coef_part)) * ")";
        else
            result = string(CodeGenerator.replace_entities_with_symbols(test_part)) * " * (wdetj)";
        end
    end

    return (result, test_ind, trial_ind);
end


text:
# Command: Switch to Window
"""
    window!(session::Session, handle::AbstractString)

The window handle associated with the current top-level browsing context.
"""
function window!(session::Session, handle::AbstractString)
    @unpack addr, id = session
    response = HTTP.post(
        "$addr/session/$id/window",
        [("Content-Type" => "application/json")],
        JSON3.write("handle" => handle),
    )
    @assert response.status == 200
    JSON3.read(response.body).value
end

ext: jl


text:
#****************************************************************************
#                     Molecular Dynamics Potentials (MDP)
#                            CESMIX-MIT Project
#
#  Contributing authors: Ngoc-Cuong Nguyen (cuongng@mit.edu, exapde@gmail.com)
#****************************************************************************

function writeapp(app,filename)

    nsize = zeros(100,1);
    nsize[1] = length(app.ndims[:]);
    nsize[2] = length(app.flag[:]);
    nsize[3] = length(app.bcs[:]);
    nsize[4] = length(app.pbc[:]);
    nsize[5] = length(app.boxoffset[:]);
    nsize[6] = length(app.atomnumbers[:]);
    nsize[7] = length(app.atommasses[:]);
    nsize[8] = length(app.atomcharges[:]);
    nsize[9] = length(app.simparam[:]);
    nsize[10] = length(app.solparam[:]);
    nsize[11] = length(app.eta[:]);
    nsize[12] = length(app.kappa[:]);
    nsize[13] = length(app.muml[:]);
    nsize[14] = length(app.mu1a[:]);
    nsize[15] = length(app.mu1b[:]);
    nsize[16] = length(app.mu2a[:]);
    nsize[17] = length(app.mu2b[:]);
    nsize[18] = length(app.mu2c[:]);
    nsize[19] = length(app.mu3a[:]);
    nsize[20] = length(app.mu3b[:]);
    nsize[21] = length(app.mu3c[:]);
    nsize[22] = length(app.mu4a[:]);
    nsize[23] = length(app.mu4b[:]);
    nsize[24] = length(app.pot1a[:]);
    nsize[25] = length(app.pot1b[:]);
    nsize[26] = length(app.pot2a[:]);
    nsize[27] = length(app.pot2b[:]);
    nsize[28] = length(app.pot2c[:]);
    nsize[29] = length(app.pot3a[:]);
    nsize[30] = length(app.pot3b[:]);
    nsize[31] = length(app.pot3c[:]);
    nsize[32] = length(app.pot4a[:]);
    nsize[33] = length(app.pot4b[:]);
    nsize[34] = length(app.rcutml);
    nsize[35] = length(app.rcut2a[:]);
    nsize[36] = length(app.rcut2b[:]);
    nsize[37] = length(app.rcut2c[:]);
    nsize[38] = length(app.rcut3a[:]);
    nsize[39] = length(app.rcut3b[:]);
    nsize[40] = length(app.rcut3c[:]);
    nsize[41] = length(app.rcut4a[:]);
    nsize[42] = length(app.rcut4b[:]);
    nsize[43] = length(app.rcutsqmax);
    nsize[44] = length(app.atom1b[:]);
    nsize[45] = length(app.atom2b[:]);
    nsize[46] = length(app.atom2c[:]);
    nsize[47] = length(app.atom3b[:]);
    nsize[48] = length(app.atom3c[:]);
    nsize[49] = length(app.atom4b[:]);
    nsize[51] = length(app.traininglist[:]);
    nsize[52] = length(app.validatelist[:]);
    nsize[53] = length(app.nveparam[:]);
    nsize[54] = length(app.nvtparam[:]);
    nsize[55] = length(app.snaparam[:]);
    nsize[56] = length(app.snapelemradius[:]);
    nsize[57] = length(app.snapelemweight[:]);
    nsize[58] = length(app.snapcoeff[:]);
    nsize[59] = length(app.createvelocity[:]);
    nsize[60] = length(app.setatomtypefraction[:]);

    #app.nsize = nsize;
    fileID = open(filename,"w");
    write(fileID,Float64(length(nsize[:])));
    write(fileID,Float64.(nsize[:]));
    write(fileID,Float64.(app.ndims[:]));
    write(fileID,Float64.(app.flag[:]));
    write(fileID,Float64.(app.bcs[:]));
    write(fileID,Float64.(app.pbc[:]));
    write(fileID,Float64.(app.boxoffset[:]));
    write(fileID,Float64.(app.atomnumbers[:]));
    write(fileID,Float64.(app.atommasses[:]));
    write(fileID,Float64.(app.atomcharges[:]));
    write(fileID,Float64.(app.simparam[:]));
    write(fileID,Float64.(app.solparam[:]));
    write(fileID,Float64.(app.eta[:]));
    write(fileID,Float64.(app.kappa[:]));
    write(fileID,Float64.(app.muml[:]));
    write(fileID,Float64.(app.mu1a[:]));
    write(fileID,Float64.(app.mu1b[:]));
    write(fileID,Float64.(app.mu2a[:]));
    write(fileID,Float64.(app.mu2b[:]));
    write(fileID,Float64.(app.mu2c[:]));
    write(fileID,Float64.(app.mu3a[:]));
    write(fileID,Float64.(app.mu3b[:]));
    write(fileID,Float64.(app.mu3c[:]));
    write(fileID,Float64.(app.mu4a[:]));
    write(fileID,Float64.(app.mu4b[:]));
    write(fileID,Float64.(app.pot1a[:]));
    write(fileID,Float64.(app.pot1b[:]));
    write(fileID,Float64.(app.pot2a[:]));
    write(fileID,Float64.(app.pot2b[:]));
    write(fileID,Float64.(app.pot2c[:]));
    write(fileID,Float64.(app.pot3a[:]));
    write(fileID,Float64.(app.pot3b[:]));
    write(fileID,Float64.(app.pot3c[:]));
    write(fileID,Float64.(app.pot4a[:]));
    write(fileID,Float64.(app.pot4b[:]));
    write(fileID,Float64.(app.rcutml^2));
    write(fileID,Float64.(app.rcut2a[:].^2));
    write(fileID,Float64.(app.rcut2b[:].^2));
    write(fileID,Float64.(app.rcut2c[:].^2));
    write(fileID,Float64.(app.rcut3a[:].^2));
    write(fileID,Float64.(app.rcut3b[:].^2));
    write(fileID,Float64.(app.rcut3c[:].^2));
    write(fileID,Float64.(app.rcut4a[:].^2));
    write(fileID,Float64.(app.rcut4b[:].^2));
    write(fileID,Float64.(app.rcutsqmax));
    write(fileID,Float64.(app.atom1b[:]));
    write(fileID,Float64.(app.atom2b[:]));
    write(fileID,Float64.(app.atom2c[:]));
    write(fileID,Float64.(app.atom3b[:]));
    write(fileID,Float64.(app.atom3c[:]));
    write(fileID,Float64.(app.atom4b[:]));
    write(fileID,Float64.(app.traininglist[:]));
    write(fileID,Float64.(app.validatelist[:]));
    write(fileID,Float64.(app.nveparam[:]));
    write(fileID,Float64.(app.nvtparam[:]));
    write(fileID,Float64.(app.snaparam[:]));
    write(fileID,Float64.(app.snapelemradius[:]));
    write(fileID,Float64.(app.snapelemweight[:]));
    write(fileID,Float64.(app.snapcoeff[:]));
    write(fileID,Float64.(app.createvelocity[:]));
    write(fileID,Float64.(app.setatomtypefraction[:]));

    close(fileID);

end

max_stars_repo_name: cesmix-mit/MDP

max_issues_repo_name: cesmix-mit/MDP

max_forks_repo_name: cesmix-mit/MDP


text:
export checkDerivative, getRandomTestDirection

function getRandomTestDirection(x0::Float64)
	return randn()
end
function getRandomTestDirection(x0::Complex128)
	return randn()+1im*randn()
end
function getRandomTestDirection(x0::Array{T}) where {T<:AbstractFloat}
	return randn(T,size(x0))
end
function getRandomTestDirection(x0::Array{Complex128})
	return randn(size(x0))+1im*randn(size(x0))
end

function checkDerivative(f::Function,df::Function,x0;kwargs...)
	function testFun(x,v=[])
		if !(isempty(v))
			return f(x), df(x)*v
		else
			return f(x)
		end
	end
	return checkDerivative(testFun,x0;kwargs...)
end

function checkDerivative(f::Function,x0::Array{T};out::Bool=true,tol::Float64=1.9,nSuccess::Int=4,v=getRandomTestDirection(x0),nTrials=20) where T
# checkDerivative(f::Function,x0;out::Bool=true,tol::Float64=1.9,nSuccess::Int=3)
	if out
		println(@sprintf("%9s\t%9s\t%9s\t%9s\t%9s\t%5s","h","E0","E1","O1","O2","OK?"))
	end

	f0,dvf  = f(x0,v)
	nf0     = norm(f0)
	#dvf    = real(dvf)
	Error   = zeros(nTrials,2)
	Order   = zeros(nTrials,2)
	Success = zeros(nTrials)
	for j=1:nTrials
		hj = convert(T,2.0^(-j))
		ft = f(x0+hj*v)            # function value
		Error[j,1] = norm(f0-ft)/nf0          # Error TaylorPoly 0
		Error[j,2] = norm(f0 .+hj*dvf .- ft)/nf0 # Error TaylorPoly 1
		if j>1
			Order[j,:] = log2.(Error[j-1,:]./Error[j,:]);
		end
		if (Order[j,2]>tol) || (Error[j,1]/Error[j,2] > 100); Success[j]=1; end
		if out
			println(@sprintf("%1.3e\t%1.3e\t%1.3e\t%1.3e\t%1.3e\t%5d",
							hj, Error[j,1],Error[j,2], Order[j,1],Order[j,2],Success[j]))
		end
	end
	pass = sum(Success) > nSuccess
	return  pass,Error,Order
end


text:
#=
   multiplication by known constant
=#

# sigdigits = precision(Float64)-2
function find_consts_for_mulbyconst(c::BigFloat)
    b = round(c, sigdigits=51, base=2)
    chi = Double64(b)
    clo = Double64(c - chi)
    return chi, clo
end

function find_consts_for_divbyconst(c::BigFloat)
    return find_consts_for_mulbyconst(inv(c))
end

function mulbyconst(x::Double64, chi::Double64, clo::Double64)
    lo = clo * x
    hi = chi * x
    return hi + lo
end

divbyconst(x::Double64, chi::Double64, clo::Double64) = mulbyconst(x, chi, clo)


text:
module MelissasModule
import Trebuchet as Trebuchets
using ForwardDiff: gradient

export aim, shoot_distance, Trebuchet, Environment

mutable struct Trebuchet <: AbstractVector{Float64}
  counterweight::Float64
  release_angle::Float64
end
Base.copy(trebuchet::Trebuchet) = Trebuchet(trebuchet.counterweight, trebuchet.release_angle)
Base.size(trebuchet::Trebuchet) = tuple(2)
Base.getindex(trebuchet::Trebuchet, i::Int) = getfield(trebuchet, i)
function Base.setindex!(trebuchet::Trebuchet, v, i::Int)
    if i === 1
        trebuchet.counterweight = v
    elseif i === 2
        trebuchet.release_angle = v
    else
        error("Trebuchet only accepts indices 1 and 2, yours is $i")
    end
end

struct Environment
  wind::Float64
  target_distance::Float64
end

function shoot_distance(windspeed, angle, weight)
    Trebuchets.shoot(windspeed, angle, weight)[2]
end
function shoot_distance(args...)
    Trebuchets.shoot(args...)[2]
end
function shoot_distance(trebuchet::Trebuchet, env::Environment)
    shoot_distance(env.wind, trebuchet.release_angle, trebuchet.counterweight)
end

function aim(trebuchet::Trebuchet, environment::Environment; ε = 1e-1, η = 0.05)
    # @show ε
    better_trebuchet = copy(trebuchet)
    hit = x -> (shoot_distance([environment.wind, x[2], x[1]]) - environment.target_distance)
    while abs(hit(better_trebuchet)) > ε
        grad = gradient(hit, better_trebuchet)
        better_trebuchet -= η * grad
    end
    return Trebuchet(better_trebuchet[1], better_trebuchet[2])
end
end # MelissasModule

max_stars_repo_name: lucaferranti/julia-novice

max_issues_repo_name: lucaferranti/julia-novice

max_forks_repo_name: lucaferranti/julia-novice


text:
### FAR FROM FINISHED

module sample_

using Printf
using IUP

export
    sample

# forward declaration to workaround '@cfunction'
function action1_cb end
function action2_cb end
function action3_cb end
function copydata_cb end
function valuechanged_cb end
function k_any end

#using IProfile
#@iprofile begin

# Probably a bug in IProfile because when I try to use it, than Julia errors with
#ERROR: function is not yet c-callable
# in set_callbacks at no file:247
# in SampleTest at no file:63

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

    IupSetGlobal("SINGLEINSTANCE", "Iup Sample");
    if (IupGetGlobal("SINGLEINSTANCE") == C_NULL)
        IupClose()
        return
    end

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

# ------------------------------------------------------------------------------------------
function SampleTest()

    #img = IupImage(32,32, img_bits1)
    #IupSetHandle("img1", img)
    # IupSetAttribute(img, "0", "0 0 0")
    # IupSetAttribute(img, "1", "BGCOLOR")
    # IupSetAttribute(img, "2", "255 0 0")

    img = load_image_Tecgraf()
    IupSetHandle("img1", img)

    img = IupImage(32,32, pointer(img_bits2()))
    IupSetHandle("img2", img)
    IupSetAttribute(img, "0", "0 0 0")
    IupSetAttribute(img, "1", "0 255 0")
    IupSetAttribute(img, "2", "BGCOLOR")
    IupSetAttribute(img, "3", "255 0 0")

    mnu = IupMenu(
        IupSubmenu("IupSubmenu 1",
        IupMenu(
            IupSetAttributes(IupItem("IupItem 1 Checked"), "VALUE=ON"),
            IupSeparator(),
            IupSetAttributes(IupItem("IupItem 2 Disabled"), "ACTIVE=NO"),
        )),
        IupItem("IupItem 3"),
        IupItem("IupItem 4"),
        )
    IupSetHandle("mnu",mnu)

    _frm_1 = IupFrame(
        IupVbox(
            set_callbacks(IupSetAttributes(IupButton("Button Text"), "PADDING=5x5")),
            IupSetCallbacks(set_callbacks(IupSetAttributes(IupButton("Text"),"IMAGE=img1, PADDING=5x5")),
                "ACTION",
                @cfunction(action1_cb, Int, (Ptr{Ihandle},))
                ),
            IupSetCallbacks(set_callbacks(IupSetAttributes(IupButton(""), "IMAGE=img1")),
                "ACTION",
                @cfunction(action2_cb, Int, (Ptr{Ihandle},))),
            IupSetCallbacks(set_callbacks(IupSetAttributes(IupButton(""), "IMAGE=img1,IMPRESS=img2")),
                "ACTION",
                @cfunction(action3_cb, Int, (Ptr{Ihandle},))),
            IupSetCallbacks(set_callbacks(IupSetAttributes(IupButton(""), "BGCOLOR=\"255 0 128\", SIZE=20x10")),
                "ACTION",
                @cfunction(action3_cb, Int, (Ptr{Ihandle},)))
        ))
    IupSetAttribute(_frm_1,"TITLE","IupButton")

    _frm_2 = IupFrame(
        IupVbox(
            IupLabel("Label Text"),
            IupSetAttributes(IupLabel(""), "SEPARATOR=HORIZONTAL, MAXSIZE=150, NAME=SAMP_SEP"),
            IupSetAttributes(IupLabel(""), "IMAGE=img1")
        ));
    IupSetAttribute(_frm_2,"TITLE","IupLabel")

    _frm_3 = IupFrame(
        IupVbox(
            set_callbacks(IupSetAttributes(IupToggle("Toggle Text"), "VALUE=ON")),
            set_callbacks(IupSetAttributes(IupToggle(""), "VALUE=ON,IMAGE=img1,IMPRESS=img2")),
            set_callbacks(IupSetAttributes(IupToggle(""), "VALUE=ON,IMAGE=img1")),
            IupSetAttributes(IupFrame(IupRadio(IupVbox(
                set_callbacks(IupToggle("Toggle Text")),
                set_callbacks(IupToggle("Toggle Text"))
                ))), "TITLE=IupRadio")
            ))
    IupSetAttribute(_frm_3,"TITLE","IupToggle")

    _text_1 = IupText("");
    IupSetAttribute(_text_1,"VALUE","Single Line Text")
    IupSetAttribute(_text_1,"SIZE","80x");

    _ml_1 = IupMultiLine(C_NULL);
    IupSetAttribute(_ml_1,"VALUE","Multiline Text\nSecond Line\nThird Line")
    IupSetAttribute(_ml_1,"EXPAND","YES")
    IupSetAttribute(_ml_1,"SIZE","80x40")

    _frm_4 = IupFrame(IupVbox(
        set_callbacks(_text_1),
        set_callbacks(_ml_1)
        ));
    IupSetAttribute(_frm_4,"TITLE","IupText")

    _list_1 = IupList( C_NULL)
    #IupSetAttribute(_list_1,"EXPAND","YES")
    IupSetAttribute(_list_1,"VALUE","1")
    IupSetAttribute(_list_1,"1","Item 1 Text")
    IupSetAttribute(_list_1,"2","Item 2 Text")
    IupSetAttribute(_list_1,"3","Item 3 Text")
    IupSetAttribute(_list_1,"TIP","List 1")

    _list_2 = IupList(C_NULL)
    IupSetAttribute(_list_2,"DROPDOWN","YES")
    #IupSetAttribute(_list_2,"EXPAND","YES")
    IupSetAttribute(_list_2,"VALUE","2")
    IupSetAttribute(_list_2,"1","Item 1 Text")
    IupSetAttribute(_list_2,"2","Item 2 Text")
    IupSetAttribute(_list_2,"3","Item 3 Text")
    IupSetAttribute(_list_2,"TIP","List 2")

    _list_3 = IupList(C_NULL)
    IupSetAttribute(_list_3,"EDITBOX","YES")
    #IupSetAttribute(_list_3,"EXPAND","YES")
    IupSetAttribute(_list_3,"VALUE","3")
    IupSetAttribute(_list_3,"1","Item 1 Text")
    IupSetAttribute(_list_3,"2","Item 2 Text")
    IupSetAttribute(_list_3,"3","Item 3 Text")
    IupSetAttribute(_list_3,"TIP","List 3")

    _frm_5 =  IupFrame(IupVbox(
        set_callbacks(_list_1),
        set_callbacks(_list_2),
        set_callbacks(_list_3)
        ));
    IupSetAttribute(_frm_5,"TITLE","IupList")

    _hbox_1 = IupHbox(_frm_1,_frm_2,_frm_3,_frm_4,_frm_5)

    val = IupVal(C_NULL)
    set_callbacks(val)

    pbar = IupProgressBar()
    IupSetAttribute(pbar, "VALUE", "0.5")
    set_callbacks(pbar)

    tabs = IupTabs(IupVbox(IupLabel("")), IupVbox(IupFill()), IupVbox(IupFill()), C_NULL)
    IupSetAttribute(tabs,"TABTITLE0","Tab Title 0")
    IupSetAttribute(tabs,"TABTITLE1","Tab Title 1")
    IupSetAttributeHandle(tabs,"TABIMAGE1", load_image_LogoTecgraf())
    IupSetAttribute(tabs,"TABTITLE2","Tab Title 2")
    IupSetAttribute(tabs,"RASTERSIZE","300x50")
    #IupSetAttribute(tabs,"PADDING","5x5");
    set_callbacks(tabs)

    tree = IupTree();
    IupSetAttribute(tree, "SHOWRENAME",   "YES")
    IupSetAttribute(tree,"RASTERSIZE","100x150")
    set_callbacks(tree);

    _cnv_1 = IupCanvas()
    IupSetAttribute(_cnv_1,"BGCOLOR","128 255 0")
    IupSetAttribute(_cnv_1,"SCROLLBAR","YES")
    IupSetAttribute(_cnv_1,"EXPAND","HORIZONTAL")
    IupSetAttribute(_cnv_1,"RASTERSIZE","x100")
    #IupSetAttribute(_cnv_1,"CANFOCUS","NO")
    set_callbacks(_cnv_1)

    _vbox_1 = IupVbox(
        _hbox_1,
        IupHbox(IupSetAttributes(IupFrame(IupHbox(val)),  "TITLE=IupVal"),
                IupSetAttributes(IupFrame(IupHbox(pbar)), "TITLE=IupProgressBar"),
                IupSetAttributes(IupFrame(IupHbox(tabs)), "TITLE=IupTabs")
        ),
        IupHbox(IupSetAttributes(IupFrame(IupHbox(_cnv_1)), "TITLE=IupCanvas"),
                IupSetAttributes(IupFrame(IupHbox(tree)), "TITLE=IupTree")
        )
    )
    IupSetAttribute(_vbox_1,"MARGIN","5x5");
    IupSetAttribute(_vbox_1,"GAP","5");

    dlg = IupDialog(_vbox_1);
    IupSetHandle("dlg",dlg);
    IupSetAttribute(dlg,"MENU","mnu");
    IupSetAttribute(dlg,"TITLE","IupDialog Title");
    #IupSetAttribute(dlg,"COMPOSITED","YES");   /* Windows Only */
    #IupSetAttribute(dlg, "OPACITY", "192");

    #IupSetAttribute(dlg, "BGCOLOR", "173 177 194");  // Motif BGCOLOR for documentation
    #IupSetAttribute(_vbox_1, "BGCOLOR", "92 92 255");
    #IupSetAttribute(dlg, "BGCOLOR", "92 92 255");
    #IupSetAttribute(dlg, "BACKGROUND", "200 10 80");

    #IupSetGlobal("DLGBGCOLOR", "92 92 255");
    #IupSetGlobal("TXTFGCOLOR", "255 92 92");
    #IupSetGlobal("TXTBGCOLOR", "92 92 255");

    #IupSetAttribute(dlg, "FONT", "Helvetica, 24")
    #IupSetAttribute(dlg, "FONT", "-*-helvetica-*-r-*-*-18-*-*-*-*-*-*-*")
    #IupSetAttribute(box, "FGCOLOR", "255 0 0")
    #IupSetAttribute(dlg,"RASTERSIZE","1000x800")

    IupSetCallback(dlg, "COPYDATA_CB", @cfunction(copydata_cb, Int, (Ptr{Ihandle}, Ptr{UInt8}, Int)))

    #IupSetGlobal("INPUTCALLBACKS", "Yes");
    #IupSetFunction("GLOBALKEYPRESS_CB", (Icallback)globalkeypress_cb);
    #IupSetFunction("GLOBALMOTION_CB", (Icallback)globalmotion_cb);
    #IupSetFunction("GLOBALBUTTON_CB", (Icallback)globalbutton_cb);
    #IupSetFunction("GLOBALWHEEL_CB", (Icallback)globalwheel_cb);

    IupMap(dlg)

    IupSetAttribute(tree, "TITLE0",       "Figures")
    IupSetAttribute(tree, "ADDLEAF0",     "Other")         # new id=1
    IupSetAttribute(tree, "ADDBRANCH1",   "triangle")      # new id=2
    IupSetAttribute(tree, "ADDLEAF2",     "equilateral")
    IupSetAttribute(tree, "ADDLEAF3",     "isoceles")
    IupSetAttribute(tree, "ADDLEAF4",     "scalenus")

    IupShow(dlg)

    # IupSetAttribute(dlg,"RASTERSIZE", C_NULL);
end

function copydata_cb(ih::Ptr{Ihandle}, value::Ptr{UInt8}, size::Int)
    @printf("COPYDATA(%s, %d)\n", unsafe_string(value), size)
    return IUP_DEFAULT
end

function set_callbacks(ih::Ptr{Ihandle})
    IupSetCallback(ih, "VALUECHANGED_CB", @cfunction(valuechanged_cb, Int, (Ptr{Ihandle},)))

    #IupSetCallback(ih, "GETFOCUS_CB", (Icallback)getfocus_cb);
    #IupSetCallback(ih, "KILLFOCUS_CB", (Icallback)killfocus_cb);

    #IupSetCallback(ih, "ENTERWINDOW_CB", (Icallback)enterwindow_cb);
    #IupSetCallback(ih, "LEAVEWINDOW_CB", (Icallback)leavewindow_cb);

    IupSetCallback(ih, "K_ANY", @cfunction(k_any, Int, (Ptr{Ihandle}, Int)))
    #IupSetCallback(ih, "HELP_CB", (Icallback)help_cb)

    return ih
end

function action1_cb(ih::Ptr{Ihandle})
    #IupSetAttribute(IupGetDialog(ih), "BACKGROUND", "255 128 128");
    show_menu(ih)
    return IUP_DEFAULT
end

function action2_cb(ih::Ptr{Ihandle})
    IupSetAttribute(IupGetDialog(ih), "BGCOLOR", "0 128 0")
    return IUP_DEFAULT
end

function action3_cb(ih::Ptr{Ihandle})
    @printf("ACTION3\n")
    #IupSetAttribute(IupGetChild(IupGetDialog(ih), 0), "BGCOLOR", "128 0 0");
    return IUP_DEFAULT
end

function valuechanged_cb(ih::Ptr{Ihandle})
    @printf("VALUECHANGED_CB(%s)=%s\n", unsafe_string(IupGetClassName(ih)),
        unsafe_string(IupGetAttribute(ih, "VALUE")))
    return IUP_DEFAULT
end

function k_any(ih::Ptr{Ihandle}, c::Int)
    if (IUP.iup_isprint(c))
        @printf("K_ANY(%s, %d = %s \'%c\')\n", IupGetClassName(ih), c, IUP.iupKeyCodeToName(c), Char(c))
    else
        @printf("K_ANY(%s, %d = %s)\n", IupGetClassName(ih), c, IUP.iupKeyCodeToName(c))
    end
    if (c == IUP.K_r)
        IupRecordInput("inputtest.iup", IUP_RECTEXT); return IUP_IGNORE        #IUP_RECBINARY, IUP_RECTEXT
    end
    if (c == IUP.K_s)
        IupRecordInput(NULL, 0); IupPlayInput(NULL); return IUP_IGNORE
    end
    if (c == IUP.K_p)
        IupPlayInput("inputtest.iup"); return IUP_IGNORE
    end
    return IUP.IUP_CONTINUE
end

function help_cb(ih::Ptr{Ihandle})
    @printf("HELP_CB(%s)\n", unsafe_string(IupGetClassName(ih)))
    return IUP_DEFAULT
end

function getfocus_cb(ih::Ptr{Ihandle})
    @printf("GETFOCUS_CB(%s)\n", unsafe_string(IupGetClassName(ih)))
    return IUP_DEFAULT
end

function killfocus_cb(ih::Ptr{Ihandle})
    @printf("KILLFOCUS_CB(%s)\n", unsafe_string(IupGetClassName(ih)))
    return IUP_DEFAULT
end

function leavewindow_cb(ih::Ptr{Ihandle})
    @printf("LEAVEWINDOW_CB(%s)\n", unsafe_string(IupGetClassName(ih)))
    return IUP_DEFAULT
end

function enterwindow_cb(ih::Ptr{Ihandle})
    @printf("ENTERWINDOW_CB(%s)\n", unsafe_string(IupGetClassName(ih)))
    return IUP_DEFAULT
end

function show_menu(ih::Ptr{Ihandle})
    menu_file = IupMenu(
        IupSetAttributes(IupItem("Item with Image", "item_cb"), "IMAGE=image_tec"),
        IupSetAttributes(IupItem("Toggle using VALUE"), "VALUE=ON, KEY=K_V"),
        IupSetAttributes(IupItem("Auto &Toggle", "item_cb"), "AUTOTOGGLE=YES, VALUE=OFF, IMAGE=image_test, IMPRESS=image_test_pressed"),
        IupSeparator(),
        IupItem("E&xit (Close)")
        )
    menu = IupMenu(
        IupSetAttributes(IupSubmenu("Submenu", menu_file), "KEY=K_S, IMAGE=image_tec"),
        IupItem("Item", "item_cb"),
        IupSetAttributes(IupItem("Item", "item_cb"), "VALUE=ON"),
        IupSetAttributes(IupItem("Item", "item_cb"), "KEY=K_I, IMAGE=image_tec")
        )

    x = IupGetInt(ih, "X")
    y = IupGetInt(ih, "Y") + IupGetInt2(ih, "RASTERSIZE")

    IupPopup(menu, x, y)
    IupDestroy(menu)
end

function load_image_Tecgraf()
    imgdata = UInt8.([
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 95, 108, 1, 90, 100, 117, 99, 123, 138, 166, 126, 137, 152, 181, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 105, 123, 147, 122, 137, 165, 255, 136, 152, 183, 255, 132, 149, 179, 250, 133, 149, 178, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 100, 115, 43, 111, 125, 150, 253, 140, 158, 190, 255, 135, 151, 182, 255, 132, 149, 179, 255, 131, 147, 177, 217, 153, 164, 188, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 113, 134, 148, 134, 151, 182, 255, 137, 154, 185, 255, 115, 129, 154, 252, 114, 128, 155, 255, 130, 146, 175, 255, 132, 147, 175, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 158, 159, 162, 3, 108, 121, 145, 230, 144, 162, 195, 255, 137, 154, 185, 197, 74, 79, 86, 45, 41, 46, 55, 246, 120, 134, 162, 255, 129, 145, 174, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 101, 113, 48, 124, 139, 167, 255, 144, 161, 194, 255, 138, 155, 186, 67, 0, 0, 0, 0, 49, 54, 62, 150, 87, 98, 118, 255, 128, 144, 173, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 113, 132, 105, 137, 154, 185, 255, 139, 156, 188, 231, 143, 159, 187, 3, 0, 0, 0, 0, 64, 68, 76, 61, 70, 79, 95, 255, 127, 143, 172, 254, 134, 149, 175, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 121, 142, 153, 141, 159, 191, 255, 139, 156, 188, 164, 0, 0, 0, 0, 0, 0, 0, 0, 79, 82, 87, 3, 69, 77, 92, 241, 122, 137, 165, 255, 127, 142, 170, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 122, 146, 191, 145, 163, 196, 255, 139, 156, 188, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 86, 101, 190, 115, 129, 156, 255, 126, 141, 170, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 125, 149, 227, 150, 168, 201, 255, 141, 157, 188, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 91, 107, 144, 113, 127, 153, 255, 125, 140, 169, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 163, 165, 167, 2, 112, 125, 150, 252, 155, 173, 203, 255, 143, 159, 189, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 94, 110, 109, 114, 128, 155, 255, 125, 140, 168, 175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 167, 181, 1, 120, 130, 149, 33, 48, 53, 59, 69, 43, 46, 52, 100, 50, 54, 59, 137, 116, 130, 156, 255, 155, 171, 201, 255, 105, 118, 142, 155, 104, 117, 141, 151, 105, 118, 141, 151, 105, 118, 142, 151, 101, 113, 136, 185, 111, 124, 150, 255, 116, 130, 156, 220, 112, 125, 148, 95, 115, 127, 150, 67, 123, 134, 156, 33, 168, 176, 190, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 119, 129, 147, 5, 109, 121, 142, 71, 106, 118, 140, 140, 105, 117, 140, 197, 107, 120, 144, 242, 120, 135, 162, 255, 123, 137, 163, 255, 44, 49, 58, 255, 28, 32, 39, 255, 125, 139, 164, 255, 150, 167, 197, 255, 138, 155, 186, 255, 131, 148, 178, 255, 125, 141, 170, 255, 119, 134, 162, 255, 114, 128, 154, 255, 108, 122, 147, 255, 104, 117, 141, 255, 102, 115, 138, 255, 103, 116, 139, 255, 107, 120, 145, 255, 111, 124, 149, 245, 113, 126, 151, 200, 113, 127, 152, 140, 116, 129, 154, 71, 122, 135, 158, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 118, 128, 145, 14, 106, 118, 140, 130, 104, 116, 139, 234, 105, 118, 142, 255, 128, 144, 173, 255, 147, 165, 199, 255, 157, 177, 213, 255, 150, 168, 202, 255, 140, 156, 187, 229, 41, 45, 52, 196, 39, 43, 51, 183, 130, 143, 168, 255, 144, 161, 192, 233, 109, 122, 145, 109, 105, 116, 138, 109, 99, 110, 130, 109, 92, 103, 123, 109, 91, 100, 117, 145, 97, 109, 131, 255, 95, 106, 128, 248, 74, 83, 97, 193, 64, 72, 85, 227, 56, 63, 75, 255, 55, 62, 75, 255, 65, 73, 88, 255, 90, 101, 121, 255, 111, 125, 150, 255, 114, 128, 154, 236, 116, 129, 155, 130, 127, 140, 165, 16, 0, 0, 0, 0,
    95, 101, 113, 22, 103, 115, 137, 220, 103, 116, 140, 255, 110, 123, 148, 255, 146, 165, 198, 255, 147, 165, 197, 232, 142, 158, 188, 147, 131, 144, 169, 78, 115, 123, 139, 20, 0, 0, 0, 0, 0, 0, 0, 0, 91, 97, 108, 68, 128, 142, 167, 255, 144, 162, 193, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 100, 107, 31, 120, 135, 163, 255, 133, 150, 180, 231, 0, 0, 0, 0, 0, 0, 0, 0, 86, 89, 93, 20, 50, 54, 61, 73, 37, 40, 46, 141, 33, 36, 42, 230, 46, 52, 63, 255, 107, 120, 144, 255, 116, 130, 157, 255, 118, 133, 159, 223, 132, 147, 174, 24,
    76, 83, 95, 114, 104, 117, 140, 255, 105, 117, 141, 255, 118, 133, 160, 253, 139, 155, 184, 116, 134, 143, 161, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 100, 110, 74, 122, 137, 163, 255, 143, 160, 191, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 114, 120, 31, 123, 138, 166, 255, 136, 153, 183, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 93, 97, 5, 42, 45, 51, 111, 86, 97, 117, 253, 118, 133, 160, 255, 119, 133, 161, 255, 133, 149, 180, 116,
    46, 50, 56, 109, 67, 76, 91, 255, 105, 118, 142, 255, 107, 120, 145, 254, 112, 125, 149, 131, 127, 139, 161, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 98, 109, 74, 116, 130, 156, 255, 142, 159, 190, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 115, 122, 31, 128, 143, 172, 255, 141, 157, 185, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 137, 163, 7, 122, 136, 162, 122, 120, 135, 162, 254, 121, 136, 164, 255, 136, 152, 184, 255, 126, 141, 168, 116,
    71, 74, 79, 17, 31, 35, 41, 206, 42, 47, 57, 255, 77, 87, 105, 255, 103, 116, 140, 255, 110, 124, 149, 239, 112, 125, 150, 157, 115, 128, 153, 89, 122, 134, 158, 30, 147, 158, 177, 2, 0, 0, 0, 0, 81, 87, 96, 65, 109, 123, 148, 255, 141, 158, 190, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 103, 112, 31, 135, 151, 180, 255, 141, 156, 183, 231, 0, 0, 0, 0, 153, 164, 183, 1, 134, 147, 171, 30, 124, 138, 165, 84, 123, 138, 165, 154, 122, 137, 164, 235, 127, 143, 172, 255, 140, 157, 189, 255, 144, 162, 195, 255, 129, 144, 172, 218, 126, 138, 161, 22,
    0, 0, 0, 0, 64, 68, 73, 7, 39, 43, 49, 118, 32, 36, 42, 225, 30, 35, 42, 255, 50, 57, 68, 255, 72, 81, 97, 255, 91, 102, 123, 255, 105, 118, 142, 255, 113, 127, 152, 240, 115, 129, 155, 204, 111, 124, 149, 196, 111, 125, 150, 255, 126, 141, 170, 234, 119, 133, 159, 120, 120, 134, 160, 116, 121, 135, 161, 117, 121, 135, 162, 119, 116, 130, 155, 152, 127, 142, 170, 255, 125, 140, 168, 248, 123, 138, 166, 199, 130, 145, 173, 235, 140, 155, 183, 255, 143, 160, 190, 255, 143, 161, 193, 255, 147, 165, 199, 255, 145, 164, 197, 255, 132, 148, 177, 230, 127, 140, 166, 126, 124, 134, 151, 12, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 141, 144, 3, 55, 58, 63, 58, 37, 40, 46, 126, 34, 38, 44, 184, 34, 38, 44, 235, 35, 39, 47, 254, 49, 55, 66, 255, 64, 72, 87, 255, 77, 87, 104, 255, 88, 98, 118, 255, 96, 108, 130, 255, 103, 116, 139, 255, 108, 122, 147, 255, 113, 127, 153, 255, 118, 133, 160, 255, 124, 140, 168, 255, 133, 148, 176, 255, 141, 156, 183, 255, 146, 161, 187, 255, 144, 159, 186, 255, 131, 146, 174, 254, 127, 141, 168, 237, 126, 141, 168, 188, 123, 137, 162, 131, 112, 123, 143, 61, 128, 132, 140, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 94, 98, 19, 64, 68, 73, 56, 53, 57, 65, 82, 62, 67, 76, 116, 66, 74, 89, 255, 95, 107, 129, 255, 80, 88, 103, 155, 81, 90, 105, 151, 86, 95, 112, 151, 95, 104, 122, 151, 98, 109, 128, 180, 124, 139, 166, 255, 109, 122, 146, 218, 100, 110, 128, 84, 96, 104, 118, 56, 105, 109, 117, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 174, 176, 2, 74, 83, 98, 252, 131, 147, 178, 255, 140, 155, 184, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 134, 157, 114, 151, 169, 203, 255, 123, 138, 165, 174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 76, 90, 224, 122, 137, 165, 255, 136, 152, 182, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, 139, 165, 147, 146, 164, 198, 255, 122, 137, 165, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 69, 81, 191, 110, 124, 149, 255, 134, 151, 181, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 143, 170, 193, 142, 160, 192, 255, 122, 137, 164, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 63, 74, 150, 94, 105, 127, 255, 133, 149, 179, 166, 0, 0, 0, 0, 0, 0, 0, 0, 115, 119, 128, 5, 130, 145, 174, 242, 137, 154, 186, 255, 125, 139, 166, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 58, 66, 102, 72, 81, 97, 255, 132, 148, 178, 236, 148, 161, 187, 5, 0, 0, 0, 0, 110, 121, 140, 64, 140, 157, 189, 255, 127, 142, 171, 254, 131, 144, 169, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 65, 71, 43, 47, 52, 63, 255, 127, 143, 172, 255, 132, 148, 177, 75, 0, 0, 0, 0, 121, 134, 158, 160, 139, 156, 188, 255, 123, 138, 165, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 156, 158, 1, 36, 39, 46, 227, 106, 119, 143, 255, 130, 145, 175, 203, 114, 125, 147, 51, 123, 138, 166, 247, 131, 147, 177, 255, 123, 138, 165, 151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 41, 47, 143, 68, 77, 93, 255, 128, 144, 174, 255, 126, 141, 170, 252, 129, 145, 174, 255, 123, 138, 166, 255, 127, 141, 167, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 68, 73, 40, 34, 38, 46, 250, 117, 131, 158, 255, 126, 142, 171, 255, 124, 140, 168, 255, 125, 139, 166, 214, 140, 152, 172, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 44, 50, 134, 58, 66, 79, 255, 123, 138, 166, 255, 123, 138, 166, 250, 127, 140, 165, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 156, 158, 1, 46, 50, 55, 83, 82, 89, 102, 123, 106, 116, 136, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    ])

    image = IupImageRGBA(32, 32, pointer(imgdata))
    return image
end

function load_image_LogoTecgraf()
    imgdata = UInt8.([
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, 120, 143, 125, 132, 148, 178, 173, 133, 149, 178, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 110, 130, 48, 130, 147, 177, 254, 124, 139, 167, 254, 131, 147, 176, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 128, 153, 134, 142, 159, 191, 194, 47, 52, 61, 110, 114, 128, 154, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 143, 172, 192, 140, 156, 188, 99, 65, 69, 76, 16, 97, 109, 131, 251, 129, 144, 172, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 147, 175, 232, 140, 157, 188, 43, 0, 0, 0, 0, 100, 112, 134, 211, 126, 141, 169, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 78, 88, 26, 48, 52, 57, 60, 135, 150, 178, 254, 108, 121, 145, 83, 105, 118, 142, 76, 106, 119, 143, 201, 118, 133, 159, 122, 117, 129, 152, 25, 168, 176, 190, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    118, 128, 145, 3, 104, 117, 140, 92, 114, 127, 152, 180, 131, 147, 177, 237, 133, 149, 178, 249, 38, 42, 50, 222, 137, 152, 180, 249, 126, 142, 170, 182, 114, 128, 154, 182, 104, 117, 140, 227, 95, 107, 128, 238, 83, 93, 112, 248, 84, 95, 113, 239, 104, 117, 141, 180, 115, 129, 155, 93, 127, 140, 165, 4,
    98, 109, 130, 153, 109, 123, 147, 254, 145, 163, 195, 153, 138, 154, 182, 56, 115, 123, 138, 5, 92, 99, 109, 35, 134, 149, 177, 230, 0, 0, 0, 0, 0, 0, 0, 0, 120, 133, 159, 143, 135, 151, 181, 115, 86, 89, 93, 5, 41, 45, 51, 54, 40, 45, 53, 150, 107, 120, 144, 254, 122, 137, 164, 154,
    51, 57, 66, 147, 83, 93, 112, 255, 108, 121, 145, 159, 113, 126, 151, 62, 123, 136, 159, 8, 87, 93, 103, 35, 125, 141, 169, 230, 0, 0, 0, 0, 0, 0, 0, 0, 129, 143, 169, 143, 140, 156, 184, 115, 134, 147, 172, 8, 124, 138, 165, 60, 124, 139, 167, 155, 131, 147, 177, 255, 131, 147, 176, 153,
    64, 68, 73, 2, 36, 39, 45, 86, 41, 46, 54, 173, 60, 67, 80, 232, 75, 84, 101, 251, 89, 100, 120, 228, 105, 118, 142, 250, 110, 123, 148, 187, 118, 132, 158, 187, 126, 141, 169, 229, 134, 149, 177, 239, 136, 152, 179, 250, 136, 152, 181, 234, 139, 156, 186, 175, 130, 145, 173, 90, 124, 134, 151, 3,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 74, 79, 19, 60, 64, 73, 50, 92, 103, 124, 254, 86, 95, 111, 84, 90, 100, 117, 76, 126, 141, 168, 201, 113, 126, 150, 119, 99, 105, 117, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 105, 125, 231, 135, 151, 181, 46, 0, 0, 0, 0, 137, 154, 184, 212, 123, 137, 164, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74, 83, 98, 191, 133, 149, 179, 102, 111, 121, 139, 17, 134, 150, 180, 252, 126, 140, 166, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 48, 57, 132, 121, 136, 164, 197, 121, 135, 161, 115, 130, 146, 175, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 47, 52, 46, 87, 98, 118, 254, 126, 142, 170, 254, 124, 139, 166, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 57, 67, 118, 115, 128, 152, 170, 127, 140, 164, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    ])

    image = IupImageRGBA(16, 16, pointer(imgdata))
    return image
end

function img_bits1()
    img = UInt8.([
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1
    ,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1
    ,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1
    ,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1
    ,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1
    ,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1
    ,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1
    ,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,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,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,2,2
    ,2,2,2,0,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,0,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,0,2,0,2,0,2,2,0,2,2,2,0,0,0,2,2,2,0,0,2,0,2,2,0,0,0,2,2,2
    ,2,2,2,0,2,0,0,2,0,0,2,0,2,0,2,2,2,0,2,0,2,2,0,0,2,0,2,2,2,0,2,2
    ,2,2,2,0,2,0,2,2,0,2,2,0,2,2,2,2,2,0,2,0,2,2,2,0,2,0,2,2,2,0,2,2
    ,2,2,2,0,2,0,2,2,0,2,2,0,2,2,0,0,0,0,2,0,2,2,2,0,2,0,0,0,0,0,2,2
    ,2,2,2,0,2,0,2,2,0,2,2,0,2,0,2,2,2,0,2,0,2,2,2,0,2,0,2,2,2,2,2,2
    ,2,2,2,0,2,0,2,2,0,2,2,0,2,0,2,2,2,0,2,0,2,2,0,0,2,0,2,2,2,0,2,2
    ,2,2,2,0,2,0,2,2,0,2,2,0,2,2,0,0,0,0,2,2,0,0,2,0,2,2,0,0,0,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,0,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,0,2,2,2,0,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,0,0,0,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,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,2,2,2,2,2,2,2,2,2,2,2
    ,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1
    ,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1
    ,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1
    ,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1
    ,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
    ,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
    ,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
    ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
    ])
end

function img_bits2()
    img = UInt8.([
     2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2
    ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2
    ,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2
    ,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2
    ,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2
    ,2,2,2,2,2,2,2,2,2,2,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2
    ,2,2,2,2,2,2,2,2,2,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2
    ,2,2,2,2,2,2,2,2,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2
    ,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
    ,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
    ,3,3,3,0,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
    ,3,3,3,0,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
    ,3,3,3,0,3,0,3,0,3,3,0,3,3,3,1,1,0,3,3,3,0,0,3,0,3,3,0,0,0,3,3,3
    ,3,3,3,0,3,0,0,3,0,0,3,0,3,0,1,1,3,0,3,0,3,3,0,0,3,0,3,3,3,0,3,3
    ,3,3,3,0,3,0,3,3,0,3,3,0,3,3,1,1,3,0,3,0,3,3,3,0,3,0,3,3,3,0,3,3
    ,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,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,1,1
    ,3,3,3,0,3,0,3,3,0,3,3,0,3,0,1,1,3,0,3,0,3,3,0,0,3,0,3,3,3,0,3,3
    ,3,3,3,0,3,0,3,3,0,3,3,0,3,3,1,1,0,0,3,3,0,0,3,0,3,3,0,0,0,3,3,3
    ,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,0,3,3,3,3,3,3,3,3
    ,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,0,3,3,3,0,3,3,3,3,3,3,3,3
    ,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,0,0,0,3,3,3,3,3,3,3,3,3
    ,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
    ,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
    ,2,2,2,2,2,2,2,3,3,3,3,3,3,3,1,1,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2
    ,2,2,2,2,2,2,3,3,3,3,3,3,3,3,1,1,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2
    ,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2
    ,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2
    ,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
    ,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
    ,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
    ,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
    ])
end

#end     # @iprofile begin

end     # module


text:
abstract type InferenceOptimizer end

## Abstract type for analytical optimiser (closed forms are known)
abstract type AOptimizer <: InferenceOptimizer end
## Abstract type for numerical optimiser (need for numerical integration)
abstract type NOptimizer <: InferenceOptimizer end

# Analytic VI Optimizer
struct AVIOptimizer{O} <: AOptimizer
    optimiser::O # Optimiser for stochastic updates
end

# Numerical VI Optimizer
struct NVIOptimizer{O} <: NOptimizer
    optimiser::O # Optimiser for stochastic updates
end

# Sampling Optimizer, does not contain anyting, just a place-holder for sampling
struct SOptimizer{O} <: AOptimizer
    optimiser::O
end

Optimisers.state(opt::InferenceOptimizer, x) = Optimisers.state(opt.optimiser, x)
function Optimisers.apply(opt::InferenceOptimizer, st, x, dx)
    return Optimisers.apply(opt.optimiser, st, x, dx)
end
function Optimisers.update(opt::InferenceOptimizer, st, x, dx)
    return Optimisers.update(opt.optimiser, st, x, dx)
end

Base.length(::InferenceOptimizer) = 1

Base.iterate(i::InferenceOptimizer) = (i, nothing)
Base.iterate(::InferenceOptimizer, ::Any) = nothing


text:
export ShiftedLaplacianMultigridSolver,updateParam,getShiftedLaplacianMultigridSolver,copySolver
export solveLinearSystem,clear!

type ShiftedLaplacianMultigridSolver <: AbstractSolver
	helmParam		:: HelmholtzParam
	MG				:: MGparam
	shift			:: Array{Float64}
	Krylov			:: String
	inner			:: Int64
	doClear			:: Int64 # flag to clear factorization
	verbose			:: Bool
	setupTime       ::Real
	nPrec           ::Int
	solveTime       ::Real
end

import jInv.LinearSolvers.copySolver;
function copySolver(s::ShiftedLaplacianMultigridSolver)
	# copies absolutely what's necessary.
	clear!(s.helmParam.Mesh);
	return getShiftedLaplacianMultigridSolver(s.helmParam,Multigrid.copySolver(s.MG),s.shift,s.Krylov,s.inner,s.verbose);
end

function getShiftedLaplacianMultigridSolver(helmParam::HelmholtzParam, MG::MGparam,shift::Array{Float64},Krylov::String="BiCGSTAB",inner::Int64=5,verbose::Bool = false)
	return ShiftedLaplacianMultigridSolver(helmParam,MG,shift,Krylov,inner,0,verbose,0.0,0,0.0);
end

function getShiftedLaplacianMultigridSolver(helmParam::HelmholtzParam, MG::MGparam,shift::Float64,Krylov::String="BiCGSTAB",inner::Int64=5,verbose::Bool = false)
	return getShiftedLaplacianMultigridSolver(helmParam,MG,ones(MG.levels)*shift,Krylov,inner,verbose);
end

function solveLinearSystem(ShiftedHT,B,param::ShiftedLaplacianMultigridSolver,doTranspose::Int64=0)
	if size(B,2) == 1
		B = vec(B);
	end
	if param.doClear==1
		clear!(param.MG);
	end
	if vecnorm(B) == 0.0
		X = zeros(eltype(B),size(B));
		return X, param;
	end
	tic()
	TYPE = eltype(B);
	n = size(B,1)
	nrhs = size(B,2)

	# build preconditioner
	if hierarchyExists(param.MG)==false
		## THIS CODE USES GEOMETRIC MULTIGRID
		# shift = param.shift;
		# Hparam_shifted = getShiftedHelmholtzParam(param.helmParam,shift[1]);
		# function restrictParam(mesh_fine,mesh_coarse,param_fine,level)
			# P = getShiftedHelmholtzParam(param_fine,shift[level+1] - shift[level]);
			# P.gamma = restrictNodalVariables2(P.gamma,mesh_fine.n+1);
			# P.m = restrictNodalVariables2(P.m,mesh_fine.n+1);
			# P.Mesh = mesh_coarse;
			# return P;
		# end
		# getOperator(mesh,Hparam) =  GetHelmholtzOperator(mesh,Hparam.m,Hparam.omega,Hparam.gamma,Hparam.NeumannOnTop,Hparam.Sommerfeld);
		# MGsetup(getMultilevelOperatorConstructor(Hparam_shifted,getOperator,restrictParam),Hparam_shifted.Mesh,param.MG,TYPE,nrhs,param.verbose);

		## THIS CODE USES GEOMETRIC MULTIGRID - RAP style.
		MGsetup(ShiftedHT,param.helmParam.Mesh,param.MG,TYPE,nrhs,param.verbose);
	end

	if (doTranspose != param.MG.doTranspose)
		transposeHierarchy(param.MG);
	end

	adjustMemoryForNumRHS(param.MG,TYPE,size(B,2),param.verbose)
	BLAS.set_num_threads(param.MG.numCores);
	ShiftedHT = param.MG.As[1];
	Az = param.MG.memCycle[1].b;
	if param.shift[1] != 0.0
		MShift = GetHelmholtzShiftOP(param.helmParam.m, param.helmParam.omega,param.shift[1]);
		if doTranspose==1
			MShift = -MShift; # this is because of the conjugate
		end
		Afun = getHelmholtzFun(ShiftedHT,MShift,Az,param.MG.numCores);
	else
		Afun = getAfun(ShiftedHT,Az,param.MG.numCores);
	end

	param.setupTime += toq();
	tic()
	if param.Krylov=="GMRES"
		X, param.MG,num_iter,nprec = solveGMRES_MG(Afun,param.MG,B,Array{eltype(B)}(0),param.verbose,param.inner);
	elseif param.Krylov=="BiCGSTAB"
		X, param.MG,num_iter,nprec = solveBiCGSTAB_MG(Afun,param.MG,B,Array{eltype(B)}(0),param.verbose);
	end
	param.solveTime +=toq();
	param.nPrec += nprec;
	if num_iter >= param.MG.maxOuterIter
		warn("MG solver reached maximum iterations without convergence");
	end

	return X, param
end

import jInv.Utils.clear!
function clear!(s::ShiftedLaplacianMultigridSolver)
	 clear!(s.MG);
	 clear!(s.helmParam)
	 s.doClear = 0;
end


text:
using JuMP
using GLPKMathProgInterface
using Ipopt

n = 2;
m = Model()
@defVar(m, -2 <= α[i=1:n] <= 2)
@defVar(m, -2 <= β1[i=1:n] <= 2)
@defVar(m, -2 <= β2[i=1:n] <= 2)
@defVar(m, -2 <= β3[i=1:n] <= 2)
@defVar(m, -2 <= β4[i=1:n] <= 2)

@defVar(m, -2 <= A011 <= 2)
@defVar(m, -2 <= A012 <= 2)
@defVar(m, -2 <= A021 <= 2)
@defVar(m, -2 <= A022 <= 2)

@defVar(m, -2 <= A111 <= 2)
@defVar(m, -2 <= A112 <= 2)
@defVar(m, -2 <= A121 <= 2)
@defVar(m, -2 <= A122 <= 2)

@defVar(m, -2 <= B011 <= 2)
@defVar(m, -2 <= B012 <= 2)
@defVar(m, -2 <= B021 <= 2)
@defVar(m, -2 <= B022 <= 2)

@defVar(m, -2 <= B111 <= 2)
@defVar(m, -2 <= B112 <= 2)
@defVar(m, -2 <= B121 <= 2)
@defVar(m, -2 <= B122 <= 2)

A0 = [A011 A012
     A021 A022]
A1 = [A111 A112
     A121 A122]
B0 = [B011 B012
      B021 B022]
B1 = [B111 B112
      B121 B122]
e = [1 1]'

@setObjective(m, Max, 0)
@addConstraints(m,sum{α[i], i=1:n}==1)
@addConstraint(m,sum{β1[i], i=1:n}==1)
@addConstraint(m,sum{β2[i], i=1:n}==0)
@addConstraint(m,sum{β3[i], i=1:n}==0)
@addConstraint(m,sum{β4[i], i=1:n}==0)
@addConstraint(m,sum{β4[i], i=1:n}==0)
@addNLConstraint(m,transpose(β1)*B1*e==0)
@addNLConstraint(m,transpose(β2)*B1*e==1)
@addNLConstraint(m,transpose(β3)*B1*e==0)
@addNLConstraint(m,transpose(β4)*B1*e==0)

@addNLConstraint(m,transpose(α)*A0*e==1//2)
@addNLConstraint(m,transpose(α)*B0*e==1)
@addNLConstraint(m,transpose(α)*(B0*e).^2 ==3//2)
@addNLConstraint(m,transpose(β1)*A1*e==1)
@addNLConstraint(m,transpose(β2)*A1*e==0)
@addNLConstraint(m,transpose(β3)*A1*e==-1)
@addNLConstraint(m,transpose(β4)*A1*e==0)

@addNLConstraint(m,transpose(β1)*(B1*e).^2==1)
@addNLConstraint(m,transpose(β3)*(B1*e).^2==-1)
@addNLConstraint(m,transpose(β2)*(B1*e).^2==0)
@addNLConstraint(m,transpose(β4)*(B1*e).^2==2)

@addNLConstraint(m,transpose(β1)*(B1*(B1*e))==0)
@addNLConstraint(m,transpose(β2)*(B1*(B1*e))==0)
@addNLConstraint(m,transpose(β3)*(B1*(B1*e))==0)
@addNLConstraint(m,transpose(β4)*(B1*(B1*e))==1)

@addNLConstraint(m,(1//2)*transpose(β1)*(A1*(B0*e))+(1//3)*transpose(β3)*(A1*(B0*e))==0)

print(m)

status = solve(m)

println("Objective value: ", getObjectiveValue(m))
println("x = ", getValue(x))
println("y = ", getValue(y))


text:
@testset "Compare to Float64" begin

    n = 100

    X = randn(Float64,n)
    Y = randn(Float64,n)

    for i in 1:n                # ADDITION
        r = X[i] + Y[i]
        @test r == Sherlog64(X[i]) + Sherlog64(Y[i])
    end

    for i in 1:n                # SUBTRACTION
        r = X[i] - Y[i]
        @test r == Sherlog64(X[i]) - Sherlog64(Y[i])
    end

    for i in 1:n                # MULTIPLICATION
        r = X[i] * Y[i]
        @test r == Sherlog64(X[i]) * Sherlog64(Y[i])
    end

    for i in 1:n                # DIVISION
        r = X[i] / Y[i]
        @test r == Sherlog64(X[i]) / Sherlog64(Y[i])
    end

    for i in 1:n
        r = sqrt(abs(X[i]))
        @test r == sqrt(Sherlog64(abs(X[i])))
    end
end

@testset "Compare to Float32" begin

    n = 100

    X = randn(Float32,n)
    Y = randn(Float32,n)

    for i in 1:n                # ADDITION
        r = X[i] + Y[i]
        @test r == Sherlog32(X[i]) + Sherlog32(Y[i])
    end

    for i in 1:n                # SUBTRACTION
        r = X[i] - Y[i]
        @test r == Sherlog32(X[i]) - Sherlog32(Y[i])
    end

    for i in 1:n                # MULTIPLICATION
        r = X[i] * Y[i]
        @test r == Sherlog32(X[i]) * Sherlog32(Y[i])
    end

    for i in 1:n                # DIVISION
        r = X[i] / Y[i]
        @test r == Sherlog32(X[i]) / Sherlog32(Y[i])
    end

    for i in 1:n
        r = sqrt(abs(X[i]))
        @test r == sqrt(Sherlog32(abs(X[i])))
    end
end

@testset "Compare to Float16" begin

    n = 100

    X = randn(Float16,n)
    Y = randn(Float16,n)

    for i in 1:n                # ADDITION
        r = X[i] + Y[i]
        @test r == Sherlog16(X[i]) + Sherlog16(Y[i])
    end

    for i in 1:n                # SUBTRACTION
        r = X[i] - Y[i]
        @test r == Sherlog16(X[i]) - Sherlog16(Y[i])
    end

    for i in 1:n                # MULTIPLICATION
        r = X[i] * Y[i]
        @test r == Sherlog16(X[i]) * Sherlog16(Y[i])
    end

    for i in 1:n                # DIVISION
        r = X[i] / Y[i]
        @test r == Sherlog16(X[i]) / Sherlog16(Y[i])
    end

    for i in 1:n
        r = sqrt(abs(X[i]))
        @test r == sqrt(Sherlog16(abs(X[i])))
    end
end

@testset "Matrix multiplication" begin

    n = 10      # this can't be too large.
    # Presumably Float64 uses BLAS or similar, but Sherlog64 will use another implementation

    A = rand(Float64,n,n)
    B = rand(Float64,n,n)

    @test all(A*B .≈ Sherlog64.(A)*Sherlog64.(B))

    A = rand(Float32,n,n)
    B = rand(Float32,n,n)

    @test all(A*B .≈ Sherlog32.(A)*Sherlog32.(B))

    A = rand(Float16,n,n)
    B = rand(Float16,n,n)

    @test all(A*B .≈ Sherlog16.(A)*Sherlog16.(B))

end

@testset "Matrix solve" begin

    n = 10      # see above

    A = rand(Float64,n,n)
    b = rand(Float64,n)

    @test all(A\b .≈ Sherlog64.(A)\Sherlog64.(b))

    A = rand(Float32,n,n)
    b = rand(Float32,n)

    @test all(A\b .≈ Sherlog32.(A)\Sherlog32.(b))

    A = rand(Float16,n,n)
    b = rand(Float16,n)

    @test all(A\b .≈ Sherlog16.(A)\Sherlog16.(b))

end

@testset "Random" begin

    using Random

    for SherlogN in (:Sherlog16, :Sherlog32, :Sherlog64)
        @eval FloatN = $(Symbol("Float",string(SherlogN)[end-1:end]))

        @eval A = Array{$FloatN}(undef, 10)
        @eval B = Array{$SherlogN}(undef, 10)
        rand!(A)
        rand!(B)
        @test A !== B

        randn!(A)
        randn!(B)
        @test A !== B

        randexp!(A)
        randexp!(B)
        @test A !== B

        @eval A = rand($FloatN, 10)
        @eval B = rand($SherlogN, 10)
        @test A !== B

        @eval A = randn($FloatN, 10)
        @eval B = randn($SherlogN, 10)
        @test A !== B

        @eval A = randexp($FloatN, 10)
        @eval B = randexp($SherlogN, 10)
        @test A !== B
    end

end

@testset "round" begin

    x = 4/3

    for SherlogN in (:Sherlog16, :Sherlog32, :Sherlog64)
        @eval round($x) == round($SherlogN($x)) == 1
    end

end

@testset "rem" begin

    x,y = 4,3

    for SherlogN in (:Sherlog16, :Sherlog32, :Sherlog64)
        @eval rem($x,$y) == rem($SherlogN($x), $SherlogN($y)) == 1
    end

end


text:
module Accessors
using MacroTools
using MacroTools: isstructdef, splitstructdef, postwalk
using Requires: @require

include("setindex.jl")
include("optics.jl")
include("sugar.jl")
include("functionlenses.jl")
include("testing.jl")

function __init__()
    @require StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" include("staticarrays.jl")
end

end


text:
"""
    Mode

# Description

A type that represents the mode of finite differences being used.

* Super type: `Any`
"""
abstract Mode

"""
    ForwardMode

# Description

A type that represents the use of forward mode finite differences for
gradients.

* Super type: `Mode`
"""
immutable ForwardMode <: Mode
end

"""
    BackwardMode

# Description

A type that represents the use of backward mode finite differences for
gradients.

* Super type: `Mode`
"""
immutable BackwardMode <: Mode
end

"""
    CentralMode

# Description

A type that represents the use of central mode finite differences for
gradients.

* Super type: `Mode`
"""
immutable CentralMode <: Mode
end

"""
    ComplexMode

# Description

A type that represents the use of complex mode finite differences for
gradients.

* Super type: `Mode`
"""
immutable ComplexMode <: Mode
end

"""
    HessianMode

# Description

A type that represents the use of finite differences for hessians.

* Super type: `Mode`
"""
immutable HessianMode <: Mode
end


text:
# This file is a part of Actors.jl, licensed under the MIT License (MIT).

using Compat

export Actor
export ActorMsgFrame
export ActorID
export ActorInbox
export AbstractLocalActor
export LocalActor
export LocalActorAltInbox
export ActorContext
export NullActor

export @actor

export actor_id
export actor_inbox
export localactor
export actor_context
export actor_id
export actor_inbox
export localactor
export actor_task
export self
export receive
export tell
export ask

@compat abstract type Actor end

immutable ActorMsgFrame
    replyto::Actor
    message::Any
end

const ActorID = UInt64

const ActorInbox = Channel{Any}

abstract AbstractLocalActor <: Actor

immutable LocalActor <: AbstractLocalActor
   task::Task

   LocalActor(task::Task) = new(task)
end

function LocalActor(body)
    const contextch = Channel{ActorContext}(5)
    try
        const task = @schedule let
            const context = actorize_current_task(false)
            put!(contextch, context)
            try
                body()
            finally
                close(context)
            end
        end
        localactor(take!(contextch))
    finally
        close(contextch)
    end
end

immutable LocalActorAltInbox <: AbstractLocalActor
    actor::LocalActor
    inbox::ActorInbox
end

immutable ActorContext
   id::ActorID
   inbox::ActorInbox
   self_ref::LocalActor
end

@inline actor_id(context::ActorContext) = context.id

@inline actor_inbox(context::ActorContext) = context.inbox

@inline localactor(context::ActorContext) = context.self_ref

actor_context(task::Task) = task.storage[:_actor_context]::ActorContext

@inline actor_id(task::Task) = actor_id(actor_context(task))

@inline actor_inbox(task::Task) = actor_inbox(actor_context(task))

@inline localactor(task::Task) = localactor(actor_context(task))

Base.show(io::IO, actor::LocalActor) = print(io, "local-actor-$(hex(actor_id(actor)))")
Base.show(io::IO, actor::LocalActorAltInbox) = print(io, "local-actor-alt-$(hex(actor_id(actor)))")

@inline Base.wait(actor::AbstractLocalActor) = wait(actor_task(actor))

function Serializer.serialize(s::SerializationState, actor::LocalActor)
    info("Serializing $actor (dummy implementation)")
    serialize(s, actor_id(actor))
end

@inline actor_task(actor::LocalActor) = actor.task

@inline actor_context(actor::AbstractLocalActor) = actor_context(actor_task(actor))
@inline actor_id(actor::AbstractLocalActor) = actor_id(actor_task(actor))

@inline actor_inbox(actor::LocalActor) = actor_inbox(actor_task(actor))

@inline actor_task(actor::LocalActorAltInbox) = actor_task(actor.actor)
@inline actor_inbox(actor::LocalActorAltInbox) = actor.inbox

function actorize_current_task(autoclose::Bool, chsize = 100)
    try
        task_local_storage(:_actor_context)::ActorContext
    catch
        const task = current_task()

        const id = rand(UInt64)
        const inbox = ActorInbox(chsize)
        const self_ref = LocalActor(task)
        const context = ActorContext(id, inbox, self_ref)
        task_local_storage(:_actor_context, context)

        autoclose && @schedule begin
            wait(task)
            close(context)
        end

        context::ActorContext
    end
end

self_context() = actorize_current_task(true)

@inline self() = localactor(self_context())

@inline self_inbox() = actor_inbox(self_context())

self_with_alt_inbox(inbox::ActorInbox) = LocalActorAltInbox(self(), inbox)

function receive(inbox::ActorInbox)
    const message = take!(inbox)::ActorMsgFrame
    Pair(message.replyto, message.message)
end

receive() = receive(self_inbox())

function Base.close(context::ActorContext)
    close(actor_inbox(context))
end

macro actor(body)
    quote
        LocalActor(() -> let
                $body
            end
        )
    end
end

tell(to::Actor, message::Any) = tell(to, message, self())

function ask(actor::Actor, msg::Any)
    const result = Ref{Any}()
    const queryactor = @actor begin
        tell(actor, msg)
        const x, reply = receive()
        result.x = reply
    end
    wait(queryactor)
    result.x
end

function tell(to::AbstractLocalActor, message::Any, replyto::Actor)
    try
        put!(actor_inbox(to), ActorMsgFrame(replyto, message))
    catch
        # info("Dead letter from $sender to $actor: $message")
    end
    return
end

function ask(actor::LocalActor, msg::Any)
    const tmp_inbox = ActorInbox(1)
    try
        tell(actor, msg, self_with_alt_inbox(tmp_inbox))
        x, reply = receive(tmp_inbox)
        reply
    finally
        close(tmp_inbox)
    end
end

function Base.kill(actor::LocalActor, exc = InterruptException())
    Base.throwto(actor_task(actor), exc)
    return
end

immutable NullActor <: Actor
end

@inline actor_id(::NullActor) = 0x0

Base.show(io::IO, actor::NullActor) = print(io, "null-actor")
Base.wait(actor::NullActor) = begin return end

tell(::NullActor, message::Any, replyto::Actor) = nothing