text:
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md

# # JuliaFEM Linear Static Example

# ![](linear_static_example_for_mechanics_days/freecad.png)

# ## Preprocessing
using JuliaFEM
using JuliaFEM.Preprocess
using JuliaFEM.Postprocess
add_elements! = JuliaFEM.add_elements!

# First we will read in the mesh. Geometry and mesh are greated with FreeCAD,
# where med format is selected for exporting. Mesh file consist also edge and
# surface mesh, which we will need to neglect later.

datadir = Pkg.dir("JuliaFEMDocumentation", "examples", "linear_static_example_for_mechanics_days")
meshfile = joinpath(datadir, "JuliaFEMSMP18.med")
mesh = aster_read_mesh(meshfile)

# Next we will create the model and define Elasticity. Also elements are added
# to the model.

model = Problem(Elasticity, "OTHER", 3)
model_elements = create_elements(mesh, "OTHER")

# Elements need material properties and they are defined next

update!(model_elements, "youngs modulus", 208.0E3)
update!(model_elements, "poissons ratio", 0.30)
update!(model_elements, "density", 7.80E-9)
add_elements!(model, model_elements)

# We can ignore Seg3 and Tri6 elements using `filter` with a special function
# returning true if element is something else than Seg3 or Tri6:

function is_not_Seg3_or_Tri6(element)
    return !isa(element, Union{Element{Seg3}, Element{Tri6}})
end

filter!(is_not_Seg3_or_Tri6, model.elements)

# The whole idea of the JuliaFEM input is to be a normal Julia script, where the
# user can freely define any functions needed to perform the task. Here we
# define a function, which finds nodes on the given plane yz, xz or xy from the
# given height.

function add_nodes_at_certain_plane_to_node_set!(mesh, name, vector_id, distance, radius=6.0)
    for (node, coords) in mesh.nodes
        if isapprox(coords[vector_id], distance, atol=radius)
            add_node_to_node_set!(mesh, name, node)
        end
    end
    return nothing
end

# We will find nodes from the xz-plane going through point (0,50,0) or actually
# we previously defined the radius to be 6.0, which means (0,[44,56],0). In other
# words we will select each node, which second coordinate value is between 44
# and 56. This function will edit mesh object and add node set called `:mid_fixed` to it.
add_nodes_at_certain_plane_to_node_set!(mesh,:mid_fixed,2,50.0)

# We need to somehow handle the i's dot. I looked the rough coordinates of the
# dot in FreeCAD and now we can search three closest nodes to these coordinates.
# Those will be added to the same set `:mid_fixed`.

ipoint = find_nearest_nodes(mesh, [165.0, 88.0, 10],3)
for poi in ipoint
    add_node_to_node_set!(mesh, :mid_fixed, poi)
end

# The fixed boundary conditions are defined next.

fixed = Problem(Dirichlet, "fixed", 3, "displacement")
fixed_elements = create_nodal_elements(mesh, "mid_fixed")
add_elements!(fixed, fixed_elements)
update!(fixed_elements, "displacement 1", 0.0)
update!(fixed_elements, "displacement 2", 0.0)
update!(fixed_elements, "displacement 3", 0.0)

# Let's use simple acceleration load.
update!(model_elements, "displacement load 1", 1.0)

# Finally the ´Analysis` couples everything togeter.
analysis = Analysis(Linear, model, fixed)

# Let's write resuls to Xdmf file

xdmf = Xdmf(joinpath(datadir,"model_results"); overwrite=true)
add_results_writer!(analysis, xdmf)

# Now we have all we need to run the analysis.

run!(analysis)

# ## Postprocessing

# This is how the stresses are requested
push!(model.postprocess_fields, "stress")

# Finally let's write the results to the xdmf (this is bug, the solver should
# do this automatically, see issue #203)

time = 0.0
JuliaFEM.postprocess!(analysis, time)
JuliaFEM.write_results!(analysis, time)

# In order to look the results, we will need to close the xdmf that it is actually
# written to the file from buffer.

close(xdmf.hdf)

# Finally when we open the model in ParaView and set some settings we have this
# end result.

# ![](linear_static/paraview.png)

# ## Testing

# First let's test that we have the output files writen to the disk

if VERSION < v"1.0.0"
    using Base.Test
else
    using Test
end
@testset "tests" begin

@test isfile(joinpath(datadir,"model_results.xmf"))
@test isfile(joinpath(datadir,"model_results.h5"))

# Secondly let's test that we have the same maximum displacement each time.
# This is also an usefull example how to access the displacements values.

time = 0.0
u = analysis("displacement", time)
u_norms = Dict(i => norm(j) for (i, j) in u)
@test isapprox(maximum(values(u_norms)),2.4052929896922337)
end


text:
abstract type AbstractGreenFunction end

"""
    A time-ordered Green function.

    This framework arises because the Heaviside functions that work very nicely
    on paper are different beasts when the Green function is discretized in a matrix form.
"""
struct TimeOrderedGreenFunction <: AbstractGreenFunction
    L   # Lesser
    G   # Greater
    R   # Retarded (this is not the true retarded function)
    A   # Advanced (this is not the true advanced function)

    hs

    function TimeOrderedGreenFunction(L, G, hs)
        A = UpperTriangular(G - L) .* hs
        new(L, G, adjoint(A), A, hs)
    end
end

struct TimeOrderedConvolution{T<:AbstractGreenFunction, V<:AbstractGreenFunction} <: AbstractGreenFunction
    A::T
    B::V

    hs
end

function Base.:+(a::AbstractGreenFunction, b::AbstractGreenFunction)
    @assert a.hs === b.hs
    TimeOrderedGreenFunction(lesser(a) + lesser(b), greater(a) + greater(b), a.hs)
end

function Base.:*(a::AbstractGreenFunction, b::AbstractGreenFunction)
    @assert a.hs === b.hs
    TimeOrderedConvolution(a, b, a.hs)
end

ext: jl


text:
using Base.Meta

macro constants(array, stripprefix, expr)
    ret = Expr(:block)
    # Initialize the name lookup array
    push!(ret.args,:(const $array = Dict{UInt32,String}()))
    for e in expr.args
        if !isexpr(e,:const)
            continue
        end
        eq = e.args[1]
        @assert isexpr(eq,:(=))
        name = string(eq.args[1])
        name = replace(name,stripprefix,"",1)
        push!(ret.args,e)
        push!(ret.args,:($array[UInt32($(eq.args[1]))] = $name))
    end
    return esc(ret)
end

# # # Machine Types
@constants IMAGE_FILE_MACHINE "IMAGE_FILE_" begin
    const IMAGE_FILE_MACHINE_UNKNOWN        = 0x0       # The contents of this field are assumed to be applicable to any machine type
    const IMAGE_FILE_MACHINE_AM33           = 0x1d3     #   Matsushita AM33
    const IMAGE_FILE_MACHINE_AMD64          = 0x8664    #  x64
    const IMAGE_FILE_MACHINE_ARM            = 0x1c0     #   ARM little endian
    const IMAGE_FILE_MACHINE_ARMNT          = 0x1c4     #   ARMv7 (or higher) Thumb mode only
    const IMAGE_FILE_MACHINE_ARM64          = 0xaa64    #  ARMv8 in 64-bit mode
    const IMAGE_FILE_MACHINE_EBC            = 0xebc     #   EFI byte code
    const IMAGE_FILE_MACHINE_I386           = 0x14c     #   Intel 386 or later processors and compatible processors
    const IMAGE_FILE_MACHINE_IA64           = 0x200     #   Intel Itanium processor family
    const IMAGE_FILE_MACHINE_M32R           = 0x9041    #  Mitsubishi M32R little endian
    const IMAGE_FILE_MACHINE_MIPS16         = 0x266     #   MIPS16
    const IMAGE_FILE_MACHINE_MIPSFPU        = 0x366     #   MIPS with FPU
    const IMAGE_FILE_MACHINE_MIPSFPU16      = 0x466     #   MIPS16 with FPU
    const IMAGE_FILE_MACHINE_POWERPC        = 0x1f0     #   Power PC little endian
    const IMAGE_FILE_MACHINE_POWERPCFP      = 0x1f1     #   Power PC with floating point support
    const IMAGE_FILE_MACHINE_R4000          = 0x166     #   MIPS little endian
    const IMAGE_FILE_MACHINE_SH3            = 0x1a2     #   Hitachi SH3
    const IMAGE_FILE_MACHINE_SH3DSP         = 0x1a3     #   Hitachi SH3 DSP
    const IMAGE_FILE_MACHINE_SH4            = 0x1a6     #   Hitachi SH4
    const IMAGE_FILE_MACHINE_SH5            = 0x1a8     #   Hitachi SH5
    const IMAGE_FILE_MACHINE_THUMB          = 0x1c2     #   ARM or Thumb (“interworking”)
    const IMAGE_FILE_MACHINE_WCEMIPSV2      = 0x169     #   MIPS little-endian WCE v2
end

# # # Characteristics

@constants IMAGE_FILE_CHARACTERISTICS "IMAGE_FILE_" begin
    const IMAGE_FILE_RELOCS_STRIPPED            = 0x0001 # Image only, Windows CE, and Windows NT® and later. This indicates that the file does not contain base relocations and must therefore be loaded at its preferred base address. If the base address is not available, the loader reports an error. The default behavior of the linker is to strip base relocations from executable (EXE) files.
    const IMAGE_FILE_EXECUTABLE_IMAGE           = 0x0002 # Image only. This indicates that the image file is valid and can be run. If this flag is not set, it indicates a linker error.
    const IMAGE_FILE_LINE_NUMS_STRIPPED         = 0x0004 # COFF line numbers have been removed. This flag is deprecated and should be zero.
    const IMAGE_FILE_LOCAL_SYMS_STRIPPED        = 0x0008 # COFF symbol table entries for local symbols have been removed. This flag is deprecated and should be zero.
    const IMAGE_FILE_AGGRESSIVE_WS_TRIM         = 0x0010 # Obsolete. Aggressively trim working set. This flag is deprecated for Windows 2000 and later and must be zero.
    const IMAGE_FILE_LARGE_ADDRESS_AWARE        = 0x0020 # Application can handle > 2 GB addresses.
    const IMAGE_FILE_BYTES_REVERSED_LO          = 0x0080 # Little endian: the least significant bit (LSB) precedes the most significant bit (MSB) in memory. This flag is deprecated and should be zero.
    #                                           = 0x0040 # This flag is reserved for future use.
    const IMAGE_FILE_32BIT_MACHINE              = 0x0100 # Machine is based on a 32-bit-word architecture.
    const IMAGE_FILE_DEBUG_STRIPPED             = 0x0200 # Debugging information is removed from the image file.
    const IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP    = 0x0400 # If the image is on removable media, fully load it and copy it to the swap file.
    const IMAGE_FILE_NET_RUN_FROM_SWAP          = 0x0800 # If the image is on network media, fully load it and copy it to the swap file.
    const IMAGE_FILE_SYSTEM                     = 0x1000 # The image file is a system file, not a user program.
    const IMAGE_FILE_DLL                        = 0x2000 # The image file is a dynamic-link library (DLL). Such files are considered executable files for almost all purposes, although they cannot be directly run.
    const IMAGE_FILE_UP_SYSTEM_ONLY             = 0x4000 # The file should be run only on a uniprocessor machine.
    const IMAGE_FILE_BYTES_REVERSED_HI          = 0x8000 # Big endian: the MSB precedes the LSB in memory. This flag is deprecated and should be zero.
end

# # # Magic Numbers
const MAGICPE32 = 0x10b
const MAGICPE   = 0x20b

# # # Windows Subsystem
const IMAGE_SUBSYSTEM_UNKNOWN                   =   0  # An unknown subsystem
const IMAGE_SUBSYSTEM_NATIVE                    =   1  # Device drivers and native Windows processes
const IMAGE_SUBSYSTEM_WINDOWS_GUI               =   2  # The Windows graphical user interface (GUI) subsystem
const IMAGE_SUBSYSTEM_WINDOWS_CUI               =   3  # The Windows character subsystem
const IMAGE_SUBSYSTEM_POSIX_CUI                 =   7  # The Posix character subsystem
const IMAGE_SUBSYSTEM_WINDOWS_CE_GUI            =   9  # Windows CE
const IMAGE_SUBSYSTEM_EFI_APPLICATION           =   10 # An Extensible Firmware Interface (EFI) application
const IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER   =   11 # An EFI driver with boot services
const IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER        =   12 # An EFI driver with run-time services
const IMAGE_SUBSYSTEM_EFI_ROM                   =   13 # An EFI ROM image
const IMAGE_SUBSYSTEM_XBOX                      =   14 # XBOX

# # # DLL Characteristics

#                                                       = 0x0001 #  Reserved, must be zero
#                                                       = 0x0002 #  Reserved, must be zero
#                                                       = 0x0004 #  Reserved, must be zero
#                                                       = 0x0008 #  Reserved, must be zero
const IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE            = 0x0040 #  DLL can be relocated at load time.
const IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY         = 0x0080 #  Code Integrity checks are enforced.
const IMAGE_DLL_CHARACTERISTICS_NX_COMPAT               = 0x0100 #  Image is NX compatible.
const IMAGE_DLLCHARACTERISTICS_NO_ISOLATION             = 0x0200 #  Isolation aware, but do not isolate the image.
const IMAGE_DLLCHARACTERISTICS_NO_SEH                   = 0x0400 #  Does not use structured exception (SE) handling. No SE handler may be called in this image.
const IMAGE_DLLCHARACTERISTICS_NO_BIND                  = 0x0800 #  Do not bind the image.
#                                                       = 0x1000 #  Reserved, must be zero
const IMAGE_DLLCHARACTERISTICS_WDM_DRIVER               = 0x2000 #  A WDM driver.
const IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE    = 0x8000 #  Terminal Server aware.

# # # Section Flags
@constants IMAGE_SCN_CHARACTERISTICS "IMAGE_SCN_" begin
    #                                         = 0x00000000 #  Reserved for future use.
    #                                         = 0x00000001 #  Reserved for future use.
    #                                         = 0x00000002 #  Reserved for future use.
    #                                         = 0x00000004 #  Reserved for future use.
    const IMAGE_SCN_TYPE_NO_PAD               = 0x00000008 #  The section should not be padded to the next boundary. This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES. This is valid only for object files.
    #                                         = 0x00000010 #  Reserved for future use.
    const IMAGE_SCN_CNT_CODE                  = 0x00000020 #  The section contains executable code.
    const IMAGE_SCN_CNT_INITIALIZED_DATA      = 0x00000040 #  The section contains initialized data.
    const IMAGE_SCN_CNT_UNINITIALIZED_DATA    = 0x00000080 #  The section contains uninitialized data.
    const IMAGE_SCN_LNK_OTHER                 = 0x00000100 #  Reserved for future use.
    const IMAGE_SCN_LNK_INFO                  = 0x00000200 #  The section contains comments or other information. The .drectve section has this type. This is valid for object files only.
    #                                         = 0x00000400 #  Reserved for future use.
    const IMAGE_SCN_LNK_REMOVE                = 0x00000800 #  The section will not become part of the image. This is valid only for object files.
    const IMAGE_SCN_LNK_COMDAT                = 0x00001000 #  The section contains COMDAT data. For more information, see section 5.5.6, “COMDAT Sections (Object Only).” This is valid only for object files.
    const IMAGE_SCN_GPREL                     = 0x00008000 #  The section contains data referenced through the global pointer (GP).
    const IMAGE_SCN_MEM_PURGEABLE             = 0x00020000 #  Reserved for future use.
    const IMAGE_SCN_MEM_16BIT                 = 0x00020000 #  For ARM machine types, the section contains Thumb code.  Reserved for future use with other machine types.
    const IMAGE_SCN_MEM_LOCKED                = 0x00040000 #  Reserved for future use.
    const IMAGE_SCN_MEM_PRELOAD               = 0x00080000 #  Reserved for future use.
    const IMAGE_SCN_ALIGN_1BYTES              = 0x00100000 #  Align data on a 1-byte boundary. Valid only for object files.
    const IMAGE_SCN_ALIGN_2BYTES              = 0x00200000 #  Align data on a 2-byte boundary. Valid only for object files.
    const IMAGE_SCN_ALIGN_4BYTES              = 0x00300000 #  Align data on a 4-byte boundary. Valid only for object files.
    const IMAGE_SCN_ALIGN_8BYTES              = 0x00400000 #  Align data on an 8-byte boundary. Valid only for object files.
    const IMAGE_SCN_ALIGN_16BYTES             = 0x00500000 #  Align data on a 16-byte boundary. Valid only for object files.
    const IMAGE_SCN_ALIGN_32BYTES             = 0x00600000 #  Align data on a 32-byte boundary. Valid only for object files.
    const IMAGE_SCN_ALIGN_64BYTES             = 0x00700000 #  Align data on a 64-byte boundary. Valid only for object files.
    const IMAGE_SCN_ALIGN_128BYTES            = 0x00800000 #  Align data on a 128-byte boundary. Valid only for object files.
    const IMAGE_SCN_ALIGN_256BYTES            = 0x00900000 #  Align data on a 256-byte boundary. Valid only for object files.
    const IMAGE_SCN_ALIGN_512BYTES            = 0x00A00000 #  Align data on a 512-byte boundary. Valid only for object files.
    const IMAGE_SCN_ALIGN_1024BYTES           = 0x00B00000 #  Align data on a 1024-byte boundary. Valid only for object files.
    const IMAGE_SCN_ALIGN_2048BYTES           = 0x00C00000 #  Align data on a 2048-byte boundary. Valid only for object files.
    const IMAGE_SCN_ALIGN_4096BYTES           = 0x00D00000 #  Align data on a 4096-byte boundary. Valid only for object files.
    const IMAGE_SCN_ALIGN_8192BYTES           = 0x00E00000 #  Align data on an 8192-byte boundary. Valid only for object files.
    const IMAGE_SCN_LNK_NRELOC_OVFL           = 0x01000000 #  The section contains extended relocations.
    const IMAGE_SCN_MEM_DISCARDABLE           = 0x02000000 #  The section can be discarded as needed.
    const IMAGE_SCN_MEM_NOT_CACHED            = 0x04000000 #  The section cannot be cached.
    const IMAGE_SCN_MEM_NOT_PAGED             = 0x08000000 #  The section is not pageable.
    const IMAGE_SCN_MEM_SHARED                = 0x10000000 #  The section can be shared in memory.
    const IMAGE_SCN_MEM_EXECUTE               = 0x20000000 #  The section can be executed as code.
    const IMAGE_SCN_MEM_READ                  = 0x40000000 #  The section can be read.
    const IMAGE_SCN_MEM_WRITE                 = 0x80000000 #  The section can be written to.
end
    const IMAGE_SCN_ALIGN_MASK                = 0x00F00000

# # # AMD64 Relocations
@constants IMAGE_REL_AMD64 "IMAGE_REL_AMD64_" begin
    const IMAGE_REL_AMD64_ABSOLUTE    = 0x0000 #  The relocation is ignored.
    const IMAGE_REL_AMD64_ADDR64      = 0x0001 #  The 64-bit VA of the relocation target.
    const IMAGE_REL_AMD64_ADDR32      = 0x0002 #  The 32-bit VA of the relocation target.
    const IMAGE_REL_AMD64_ADDR32NB    = 0x0003 #  The 32-bit address without an image base (RVA).
    const IMAGE_REL_AMD64_REL32       = 0x0004 #  The 32-bit relative address from the byte following the relocation.
    const IMAGE_REL_AMD64_REL32_1     = 0x0005 #  The 32-bit address relative to byte distance 1 from the relocation.
    const IMAGE_REL_AMD64_REL32_2     = 0x0006 #  The 32-bit address relative to byte distance 2 from the relocation.
    const IMAGE_REL_AMD64_REL32_3     = 0x0007 #  The 32-bit address relative to byte distance 3 from the relocation.
    const IMAGE_REL_AMD64_REL32_4     = 0x0008 #  The 32-bit address relative to byte distance 4 from the relocation.
    const IMAGE_REL_AMD64_REL32_5     = 0x0009 #  The 32-bit address relative to byte distance 5 from the relocation.
    const IMAGE_REL_AMD64_SECTION     = 0x000A #  The 16-bit section index of the section that contains the target. This is used to support debugging information.
    const IMAGE_REL_AMD64_SECREL      = 0x000B #  The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage.
    const IMAGE_REL_AMD64_SECREL7     = 0x000C #  A 7-bit unsigned offset from the base of the section that contains the target.
    const IMAGE_REL_AMD64_TOKEN       = 0x000D #  CLR tokens.
    const IMAGE_REL_AMD64_SREL32      = 0x000E #  A 32-bit signed span-dependent value emitted into the object.
    const IMAGE_REL_AMD64_PAIR        = 0x000F #  A pair that must immediately follow every span-dependent value.
    const IMAGE_REL_AMD64_SSPAN32     = 0x0010 #  A 32-bit signed span-dependent value that is applied at link time.
end

# # # ARM Relocations
@constants IMAGE_REL_ARM "IMAGE_REL_ARM_" begin
    const IMAGE_REL_ARM_ABSOLUTE      = 0x0000 #  The relocation is ignored.
    const IMAGE_REL_ARM_ADDR32        = 0x0001 #  The 32-bit VA of the target.
    const IMAGE_REL_ARM_ADDR32NB      = 0x0002 #  The 32-bit RVA of the target.
    const IMAGE_REL_ARM_BRANCH24      = 0x0003 #  The most significant 24 bits of the signed 26-bit relative displacement of the target.  Applied to a B or BL instruction in ARM mode.
    const IMAGE_REL_ARM_BRANCH11      = 0x0004 #  The most significant 22 bits of the signed 23-bit relative displacement of the target.  Applied to a contiguous 16-bit B+BL pair in Thumb mode prior to ARMv7.
    const IMAGE_REL_ARM_TOKEN         = 0x0005 #  CLR tokens.
    const IMAGE_REL_ARM_BLX24         = 0x0008 #  The most significant 24 or 25 bits of the signed 26-bit relative displacement of the target.  Applied to an unconditional BL instruction in ARM mode.  The BL is transformed to a BLX during relocation if the target is in Thumb mode.
    const IMAGE_REL_ARM_BLX11         = 0x0009 #  The most significant 21 or 22 bits of the signed 23-bit relative displacement of the target.  Applied to a contiguous 16-bit B+BL pair in Thumb mode prior to ARMv7.  The BL is transformed to a BLX during relocation if the target is in ARM mode.
    const IMAGE_REL_ARM_SECTION       = 0x000E #  The 16-bit section index of the section that contains the target. This is used to support debugging information.
    const IMAGE_REL_ARM_SECREL        = 0x000F #  The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage.
    const IMAGE_REL_ARM_MOV32A        = 0x0010 #  The 32-bit VA of the target.  Applied to a contiguous MOVW+MOVT pair in ARM mode.  The 32-bit VA is added to the existing value that is encoded in the immediate fields of the pair.
    const IMAGE_REL_ARM_MOV32T        = 0x0011 #  The 32-bit VA of the target.  Applied to a contiguous MOVW+MOVT pair in Thumb mode.  The 32-bit VA is added to the existing value that is encoded in the immediate fields of the pair.
    const IMAGE_REL_ARM_BRANCH20T     = 0x0012 #  The most significant 20 bits of the signed 21-bit relative displacement of the target.  Applied to a 32-bit conditional B instruction in Thumb mode.
    const IMAGE_REL_ARM_BRANCH24T     = 0x0014 #  The most significant 24 bits of the signed 25-bit relative displacement of the target.  Applied to a 32-bit unconditional B or BL instruction in Thumb mode.
    const IMAGE_REL_ARM_BLX23T        = 0x0015 #  The most significant 23 or 24 bits of the signed 25-bit relative displacement of the target.  Applied to a 32-bit BL instruction in Thumb mode.  The BL is transformed to a BLX during relocation if the target is in ARM mode.
end

# # # ARM64 Relocations
@constants IMAGE_REL_ARM64 "IMAGE_REL_ARM64_" begin
    const IMAGE_REL_ARM64_ABSOLUTE          = 0x0000 #  The relocation is ignored.
    const IMAGE_REL_ARM64_ADDR32            = 0x0001 #  The 32-bit VA of the target.
    const IMAGE_REL_ARM64_ADDR32NB          = 0x0002 #  The 32-bit RVA of the target.
    const IMAGE_REL_ARM64_BRANCH26          = 0x0003 #  The 26-bit relative displacement to the target.
    const IMAGE_REL_ARM64_PAGEBASE_REL21    = 0x0004 #  The 21-bit page base of the target.
    const IMAGE_REL_ARM64_REL21             = 0x0005 #  The 21-bit relative displacement to the target.
    const IMAGE_REL_ARM64_PAGEOFFSET_12A    = 0x0006 #  The 12-bit page offset of the target address, used for instruction ADDS.
    const IMAGE_REL_ARM64_PAGEOFFSET_12L    = 0x0007 #  The 12-bit page offset of the target address, used for instruction LDR.
    const IMAGE_REL_ARM64_SECREL            = 0x0008 #  The 32-bit offset of the target from the beginning of its section. This is used to support debugging information.
    const IMAGE_REL_ARM64_SECREL_LOW12A     = 0x0009 #  The low 12-bit offset of the target from the beginning of its section. This is used for static thread local storage and for instruction ADDS.
    const IMAGE_REL_ARM64_SECREL_HIGH12A    = 0x000A #  The 12-bit (bit 12 to bit 23) offset of the target from the beginning of its section. This is used for static thread local storage and for instruction ADDS.
    const IMAGE_REL_ARM64_SECREL_LOW12L     = 0x000B #  The low 12-bit offset of the target from the beginning of its section. This is used for static thread local storage and for instruction LDR.
    const IMAGE_REL_ARM64_TOKEN             = 0x000C #  CLR token.
    const IMAGE_REL_ARM64_SECTION           = 0x000D #  The 16-bit section index of the section that contains the target. This is used to support debugging information.
    const IMAGE_REL_ARM64_ADDR64            = 0x000E #  The 64-bit VA of the relocation target.
end

# # # Hitachi SuperH relocations
@constants IMAGE_REL_SUPERH "IMAGE_REL_" begin
    const IMAGE_REL_SH3_ABSOLUTE            = 0x0000 #  The relocation is ignored.
    const IMAGE_REL_SH3_DIRECT16            = 0x0001 #  A reference to the 16-bit location that contains the VA of the target symbol.
    const IMAGE_REL_SH3_DIRECT32            = 0x0002 #  The 32-bit VA of the target symbol.
    const IMAGE_REL_SH3_DIRECT8             = 0x0003 #  A reference to the 8-bit location that contains the VA of the target symbol.
    const IMAGE_REL_SH3_DIRECT8_WORD        = 0x0004 #  A reference to the 8-bit instruction that contains the effective 16-bit VA of the target symbol.
    const IMAGE_REL_SH3_DIRECT8_LONG        = 0x0005 #  A reference to the 8-bit instruction that contains the effective 32-bit VA of the target symbol.
    const IMAGE_REL_SH3_DIRECT4             = 0x0006 #  A reference to the 8-bit location whose low 4 bits contain the VA of the target symbol.
    const IMAGE_REL_SH3_DIRECT4_WORD        = 0x0007 #  A reference to the 8-bit instruction whose low 4 bits contain the effective 16-bit VA of the target symbol.
    const IMAGE_REL_SH3_DIRECT4_LONG        = 0x0008 #  A reference to the 8-bit instruction whose low 4 bits contain the effective 32-bit VA of the target symbol.
    const IMAGE_REL_SH3_PCREL8_WORD         = 0x0009 #  A reference to the 8-bit instruction that contains the effective 16-bit relative offset of the target symbol.
    const IMAGE_REL_SH3_PCREL8_LONG         = 0x000A #  A reference to the 8-bit instruction that contains the effective 32-bit relative offset of the target symbol.
    const IMAGE_REL_SH3_PCREL12_WORD        = 0x000B #  A reference to the 16-bit instruction whose low 12 bits contain the effective 16-bit relative offset of the target symbol.
    const IMAGE_REL_SH3_STARTOF_SECTION     = 0x000C #  A reference to a 32-bit location that is the VA of the section that contains the target symbol.
    const IMAGE_REL_SH3_SIZEOF_SECTION      = 0x000D #  A reference to the 32-bit location that is the size of the section that contains the target symbol.
    const IMAGE_REL_SH3_SECTION             = 0x000E #  The 16-bit section index of the section that contains the target. This is used to support debugging information.
    const IMAGE_REL_SH3_SECREL              = 0x000F #  The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage.
    const IMAGE_REL_SH3_DIRECT32_NB         = 0x0010 #  The 32-bit RVA of the target symbol.
    const IMAGE_REL_SH3_GPREL4_LONG         = 0x0011 #  GP relative.
    const IMAGE_REL_SH3_TOKEN               = 0x0012 #  CLR token.
    const IMAGE_REL_SHM_PCRELPT             = 0x0013 #  The offset from the current instruction in longwords. If the NOMODE bit is not set, insert the inverse of the low bit at bit 32 to select PTA or PTB.
    const IMAGE_REL_SHM_REFLO               = 0x0014 #  The low 16 bits of the 32-bit address.
    const IMAGE_REL_SHM_REFHALF             = 0x0015 #  The high 16 bits of the 32-bit address.
    const IMAGE_REL_SHM_RELLO               = 0x0016 #  The low 16 bits of the relative address.
    const IMAGE_REL_SHM_RELHALF             = 0x0017 #  The high 16 bits of the relative address.
    const IMAGE_REL_SHM_PAIR                = 0x0018 #  The relocation is valid only when it immediately follows a REFHALF, RELHALF, or RELLO relocation. The SymbolTableIndex field of the relocation contains a displacement and not an index into the symbol table.
    const IMAGE_REL_SHM_NOMODE              = 0x8000 #  The relocation ignores section mode.
end

# # # PowerPC Relocations
@constants IMAGE_REL_PPC "IMAGE_REL_PPC_" begin
    const IMAGE_REL_PPC_ABSOLUTE    = 0x0000 #  The relocation is ignored.
    const IMAGE_REL_PPC_ADDR64      = 0x0001 #  The 64-bit VA of the target.
    const IMAGE_REL_PPC_ADDR32      = 0x0002 #  The 32-bit VA of the target.
    const IMAGE_REL_PPC_ADDR24      = 0x0003 #  The low 24 bits of the VA of the target. This is valid only when the target symbol is absolute and can be sign-extended to its original value.
    const IMAGE_REL_PPC_ADDR16      = 0x0004 #  The low 16 bits of the target’s VA.
    const IMAGE_REL_PPC_ADDR14      = 0x0005 #  The low 14 bits of the target’s VA. This is valid only when the target symbol is absolute and can be sign-extended to its original value.
    const IMAGE_REL_PPC_REL24       = 0x0006 #  A 24-bit PC-relative offset to the symbol’s location.
    const IMAGE_REL_PPC_REL14       = 0x0007 #  A 14-bit PC-relative offset to the symbol’s location.
    const IMAGE_REL_PPC_ADDR32NB    = 0x000A #  The 32-bit RVA of the target.
    const IMAGE_REL_PPC_SECREL      = 0x000B #  The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage.
    const IMAGE_REL_PPC_SECTION     = 0x000C #  The 16-bit section index of the section that contains the target. This is used to support debugging information.
    const IMAGE_REL_PPC_SECREL16    = 0x000F #  The 16-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage.
    const IMAGE_REL_PPC_REFHI       = 0x0010 #  The high 16 bits of the target’s 32-bit VA. This is used for the first instruction in a two-instruction sequence that loads a full address. This relocation must be immediately followed by a PAIR relocation whose SymbolTableIndex contains a signed 16-bit displacement that is added to the upper 16 bits that was taken from the location that is being relocated.
    const IMAGE_REL_PPC_REFLO       = 0x0011 #  The low 16 bits of the target’s VA.
    const IMAGE_REL_PPC_PAIR        = 0x0012 #  A relocation that is valid only when it immediately follows a REFHI or SECRELHI relocation. Its SymbolTableIndex contains a displacement and not an index into the symbol table.
    const IMAGE_REL_PPC_SECRELLO    = 0x0013 #  The low 16 bits of the 32-bit offset of the target from the beginning of its section.
    const IMAGE_REL_PPC_GPREL       = 0x0015 #  The 16-bit signed displacement of the target relative to the GP register.
    const IMAGE_REL_PPC_TOKEN       = 0x0016 #  The CLR token.
end

# # # i386 Relocations
@constants IMAGE_REL_I386 "IMAGE_REL_I386_" begin
    const IMAGE_REL_I386_ABSOLUTE = 0x0000 #  The relocation is ignored.
    const IMAGE_REL_I386_DIR16    = 0x0001 #  Not supported.
    const IMAGE_REL_I386_REL16    = 0x0002 #  Not supported.
    const IMAGE_REL_I386_DIR32    = 0x0006 #  The target’s 32-bit VA.
    const IMAGE_REL_I386_DIR32NB  = 0x0007 #  The target’s 32-bit RVA.
    const IMAGE_REL_I386_SEG12    = 0x0009 #  Not supported.
    const IMAGE_REL_I386_SECTION  = 0x000A #  The 16-bit section index of the section that contains the target. This is used to support debugging information.
    const IMAGE_REL_I386_SECREL   = 0x000B #  The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage.
    const IMAGE_REL_I386_TOKEN    = 0x000C #  The CLR token.
    const IMAGE_REL_I386_SECREL7  = 0x000D #  A 7-bit offset from the base of the section that contains the target.
    const IMAGE_REL_I386_REL32    = 0x0014 #  The 32-bit relative displacement of the target. This supports the x86 relative branch and call instructions.
end

# # # IA64 Relocation
@constants IMAGE_REL_IA64 "IMAGE_REL_IA64_" begin
    const IMAGE_REL_IA64_ABSOLUTE     = 0x0000 #  The relocation is ignored.
    const IMAGE_REL_IA64_IMM14        = 0x0001 #  The instruction relocation can be followed by an ADDEND relocation whose value is added to the target address before it is inserted into the specified slot in the IMM14 bundle. The relocation target must be absolute or the image must be fixed.
    const IMAGE_REL_IA64_IMM22        = 0x0002 #  The instruction relocation can be followed by an ADDEND relocation whose value is added to the target address before it is inserted into the specified slot in the IMM22 bundle. The relocation target must be absolute or the image must be fixed.
    const IMAGE_REL_IA64_IMM64        = 0x0003 #  The slot number of this relocation must be one (1). The relocation can be followed by an ADDEND relocation whose value is added to the target address before it is stored in all three slots of the IMM64 bundle.
    const IMAGE_REL_IA64_DIR32        = 0x0004 #  The target’s 32-bit VA. This is supported only for /LARGEADDRESSAWARE:NO images.
    const IMAGE_REL_IA64_DIR64        = 0x0005 #  The target’s 64-bit VA.
    const IMAGE_REL_IA64_PCREL21B     = 0x0006 #  The instruction is fixed up with the 25-bit relative displacement of the 16-bit aligned target. The low 4 bits of the displacement are zero and are not stored.
    const IMAGE_REL_IA64_PCREL21M     = 0x0007 #  The instruction is fixed up with the 25-bit relative displacement of the 16-bit aligned target. The low 4 bits of the displacement, which are zero, are not stored.
    const IMAGE_REL_IA64_PCREL21F     = 0x0008 #  The LSBs of this relocation’s offset must contain the slot number whereas the rest is the bundle address. The bundle is fixed up with the 25-bit relative displacement of the 16-bit aligned target. The low 4 bits of the displacement are zero and are not stored.
    const IMAGE_REL_IA64_GPREL22      = 0x0009 #  The instruction relocation can be followed by an ADDEND relocation whose value is added to the target address and then a 22-bit GP-relative offset that is calculated and applied to the GPREL22 bundle.
    const IMAGE_REL_IA64_LTOFF22      = 0x000A #  The instruction is fixed up with the 22-bit GP-relative offset to the target symbol’s literal table entry. The linker creates this literal table entry based on this relocation and the ADDEND relocation that might follow.
    const IMAGE_REL_IA64_SECTION      = 0x000B #  The 16-bit section index of the section contains the target. This is used to support debugging information.
    const IMAGE_REL_IA64_SECREL22     = 0x000C #  The instruction is fixed up with the 22-bit offset of the target from the beginning of its section. This relocation can be followed immediately by an ADDEND relocation, whose Value field contains the 32-bit unsigned offset of the target from the beginning of the section.
    const IMAGE_REL_IA64_SECREL64I    = 0x000D #  The slot number for this relocation must be one (1). The instruction is fixed up with the 64-bit offset of the target from the beginning of its section. This relocation can be followed immediately by an ADDEND relocation whose Value field contains the 32-bit unsigned offset of the target from the beginning of the section.
    const IMAGE_REL_IA64_SECREL32     = 0x000E #  The address of data to be fixed up with the 32-bit offset of the target from the beginning of its section.
    const IMAGE_REL_IA64_DIR32NB      = 0x0010 #  The target’s 32-bit RVA.
    const IMAGE_REL_IA64_SREL14       = 0x0011 #  This is applied to a signed 14-bit immediate that contains the difference between two relocatable targets. This is a declarative field for the linker that indicates that the compiler has already emitted this value.
    const IMAGE_REL_IA64_SREL22       = 0x0012 #  This is applied to a signed 22-bit immediate that contains the difference between two relocatable targets. This is a declarative field for the linker that indicates that the compiler has already emitted this value.
    const IMAGE_REL_IA64_SREL32       = 0x0013 #  This is applied to a signed 32-bit immediate that contains the difference between two relocatable values. This is a declarative field for the linker that indicates that the compiler has already emitted this value.
    const IMAGE_REL_IA64_UREL32       = 0x0014 #  This is applied to an unsigned 32-bit immediate that contains the difference between two relocatable values. This is a declarative field for the linker that indicates that the compiler has already emitted this value.
    const IMAGE_REL_IA64_PCREL60X     = 0x0015 #  A 60-bit PC-relative fixup that always stays as a BRL instruction of an MLX bundle.
    const IMAGE_REL_IA64_PCREL60B     = 0x0016 #  A 60-bit PC-relative fixup. If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MBB bundle with NOP.B in slot 1 and a 25-bit BR instruction (with the 4 lowest bits all zero and dropped) in slot 2.
    const IMAGE_REL_IA64_PCREL60F     = 0x0017 #  A 60-bit PC-relative fixup. If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MFB bundle with NOP.F in slot 1 and a 25-bit (4 lowest bits all zero and dropped) BR instruction in slot 2.
    const IMAGE_REL_IA64_PCREL60I     = 0x0018 #  A 60-bit PC-relative fixup. If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MIB bundle with NOP.I in slot 1 and a 25-bit (4 lowest bits all zero and dropped) BR instruction in slot 2.
    const IMAGE_REL_IA64_PCREL60M     = 0x0019 #  A 60-bit PC-relative fixup. If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MMB bundle with NOP.M in slot 1 and a 25-bit (4 lowest bits all zero and dropped) BR instruction in slot 2.
    const IMAGE_REL_IA64_IMMGPREL64   = 0x001a #  A 64-bit GP-relative fixup.
    const IMAGE_REL_IA64_TOKEN        = 0x001b #  A CLR token.
    const IMAGE_REL_IA64_GPREL32      = 0x001c #  A 32-bit GP-relative fixup.
    const IMAGE_REL_IA64_ADDEND       = 0x001F #  The relocation is valid only when it immediately follows one of the following relocations: IMM14, IMM22, IMM64, GPREL22, LTOFF22, LTOFF64, SECREL22, SECREL64I, or SECREL32. Its value contains the addend to apply to instructions within a bundle, not for data.
end

# # # MIPS Relocations
@constants IMAGE_REL_MIPS "IMAGE_REL_MIPS_" begin
    const IMAGE_REL_MIPS_ABSOLUTE     = 0x0000 #  The relocation is ignored.
    const IMAGE_REL_MIPS_REFHALF      = 0x0001 #  The high 16 bits of the target’s 32-bit VA.
    const IMAGE_REL_MIPS_REFWORD      = 0x0002 #  The target’s 32-bit VA.
    const IMAGE_REL_MIPS_JMPADDR      = 0x0003 #  The low 26 bits of the target’s VA. This supports the MIPS J and JAL instructions.
    const IMAGE_REL_MIPS_REFHI        = 0x0004 #  The high 16 bits of the target’s 32-bit VA. This is used for the first instruction in a two-instruction sequence that loads a full address. This relocation must be immediately followed by a PAIR relocation whose SymbolTableIndex contains a signed 16-bit displacement that is added to the upper 16 bits that are taken from the location that is being relocated.
    const IMAGE_REL_MIPS_REFLO        = 0x0005 #  The low 16 bits of the target’s VA.
    const IMAGE_REL_MIPS_GPREL        = 0x0006 #  A 16-bit signed displacement of the target relative to the GP register.
    const IMAGE_REL_MIPS_LITERAL      = 0x0007 #  The same as IMAGE_REL_MIPS_GPREL.
    const IMAGE_REL_MIPS_SECTION      = 0x000A #  The 16-bit section index of the section contains the target. This is used to support debugging information.
    const IMAGE_REL_MIPS_SECREL       = 0x000B #  The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage.
    const IMAGE_REL_MIPS_SECRELLO     = 0x000C #  The low 16 bits of the 32-bit offset of the target from the beginning of its section.
    const IMAGE_REL_MIPS_SECRELHI     = 0x000D #  The high 16 bits of the 32-bit offset of the target from the beginning of its section. An IMAGE_REL_MIPS_PAIR relocation must immediately follow this one. The SymbolTableIndex of the PAIR relocation contains a signed 16-bit displacement that is added to the upper 16 bits that are taken from the location that is being relocated.
    const IMAGE_REL_MIPS_JMPADDR16    = 0x0010 #  The low 26 bits of the target’s VA. This supports the MIPS16 JAL instruction.
    const IMAGE_REL_MIPS_REFWORDNB    = 0x0022 #  The target’s 32-bit RVA.
    const IMAGE_REL_MIPS_PAIR         = 0x0025 #  The relocation is valid only when it immediately follows a REFHI or SECRELHI relocation. Its SymbolTableIndex contains a displacement and not an index into the symbol table.
end

# # # M32R Relocations
@constants IMAGE_REL_M32R "IMAGE_REL_M32R_" begin
    const IMAGE_REL_M32R_ABSOLUTE     = 0x0000 #  The relocation is ignored.
    const IMAGE_REL_M32R_ADDR32       = 0x0001 #  The target’s 32-bit VA.
    const IMAGE_REL_M32R_ADDR32NB     = 0x0002 #  The target’s 32-bit RVA.
    const IMAGE_REL_M32R_ADDR24       = 0x0003 #  The target’s 24-bit VA.
    const IMAGE_REL_M32R_GPREL16      = 0x0004 #  The target’s 16-bit offset from the GP register.
    const IMAGE_REL_M32R_PCREL24      = 0x0005 #  The target’s 24-bit offset from the program counter (PC), shifted left by 2 bits and sign-extended
    const IMAGE_REL_M32R_PCREL16      = 0x0006 #  The target’s 16-bit offset from the PC, shifted left by 2 bits and sign-extended
    const IMAGE_REL_M32R_PCREL8       = 0x0007 #  The target’s 8-bit offset from the PC, shifted left by 2 bits and sign-extended
    const IMAGE_REL_M32R_REFHALF      = 0x0008 #  The 16 MSBs of the target VA.
    const IMAGE_REL_M32R_REFHI        = 0x0009 #  The 16 MSBs of the target VA, adjusted for LSB sign extension. This is used for the first instruction in a two-instruction sequence that loads a full 32-bit address. This relocation must be immediately followed by a PAIR relocation whose SymbolTableIndex contains a signed 16-bit displacement that is added to the upper 16 bits that are taken from the location that is being relocated.
    const IMAGE_REL_M32R_REFLO        = 0x000A #  The 16 LSBs of the target VA.
    const IMAGE_REL_M32R_PAIR         = 0x000B #  The relocation must follow the REFHI relocation. Its SymbolTableIndex contains a displacement and not an index into the symbol table.
    const IMAGE_REL_M32R_SECTION      = 0x000C #  The 16-bit section index of the section that contains the target. This is used to support debugging information.
    const IMAGE_REL_M32R_SECREL       = 0x000D #  The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage.
    const IMAGE_REL_M32R_TOKEN        = 0x000E #  The CLR token.
end

const MachineRelocationMap = Dict(
    IMAGE_FILE_MACHINE_IA64 => IMAGE_REL_IA64,
    IMAGE_FILE_MACHINE_MIPS16 => IMAGE_REL_MIPS,
    IMAGE_FILE_MACHINE_MIPSFPU16 => IMAGE_REL_MIPS,
    IMAGE_FILE_MACHINE_MIPSFPU => IMAGE_REL_MIPS,
    IMAGE_FILE_MACHINE_M32R => IMAGE_REL_M32R,
    IMAGE_FILE_MACHINE_ARM64 => IMAGE_REL_ARM64,
    IMAGE_FILE_MACHINE_ARM => IMAGE_REL_ARM,
    IMAGE_FILE_MACHINE_SH3 => IMAGE_REL_SUPERH,
    IMAGE_FILE_MACHINE_SH3DSP => IMAGE_REL_SUPERH,
    IMAGE_FILE_MACHINE_SH4 => IMAGE_REL_SUPERH,
    IMAGE_FILE_MACHINE_SH5 => IMAGE_REL_SUPERH,
    IMAGE_FILE_MACHINE_AMD64 => IMAGE_REL_AMD64,
    IMAGE_FILE_MACHINE_POWERPC => IMAGE_REL_PPC,
    IMAGE_FILE_MACHINE_POWERPCFP => IMAGE_REL_PPC,
    IMAGE_FILE_MACHINE_AMD64 => IMAGE_REL_AMD64,
    IMAGE_FILE_MACHINE_I386 => IMAGE_REL_I386
)

# # # Type representations
const IMAGE_SYM_TYPE_NULL         = 0 # No type information or unknown base type. Microsoft tools use this setting
const IMAGE_SYM_TYPE_VOID         = 1 # No valid type; used with void pointers and functions
const IMAGE_SYM_TYPE_CHAR         = 2 # A character (signed byte)
const IMAGE_SYM_TYPE_SHORT        = 3 # A 2-byte signed integer
const IMAGE_SYM_TYPE_INT          = 4 # A natural integer type (normally 4 bytes in Windows)
const IMAGE_SYM_TYPE_LONG         = 5 # A 4-byte signed integer
const IMAGE_SYM_TYPE_FLOAT        = 6 # A 4-byte floating-point number
const IMAGE_SYM_TYPE_DOUBLE       = 7 # An 8-byte floating-point number
const IMAGE_SYM_TYPE_STRUCT       = 8 # A structure
const IMAGE_SYM_TYPE_UNION        = 9 # A union
const IMAGE_SYM_TYPE_ENUM         = 10 #  An enumerated type
const IMAGE_SYM_TYPE_MOE          = 11 #  A member of enumeration (a specific value)
const IMAGE_SYM_TYPE_BYTE         = 12 #  A byte; unsigned 1-byte integer
const IMAGE_SYM_TYPE_WORD         = 13 #  A word; unsigned 2-byte integer
const IMAGE_SYM_TYPE_UINT         = 14 #  An unsigned integer of natural size (normally, 4 bytes)
const IMAGE_SYM_TYPE_DWORD        = 15 #  An unsigned 4-byte integer

const IMAGE_SYM_DTYPE_NULL        = 0 #  No derived type; the symbol is a simple scalar variable.
const IMAGE_SYM_DTYPE_POINTER     = 1 #  The symbol is a pointer to base type.
const IMAGE_SYM_DTYPE_FUNCTION    = 2 #  The symbol is a function that returns a base type.
const IMAGE_SYM_DTYPE_ARRAY       = 3 #  The symbol is an array of base type.

# # # Storage Class
@constants IMAGE_SYM_CLASS "IMAGE_SYM_CLASS_" begin
    const IMAGE_SYM_CLASS_END_OF_FUNCTION   = 0xFF   # A special symbol that represents the end of function, for debugging purposes.
    const IMAGE_SYM_CLASS_NULL              = 0      # No assigned storage class.
    const IMAGE_SYM_CLASS_AUTOMATIC         = 1      # The automatic (stack) variable. The Value field specifies the stack frame offset.
    const IMAGE_SYM_CLASS_EXTERNAL          = 2      # A value that Microsoft tools use for external symbols. The Value field indicates the size if the section number is IMAGE_SYM_UNDEFINED (0). If the section number is not zero, then the Value field specifies the offset within the section.
    const IMAGE_SYM_CLASS_STATIC            = 3      # The offset of the symbol within the section. If the Value field is zero, then the symbol represents a section name.
    const IMAGE_SYM_CLASS_REGISTER          = 4      # A register variable. The Value field specifies the register number.
    const IMAGE_SYM_CLASS_EXTERNAL_DEF      = 5      # A symbol that is defined externally.
    const IMAGE_SYM_CLASS_LABEL             = 6      # A code label that is defined within the module. The Value field specifies the offset of the symbol within the section.
    const IMAGE_SYM_CLASS_UNDEFINED_LABEL   = 7      # A reference to a code label that is not defined.
    const IMAGE_SYM_CLASS_MEMBER_OF_STRUCT  = 8      # The structure member. The Value field specifies the nth member.
    const IMAGE_SYM_CLASS_ARGUMENT          = 9      # A formal argument (parameter) of a function. The Value field specifies the nth argument.
    const IMAGE_SYM_CLASS_STRUCT_TAG        = 10     #   The structure tag-name entry.
    const IMAGE_SYM_CLASS_MEMBER_OF_UNION   = 11     #   A union member. The Value field specifies the nth member.
    const IMAGE_SYM_CLASS_UNION_TAG         = 12     #   The Union tag-name entry.
    const IMAGE_SYM_CLASS_TYPE_DEFINITION   = 13     #   A Typedef entry.
    const IMAGE_SYM_CLASS_UNDEFINED_STATIC  = 14     #   A static data declaration.
    const IMAGE_SYM_CLASS_ENUM_TAG          = 15     #   An enumerated type tagname entry.
    const IMAGE_SYM_CLASS_MEMBER_OF_ENUM    = 16     #   A member of an enumeration. The Value field specifies the nth member.
    const IMAGE_SYM_CLASS_REGISTER_PARAM    = 17     #   A register parameter.
    const IMAGE_SYM_CLASS_BIT_FIELD         = 18     #   A bit-field reference. The Value field specifies the nth bit in the bit field.
    const IMAGE_SYM_CLASS_BLOCK             = 100    #    A .bb (beginning of block) or .eb (end of block) record. The Value field is the relocatable address of the code location.
    const IMAGE_SYM_CLASS_FUNCTION          = 101    # A value that Microsoft tools use for symbol records that define the extent of a function: begin function (.bf), end function (.ef), and lines in function (.lf). For .lf records, the Value field gives the number of source lines in the function. For .ef records, the Value field gives the size of the function code.
    const IMAGE_SYM_CLASS_END_OF_STRUCT     = 102    # An end-of-structure entry.
    const IMAGE_SYM_CLASS_FILE              = 103    # A value that Microsoft tools, as well as traditional COFF format, use for the source-file symbol record. The symbol is followed by auxiliary records that name the file.
    const IMAGE_SYM_CLASS_SECTION           = 104    # A definition of a section (Microsoft tools use STATIC storage class instead).
    const IMAGE_SYM_CLASS_WEAK_EXTERNAL     = 105    # A weak external. For more information, see section 5.5.3, “Auxiliary Format 3: Weak Externals.”
    const IMAGE_SYM_CLASS_CLR_TOKEN         = 107    # A CLR token symbol. The name is an ASCII string that consists of the hexadecimal value of the token. For more information, see section 5.5.7, “CLR Token Definition (Object Only).”
end

# # # COMDAT Section
const IMAGE_COMDAT_SELECT_NODUPLICATES  = 1 #   If this symbol is already defined, the linker issues a “multiply defined symbol” error.
const IMAGE_COMDAT_SELECT_ANY           = 2 #   Any section that defines the same COMDAT symbol can be linked; the rest are removed.
const IMAGE_COMDAT_SELECT_SAME_SIZE     = 3 #   The linker chooses an arbitrary section among the definitions for this symbol. If all definitions are not the same size, a “multiply defined symbol” error is issued.
const IMAGE_COMDAT_SELECT_EXACT_MATCH   = 4 #   The linker chooses an arbitrary section among the definitions for this symbol. If all definitions do not match exactly, a “multiply defined symbol” error is issued.
const IMAGE_COMDAT_SELECT_ASSOCIATIVE   = 5 #   The section is linked if a certain other COMDAT section is linked. This other section is indicated by the Number field of the auxiliary symbol record for the section definition. This setting is useful for definitions that have components in multiple sections (for example, code in one and data in another), but where all must be linked or discarded as a set. The other section with which this section is associated must be a COMDAT section; it cannot be another associative COMDAT section (that is, the other section cannot have IMAGE_COMDAT_SELECT_ASSOCIATIVE set).
const IMAGE_COMDAT_SELECT_LARGEST       = 6 #   The linker chooses the largest definition from among all of the definitions for this symbol. If multiple definitions have this size, the choice between them is arbitrary.

# # # Win Cert
const WIN_CERT_REVISION_1_0 = 0x100  # Version 1, legacy version of the Win_Certificate structure. It is supported only for purposes of verifying legacy Authenticode signatures
const WIN_CERT_REVISION_2_0 = 0x200  # Version 2 is the current version of the Win_Certificate structure.

const WIN_CERT_TYPE_X509                = 0x0001 # b_certificate contains an X.509 Certificate  (Not Supported)
const WIN_CERT_TYPE_PKCS_SIGNED_DATA    = 0x0002 # b_certificate contains a PKCS#7 SignedData structure
const WIN_CERT_TYPE_RESERVED_1          = 0x0003 # Reserved
const WIN_CERT_TYPE_TS_STACK_SIGNED     = 0x0004 # Terminal Server Protocol Stack Certificate signing (Not Supported)

# # # Debug Type
const IMAGE_DEBUG_TYPE_UNKNOWN          = 0  # An unknown value that is ignored by all tools.
const IMAGE_DEBUG_TYPE_COFF             = 1  # The COFF debug information (line numbers, symbol table, and string table). This type of debug information is also pointed to by fields in the file headers.
const IMAGE_DEBUG_TYPE_CODEVIEW         = 2  # The Visual C++ debug information.
const IMAGE_DEBUG_TYPE_FPO              = 3  # The frame pointer omission (FPO) information. This information tells the debugger how to interpret nonstandard stack frames, which use the EBP register for a purpose other than as a frame pointer.
const IMAGE_DEBUG_TYPE_MISC             = 4  # The location of DBG file.
const IMAGE_DEBUG_TYPE_EXCEPTION        = 5  # A copy of .pdata section.
const IMAGE_DEBUG_TYPE_FIXUP            = 6  # Reserved.
const IMAGE_DEBUG_TYPE_OMAP_TO_SRC      = 7  # The mapping from an RVA in image to an RVA in source image.
const IMAGE_DEBUG_TYPE_OMAP_FROM_SRC    = 8  # The mapping from an RVA in source image to an RVA in image.
const IMAGE_DEBUG_TYPE_BORLAND          = 9  # Reserved for Borland.
const IMAGE_DEBUG_TYPE_RESERVED10       = 10 # Reserved.
const IMAGE_DEBUG_TYPE_CLSID            = 11 # Reserved.

# # # Base Relocations
const IMAGE_REL_BASED_ABSOLUTE          = 0  # The base relocation is skipped. This type can be used to pad a block.
const IMAGE_REL_BASED_HIGH              = 1  # The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the high value of a 32-bit word.
const IMAGE_REL_BASED_LOW               = 2  # The base relocation adds the low 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the low half of a 32-bit word.
const IMAGE_REL_BASED_HIGHLOW           = 3  # The base relocation applies all 32 bits of the difference to the 32-bit field at offset.
const IMAGE_REL_BASED_HIGHADJ           = 4  # The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the high value of a 32-bit word. The low 16 bits of the 32-bit value are stored in the 16-bit word that follows this base relocation. This means that this base relocation occupies two slots.
const IMAGE_REL_BASED_MIPS_JMPADDR      = 5  # For MIPS machine types, the base relocation applies to a MIPS jump instruction.
const IMAGE_REL_BASED_ARM_MOV32A        = 5  # For ARM machine types, the base relocation applies the difference to the 32-bit value encoded in the immediate fields of a contiguous MOVW+MOVT pair in ARM mode at offset.
#                                       = 6  # Reserved, must be zero.
const IMAGE_REL_BASED_ARM_MOV32T        = 7  # The base relocation applies the difference to the 32-bit value encoded in the immediate fields of a contiguous MOVW+MOVT pair in Thumb mode at offset.
const IMAGE_REL_BASED_MIPS_JMPADDR16    = 9  # The base relocation applies to a MIPS16 jump instruction.
const IMAGE_REL_BASED_DIR64             = 10 #The base relocation applies the difference to the 64-bit field at offset.


text:
module RelSaturate
using Hecke

Hecke.add_verbose_scope(:Saturate)

export saturate!

function mod_p(R::Vector{FacElem{nf_elem, AnticNumberField}}, Q::NfOrdIdl, p::Int, T::Hecke.GaloisField, D::Vector, cached::Bool)
  Zk = order(Q)
  F, mF = Hecke.ResidueFieldSmallDegree1(Zk, Q)
  mF1 = Hecke.extend_easy(mF, number_field(Zk))
  oF = Int(size(F))-1
  @assert iszero(oF % p)
  pp, e = Hecke.ppio(oF, p)
  #We now want the discrete logarithm of the images of the elements of R in F
  #We don't need the full group, just the quotient by p
  #We compute a generator and cache the powers in dl
  #Then we will compute the discrete logarithms by checking the values in dl
  dl = Dict{Hecke.Nemo.gfp_elem, Int}()
  dl[F(1)] = 0
  exp_to_test = divexact(pp, p)
  x = rand(F)
  while true
    if iszero(x)
      continue
    end
    x = x^e
    if !isone(x^exp_to_test)
      break
    end
    x = rand(F)
  end
  y = x
  for i = 1:pp-1
    dl[y] = i
    y *= x
  end
  return matrix(T, 1, length(R), Int[dl[image(mF1, R[i], D[i], cached, pp)^e] % p for i in 1:length(R)])
end

#= idea
  let G = <a_1, ... a_n> and p a prime
    for prime ideals Q s.th. N(Q) = 1 (p) we do
        log_Q(a_i)
        nullspace() to get comb. that looks locally like an p-th power
        change a_i
=#

function _mod_exponents(a::FacElem{nf_elem, AnticNumberField}, p::Int)
  pU = UInt(p)
  a1 = copy(a.fac)
  for i = a1.idxfloor:length(a1.vals)
    if a1.slots[i] == 0x01
      new_e = Hecke.fmpz_mod_ui(a1.vals[i], pU)
      if iszero(new_e)
        a1.slots[i] = 0x00
        a1.count -= 1
      else
        a1.vals[i] = new_e
      end
    end
  end
  if isempty(a1)
    #TODO: If this happens, I already have a square!
    #Should take care of this before starting with this part of code.
    K = base_ring(parent(a))
    return FacElem(one(K))
  end
  return FacElem(a1)
end

function relations(c::Hecke.ClassGrpCtx)
  v = Vector{FacElem{nf_elem, AnticNumberField}}(undef, length(c.R_gen) + length(c.R_rel))
  for i = 1:length(c.R_gen)
    if typeof(c.R_gen[i]) == nf_elem
      v[i] = FacElem(c.R_gen[i])
    else
      v[i] = c.R_gen[i]
    end
  end
  for i = 1:length(c.R_rel)
    if typeof(c.R_rel[i]) == nf_elem
      v[i+length(c.R_gen)] = FacElem(c.R_rel[i])
    else
      v[i+length(c.R_gen)] = c.R_rel[i]
    end
  end
  return v
end

function relations_mod_powers(c::Hecke.ClassGrpCtx, p::Int)
  v = Vector{FacElem{nf_elem, AnticNumberField}}(undef, length(c.R_gen) + length(c.R_rel))
  for i = 1:length(c.R_gen)
    if typeof(c.R_gen[i]) == nf_elem
      v[i] = FacElem(c.R_gen[i])
    else
      v[i] = _mod_exponents(c.R_gen[i], p)
    end
  end
  for i = 1:length(c.R_rel)
    if typeof(c.R_rel[i]) == nf_elem
      v[i+length(c.R_gen)] = FacElem(c.R_rel[i])
    else
      v[i+length(c.R_gen)] = _mod_exponents(c.R_rel[i], p)
    end
  end
  return v
end

function relations_matrix(c::Hecke.ClassGrpCtx)
  v = Vector{SRow{fmpz}}(undef, length(c.R_gen) + length(c.R_rel))
  for i = 1:length(c.R_gen)
    v[i] = c.M.bas_gens[i]
  end
  for i = 1:length(c.R_rel)
    v[i+length(c.R_gen)] = c.M.rel_gens[i]
  end
  return v
end

function compute_candidates_for_saturate(c::Hecke.ClassGrpCtx, p::Int, stable::Float64 = 1.5)
  ZK = order(c.FB.ideals[1])
  K = nf(ZK)
  zeta, sT = Hecke.torsion_units_gen_order(K)

  @vprint :Saturate 3 "Reducing exponents\n"
  R = relations_mod_powers(c, p)
  if gcd(sT, p) != 1 && !(hash(zeta) in c.RS) # && order is promising...
    push!(R, FacElem(zeta))
  end
  @vprint :Saturate 3 "Done\n"

  T = GF(p, cached = false)
  cA = length(R)
  A = identity_matrix(T, cA)

  S = Hecke.PrimesSet(Hecke.p_start, -1, p, 1)

  D = Vector{Vector{gfp_poly}}(undef, length(R))
  for i in 1:length(R)
    D[i] = Vector{gfp_poly}(undef, length(R[i].fac))
  end
  dK = discriminant(ZK)
  threshold = stable*ncols(A)

  i = 1
  for q in S
    @vprint :Saturate 3 "Finding primes for saturation: $i/$(threshold)\n"
    if isdefining_polynomial_nice(K) && isindex_divisor(ZK, q)
      continue
    end
    if iszero(dK % q)
      continue
    end
    @vtime :Saturate 3 lq = prime_decomposition(ZK, q, 1)
    if isempty(lq)
      continue
    end

    first_prime = true
    for Q in lq
      try
        if first_prime
          @vtime :Saturate 3 z = mod_p(R, Q[1], Int(p), T, D, false)
          first_prime = false
        else
          @vtime :Saturate 3 z = mod_p(R, Q[1], Int(p), T, D, true)
        end
        z = z*A
        rrz, z = nullspace(z)
        if iszero(rrz)
          return zero_matrix(FlintZZ, 0, length(R))
        end
        A = A*sub(z, 1:nrows(z), 1:rrz)
        if cA == ncols(A)
          i += 1
        else
          i = 0
          cA = ncols(A)
        end
        if i > threshold
          break
        end
      catch e
        if !isa(e, Hecke.BadPrime)
          rethrow(e)
        end
      end
    end
    if i > threshold
      break
    end
  end
  return Hecke.lift_nonsymmetric(A)
end

function compute_candidates_for_saturate1(c::Hecke.ClassGrpCtx, p::Int, stable::Float64 = 1.5)
  ZK = order(c.FB.ideals[1])
  K = nf(ZK)
  zeta, sT = Hecke.torsion_units_gen_order(K)

  @vprint :Saturate 3 "Reducing exponents\n"
  R = relations_mod_powers(c, p)
  if gcd(sT, p) != 1 && !(hash(zeta) in c.RS) # && order is promising...
    push!(R, FacElem(zeta))
  end
  @vprint :Saturate 3 "Done\n"

  T = GF(p, cached = false)
  cA = length(R)
  A = identity_matrix(T, cA)

  S = Hecke.PrimesSet(Hecke.p_start, -1, p, 1)

  dK = discriminant(ZK)
  threshold = stable*ncols(A)

  f = K.pol
  att = 1

  #evals will contain at the same time all the evaluations at the prime ideals
  #of every element in R
  evals = Vector{Vector{Hecke.gfp_elem}}(undef, length(R))
  for i = 1:length(evals)
    evals[i] = Vector{Hecke.gfp_elem}(undef, degree(K))
  end

  evaluateat = Vector{Hecke.gfp_elem}(undef, degree(K))
  for q in S
    @vprint :Saturate 3 "Finding primes for saturation: $att/$(threshold)\n"
    if isdefining_polynomial_nice(K) && isindex_divisor(ZK, q)
      continue
    end
    if iszero(dK % q)
      continue
    end

    F = GF(q, cached = false)
    Fx, x = PolynomialRing(F, "x", cached = false)
    fF = Fx(f)
    g = gcd(fF, powmod(x, q, fF)-x)
    if isone(g)
      continue
    end
    facts = Hecke.factor_equal_deg(g, 1)
    lfacts = length(facts)
    #I take the evaluation points...
    for i = 1:lfacts
      evaluateat[i] = -coeff(facts[i], 0)
    end

    #Now, I evaluate the elements.
    bad_prime = false
    t = Fx()
    for i = 1:length(R)
      isfirst = true
      for (k, v) in R[i]
        if !iscoprime(denominator(k), q)
          bad_prime = true
          break
        end
        Hecke.nf_elem_to_gfp_poly!(t, k)
        #evaluations = evaluate(t, evaluateat[1:lfacts])
        for j = 1:lfacts
          ev_t = evaluate(t, evaluateat[j])#evaluations[j]
          if isone(ev_t)
            continue
          end
          if isfirst
            if isone(v)
              evals[i][j] = ev_t
            else
              evals[i][j] = ev_t^Int(v)
            end
          else
            if isone(v)
              evals[i][j] = mul!(evals[i][j], evals[i][j], ev_t)
            else
              evals[i][j] = mul!(evals[i][j], evals[i][j], ev_t^Int(v))
            end
          end
        end
        isfirst = false
      end
      if bad_prime
        break
      end
    end
    if bad_prime
      continue
    end
    #Prepare the disc log dictionary
    disc_log = Dict{Hecke.gfp_elem, Hecke.gfp_elem}()
    disc_log[F(1)] = zero(T)
    pp, e = ppio(q-1, p)
    exp_to_test = divexact(pp, p)
    elF = rand(F)
    while true
      if iszero(elF)
        continue
      end
      elF = elF^e
      if !isone(elF^exp_to_test)
        break
      end
      elF = rand(F)
    end
    y = elF
    for i = 1:pp-1
      disc_log[y] = T(i)
      y *= elF
    end
    #The disc log dictionary is ready. Now we need the subspace.
    for i = 1:lfacts
      z = matrix(T, 1, length(R), Hecke.gfp_elem[disc_log[evals[j][i]^e] for j = 1:length(R)])
      z = z*A
      rrz, z = nullspace(z)
      if iszero(rrz)
        return zero_matrix(FlintZZ, 0, length(R))
      end
      A = A*sub(z, 1:nrows(z), 1:rrz)
      if cA == ncols(A)
        att += 1
      else
        att = 0
        cA = ncols(A)
      end
      if att > threshold
        break
      end
    end
    if att > threshold
      break
    end
  end
  return Hecke.lift_nonsymmetric(A)
end

function _get_element(e, R, R_mat, zeta, i)
  K = parent(zeta)
  a = FacElem(K(1))
  fac_a = SRow(FlintZZ)
  for j = 1:length(R)
    if !iszero(e[j, i])
      mul!(a, a, R[j]^e[j, i])
      fac_a += e[j, i] * R_mat[j]
    end
  end
  if nrows(e) > length(R) && !iszero(e[nrows(e), i])
    @assert length(R) + 1 == nrows(e)
    Hecke.add_to_key!(a.fac, zeta, e[nrows(e), i])
  end
  return a, fac_a
end

function saturate!(d::Hecke.ClassGrpCtx, U::Hecke.UnitGrpCtx, n::Int, stable::Float64 = 3.5; use_orbit::Bool = false, easy_root::Bool = false, use_LLL::Bool = false)
  @assert isprime(n)
  K = nf(d)
  @vprint :Saturate 1 "Simplifying the context\n"
  @vtime :Saturate 1 c = simplify(d, U, n, use_LLL = use_LLL)
  success = false
  restart = false
  while true
    if success
      @vprint :Saturate 1 "Simplifying the context\n"
      @vtime :Saturate 1 c = simplify(d, U, n, use_LLL = use_LLL)
    end
    @vprint :Saturate 1 "Computing candidates for the saturation\n"
    @vtime :Saturate 1 e = compute_candidates_for_saturate(c, n, stable)
    if nrows(e) == 0
      @vprint :Saturate 1 "sat yielded nothing new at $stable, $success \n"
      return success
    end
    zeta = Hecke.torsion_units_generator(K)
    @vprint :Saturate 1 "(Hopefully) enlarging by $(ncols(e)) elements\n"

    rels_added = sparse_matrix(FlintZZ)
    R = relations(c)
    R_mat = relations_matrix(c)
    wasted = false
    for i = ncols(e):-1:1
      a, fac_a = _get_element(e, R, R_mat, zeta, i)
      if !iszero(fac_a) && nrows(rels_added) > 0
        candidate_rel = divexact(fac_a, n)
        red_candidate = reduce(rels_added, candidate_rel)
        if iszero(red_candidate)
          @vprint :Saturate 1 "Ignore this relation! \n"
          continue
        end
      end

      decom = Dict{NfOrdIdl, fmpz}((c.FB.ideals[k], v) for (k, v) = fac_a)
      @vprint :Saturate 1 "Testing if element is an n-th power\n"
      @vtime :Saturate 1 fl, x = ispower(a, n, decom = decom, easy = easy_root)
      if fl
        @vprint :Saturate 1  "The element is an n-th power\n"
        success = true
        fac_a = divexact(fac_a, n)
        if iszero(fac_a)
          #In this case, the element we have found is a unit and
          #we want to make sure it is used
          #find units can be randomised...
          #maybe that should also be addressed elsewhere
          @vprint :Saturate 1  "The new element is a unit\n"

          if use_orbit
            auts_action = Hecke._get_autos_from_ctx(d)
            for s = 1:length(auts_action)
              new_u = auts_action[s][1](x)
              Hecke._add_dependent_unit!(U, new_u)
            end
            restart = true
            break
          else
            Hecke._add_dependent_unit!(U, x)
          end
        else
          @vprint :Saturate 1  "The new element gives a relation\n"
          Hecke.class_group_add_relation(d, x, fac_a)
          if use_orbit
            #We add the relation to the matrix and compute the snf
            auts_action = Hecke._get_autos_from_ctx(d)
            for s = 1:length(auts_action)
              push!(rels_added, Hecke.permute_row(fac_a, auts_action[s][2]))
            end
            rels_added = hnf(rels_added, truncate = true)
            restart = true
          end
        end
      else
        @vprint :Saturate 1  "The element is not an n-th power\n"
        wasted = true
        break
      end
    end
    if restart
      restart = false
      continue
    elseif wasted
      stable *= 2
    else
      @vprint :Saturate  1 "sat success at $(stable)\n"
      return success
    end
  end
end

function simplify(c::Hecke.ClassGrpCtx, U::Hecke.UnitGrpCtx, cp::Int = 0; use_LLL::Bool = false)

  d = Hecke.class_group_init(c.FB, SMat{fmpz}, add_rels = false)
  Hecke.module_trafo_assure(c.M)
  trafos = c.M.trafo
  R = relations(c)
  R_mat = relations_matrix(c)

  new_rels = Vector{FacElem{nf_elem, AnticNumberField}}()
  vals_new_rels = Vector{SRow{fmpz}}()
  @vprint :Saturate 1 "Computing rels...\n"
  for i=1:length(c.FB.ideals)
    if cp != 0 && isone(c.M.basis.rows[i].values[1])
      continue
    end
    @assert all(x -> x > 0, c.M.basis.rows[i].values)
    x = zeros(fmpz, length(R))
    x[i] = 1
    for j in length(trafos):-1:1
      Hecke.apply_right!(x, trafos[j])
    end
    y = R[1]^x[1]
    for j = 2:length(R)
      if !iszero(x[j])
        mul!(y, y, R[j]^x[j])
      end
    end
    push!(new_rels, y)
    push!(vals_new_rels, deepcopy(c.M.basis.rows[i]))
  end
  if use_LLL && !isempty(new_rels)
    M = sparse_matrix(FlintZZ)
    for x in vals_new_rels
      push!(M, x)
    end
    M1 = matrix(M)
    M2, T = lll_with_transform(M1)
    transpose!(T, T)
    new_rels = transform(new_rels, T)
    for i = 1:length(vals_new_rels)
      vals_new_rels[i] = sparse_row(view(M2, i:i, 1:ncols(M2)))
    end
  end
  @vprint :Saturate 1 "Reducing rels...\n"
  if !isempty(new_rels)
    @vtime :Saturate 1 new_rels = Hecke.reduce_mod_units(new_rels, U)
    for i = 1:length(new_rels)
      fl = Hecke.class_group_add_relation(d, new_rels[i], vals_new_rels[i])
      @assert fl
    end
  end
  for i=1:length(U.units)
    Hecke.class_group_add_relation(d, U.units[i], SRow(FlintZZ))
  end
  return d
end

end


text:
export ISS

mutable struct ISS{T<:AbstractFloat} <: Environment
  worldAABBmin::Vector{T}
  worldAABBmax::Vector{T}
  keepin_zones::Vector
  keepout_zones::Vector
  obstacle_set::Vector
end
function ISS{T}() where T
  keepin_zones = Vector{HyperRectangle}(0)
  vars = matread(joinpath(ENV["GUSTO"], "environment","iss.mat"))
  for zone in vars["keepin_zones"]
    push!(keepin_zones,
      HyperRectangle(Vec3f0(zone["corner1"]),Vec3f0(zone["corner2"]-zone["corner1"])))
  end

  worldAABBmin = Inf*ones(T,3)
  worldAABBmax = -Inf*ones(T,3)
  for zone in keepin_zones
    corner1,corner2 = zone.origin, zone.origin+zone.widths
    zone_min = [min(corner1[i], corner2[i]) for i in 1:3]
    worldAABBmin[worldAABBmin .> zone_min] = zone_min[worldAABBmin .> zone_min]
    zone_max = [max(corner1[i], corner2[i]) for i in 1:3]
    worldAABBmax[worldAABBmax .< zone_max] = zone_max[worldAABBmax .< zone_max]
  end

  keepout_zones = Vector{GeometryTypes.GeometryPrimitive}(0)
  obstacle_set = Vector{GeometryTypes.GeometryPrimitive}(0)

  return ISS{T}(worldAABBmin, worldAABBmax, keepin_zones, keepout_zones, obstacle_set)
end
ISS(::Type{T} = Float64; kwargs...) where {T} = ISS{T}(; kwargs...)

function update_aabb!(env::ISS)
  for zone in env.keepin_zones
    corner1,corner2 = zone.origin, zone.origin+zone.widths
    zone_min = [min(corner1[i], corner2[i]) for i in 1:3]
    env.worldAABBmin[env.worldAABBmin .> zone_min] = zone_min[env.worldAABBmin .> zone_min]
    zone_max = [max(corner1[i], corner2[i]) for i in 1:3]
    env.worldAABBmax[env.worldAABBmax .< zone_max] = zone_max[env.worldAABBmax .< zone_max]
  end
  warn("Overriding collision world in env()")
end


text:
@testset "util.iterator" begin

@testset "combinations" begin
    @test length(collect(combinations(10, 1))) == 10
    @test length(collect(combinations(10, 2))) == 45
    @test length(collect(combinations(10, 3))) == 120
    @test length(collect(combinations(10, 8))) == 45
    @test length(collect(combinations(10, 9))) == 10
    @test length(collect(combinations(10, 10))) == 1
    @test length(collect(combinations(10, 0))) == 1
    @test_throws DomainError combinations(10, -1)
    @test_throws ErrorException combinations(10, 11)
    @test_throws ErrorException combinations(0, 1)
    @test_throws MethodError combinations(10, 1.5)
end

@testset "sortstablemax" begin
    @test sortstablemax([1, 4, 2, 7, 5]) == 7
    @test sortstablemax([8:10, 1:3, [], 4:23, 1:9], by=length) == 4:23
    @test sortstablemax([8:10, 1:3, 3:22, 4:23, 1:9], by=length) == 3:22
    @test_throws ErrorException sortstablemax([])
    @test sortstablemax([], init=0) == 0
end

@testset "sortstablemin" begin
    @test sortstablemin([1, 4, 2, 7, 5]) == 1
    @test sortstablemin([8:10, 1:3, [], 4:23, 1:9], by=length) == []
    @test sortstablemin([8:10, 1:3, 3:22, 4:23, 1:9], by=length) == 8:10
    @test_throws ErrorException sortstablemin([])
    @test sortstablemin([], init=0) == 0
end
end # util.iterator


text:
#!/usr/bin/env julia

import Celeste.ParallelRun: BoundingBox, get_overlapping_fields
import Celeste.SDSSIO: RunCamcolField

# Lists all Run-Camcol-Field triplets that overlap with a specified
# bounding box. Output is in a format that can be piped to make, with the
# makefile in this directory, e.g.
#
#    ./list_rcfs.jl -999 999 -999 999 | sort -R | xargs -P 32 -n 1 make

if length(ARGS) == 4
    box = BoundingBox(ARGS...)
    rcfs = get_overlapping_fields(box, dirname(ENV["FIELD_EXTENTS"]))

    for rcf in rcfs
        println("RUN=$(rcf.run) CAMCOL=$(rcf.camcol) FIELD=$(rcf.field)")
    end
else
    println("Usage:\n    list_rcfs.jl <ramin> <ramax> <decmin> <decmax>")
end


text:
module ProfileVega

import FlameGraphs, VegaLite, LeftChildRightSiblingTrees, Profile
using VegaLite: save
using LeftChildRightSiblingTrees: Node, isleaf, prunebranch!

include("options.jl")

const global _options = Options(800, 400, false, true)

include("view.jl")
include("diffview.jl")

export @profview, @profbase, @profdiffview, save

end # module

max_stars_repo_name: davidanthoff/ProfileVega

max_issues_repo_name: davidanthoff/ProfileVega

max_forks_repo_name: davidanthoff/ProfileVega


text:
using LinAlgTools
using Documenter

DocMeta.setdocmeta!(LinAlgTools, :DocTestSetup, :(using LinAlgTools); recursive=true)

makedocs(;
    modules=[LinAlgTools],
    authors="Jeremie Knuesel <knuesel@gmail.com> and contributors",
    repo="https://github.com/knuesel/LinAlgTools.jl/blob/{commit}{path}#L{line}",
    sitename="LinAlgTools.jl",
    format=Documenter.HTML(;
        prettyurls=get(ENV, "CI", "false") == "true",
        canonical="https://knuesel.github.io/LinAlgTools.jl",
        assets=String[],
    ),
    pages=[
        "Home" => "index.md",
        "API" => "api.md",
    ],
)

deploydocs(;
    repo="github.com/knuesel/LinAlgTools.jl",
)


text:
"""
    xxhat, Mhat = kalmanEM(yy, M1::LinearHomogSystem, maxit = 500, tol = 0.001)

EM procedure for the state space model (Shumway, Stoffer)

- yy -- data
- M1 -- initial model
- maxit -- maximum number of iterations
- tol -- rel. tolerance for test for convergence of marginal likelihood

- xxhat, Mhat -- smoothed process with estimated model
"""
function kalmanEM(yy, M::LinearHomogSystem, maxit = 500, tol = 0.001)

    H, Phi, b, Q, R = M.H, M.Phi, M.b, M.Q, M.R
    d2, d = size(M.H)
    assert(ndims(yy) == 2)
    assert(norm(b) == 0)
    n = size(yy,2)

    x0 = M.x0
    P0 = M.P0
    xxs = xxf = zeros(d, n) # #x(f/s)[k] predited and corrected (and smoothed)

    PPf = zeros(d, d, n)  #P[k,k]
    PPpred = zeros(d, d, n)     #P[k, k-1]
    PPs = zeros(d, d, n)  #P[k,k]
    PPcs = zeros(d, d, n)  #P[k-1,k]

    K = zeros(d, d)

    cvg = 1.+tol
    nll = NaN
    for k in 1:maxit
        xf = x0
        Pf = P0

        # E step, forward pass
        nllold = nll
        nll = 0.
        for i in 1:n
            xf, Pf, Ppred, l, K  = kalman_kernel(xf, yy[:, i], Pf, H, Phi, b, Q, R)
            xxf[:, i], PPf[:, :, i], PPpred[:, :, i] = xf, Pf, Ppred
            l += d*log(2pi)/2         # constant messes up convergence test
            nll -= l
        end

        if k > 1
            cvg = (nllold-nll)/abs(nllold)
            cvg < 0 && warn("Likelihood decreasing")
            if abs(cvg) < tol
#                println([nll, cvg])
                break
            end
        end

        # E step, backwards pass including PPcs

        #start with xf, Pf from forward pass
        xs = xf
        Ps = Pf

        PPcs[:, :, n] = (I - K*H)*Phi*PPf[:, :, n-1]
        J = PPf[:, :, n]*Phi'/(Phi*Ps*Phi' + Q)
        PPs[:, :, n] = Ps
        for i in n-1:-1:1
            Jprev = J
            xs, Ps, J = smoother_kernel(xs, Ps, xxf[:, i],  PPf[:, :, i], PPpred[:, :, i+1], Phi, b)
            xxs[:, i], PPs[:, :, i] = xs, Ps

            j = i + 2 #i = j - 2 as J = J(i)
            if 2 < j <= n

                 Jjm2 = J
                 Jjm1 = Jprev
                 PPcs[:, :, j-1] = PPf[:, :, j-1]*Jjm2' +  Jjm1*(PPcs[:, :, j]  - Phi*PPf[:, :, j-1])*Jjm2'
                 #Pcs[,,j-1]=Pf[,,j-1]%*%t(J[,,j-2])+ J[,,j-1]%*%(Pcs[,,j]-Phi%*%Pf[,,j-1])%*%t(J[,,j-2])}

            end
        end
        x0, P0, J0 = smoother_kernel(xs, Ps, x0, P0, PPpred[:, :, 1], Phi, b)
        PPcs[:, :, 1] = PPf[:, :, 1]*J0' +  J*(PPcs[:, :, 2]  - Phi*PPf[:, :, 1])*J0'

        # M step

        A11 = xxs[:, 1]*xxs[:, 1]' + PPs[:, :, 1]
        A10 = xxs[:, 1]*x0' + PPcs[:, :, 1]
        A00 = x0*x0' + P0

        u = yy[:,1]-H*xxs[:,1]
        R = u*u' + H*PPs[:, :, 1]*H'

        for i in 1:n-1
            A11 = A11 + xxs[:, i+1]*xxs[:, i+1]' + PPs[:, :, i+1]
            A10 = A10 + xxs[:, i+1]*xxs[:, i]' + PPcs[:, :, i+1]
            A00 = A00 + xxs[:, i]*xxs[:, i]' + PPs[:, :, i]

            u = yy[:,i+1]-H*xxs[:,i+1]
            R = R + u * u' + H*PPs[:, :, i+1]*H'
        end

        Phi = A10/A00
        Q = (A11 - Phi*A10')/n
        Q = (Q+Q')/2
        R = R/n

#        println("PARAM $k: nll", [nll, cvg], "\n x0 $x0\n P0 $P0\n R $R\n Phi $Phi\n Q $Q")

    end

    xxs, LinearHomogSystem(x0, P0, Phi, b, Q, H, R)
end


text:
function module_dir()
	return joinpath(@__DIR__, "..")
end


text:
using NBTesting
using Base.Test

nbtest("Water_Analysis.ipynb")


text:
using Documenter, Juno

makedocs(modules=Module[Juno],
         doctest=false, clean=true,
         format =Documenter.Formats.HTML,
         sitename="Juno Documentation",
         pages = Any[
         "Home" => "index.md",
         "Manual" => Any[
             "man/installation.md",
             "man/basic_usage.md",
             "man/faq.md",
             "man/juno_frontend.md"
         ],
         "Developer Documentation" => Any[
             "devdocs/contributor_guide.md",
             "devdocs/dev_install.md",
             "devdocs/package_info.md",
             "devdocs/juno_ci.md",
             "devdocs/communication.md"
         ]])

deploydocs(
   repo = "github.com/ChrisRackauckas/JunoDocs.jl.git",
   target = "build",
   deps = nothing,
   make = nothing)


text:
include("subproblem.jl")
include("AbstractProgressiveHedging.jl")


text:
#=
import Base: hash, string, show, tryparse

withtypes = [(F,T1,T2) for F in (:hash, :string) for T1 in  (:Float64, :XFloat16) for T2 in (:XFloat16, :Float16)]

for (TF,TX) in ((:Float64, :XFloat32)(:Float64, :XFloat32))
  for F in (:hash, :abs)
     $F(x::$TX) = $F(reinterpret($TF, $TX))#      @eval a = string($T," ",$F); println(a);
           end; end
withtypes = [(F,T) for F in (:hash, :string) for T in  (:Float32, :XFloat16)]
  @eval begin
    $F(x::$T) = reinterpret(

=#