text:
export ininterior, inrelativeinterior

hyperplane(h::HyperPlane) = h
hyperplane(h::HalfSpace) = HyperPlane(h.a, h.β)

halfspace(h::HyperPlane) = HalfSpace(h.a, h.β)
halfspace(h::HalfSpace) = h

line(r::Ray) = Line(coord(r))
linetype(::Type{Ray{N, T, AT}}) where {N, T, AT} = Line{N, T, AT}

###############
# TRANSLATION #
###############

export translate

function htranslate(p::HRep{N, T}, v::Union{AbstractPoint{N, S}}) where {N, S, T}
    f = (i, h) -> translate(h, v)
    d = FullDim{N}()
    Tout = Base.promote_op(+, T, S)
    similar(p, d, Tout, hmap(f, d, Tout, p)...)
end

function vtranslate(p::VRep{N, T}, v::Union{AbstractPoint{N, S}}) where {N, S, T}
    f = (i, u) -> translate(u, v)
    d = FullDim{N}()
    Tout = Base.promote_op(+, T, S)
    similar(p, d, Tout, vmap(f, d, Tout, p)...)
end

translate(p::HRep, v) = htranslate(p, v)
translate(p::VRep, v) = vtranslate(p, v)
function translate(p::Polyhedron, v)
    if hrepiscomputed(p)
        htranslate(p, v)
    else
        vtranslate(p, v)
    end
end

######
# IN #
######
function _vinh(v::VRepElement{N}, it::ElemIt{<:HRepElement{N}}, infun) where N
    for h in it
        if !infun(v, h)
            return false
        end
    end
    return true
end
function _vinh(v::VRepElement{N}, hr::HRep{N}, infun) where N
    all(map(it -> _vinh(v, it, infun), hreps(hr)))
end

"""
    in(p::VRepElement, h::HRepElement)

Returns whether `p` is in `h`.
If `h` is an hyperplane, it returns whether ``\\langle a, x \\rangle \\approx \\beta``.
If `h` is an halfspace, it returns whether ``\\langle a, x \\rangle \\le \\beta``.

    in(p::VRepElement, h::HRep)

Returns whether `p` is in `h`, e.g. in all the hyperplanes and halfspaces supporting `h`.
"""
Base.in(v::VRepElement{N}, hr::HRep{N}) where {N} = _vinh(v, hr, Base.in)

"""
    ininterior(p::VRepElement, h::HRepElement)

Returns whether `p` is in the interior of `h`.
If `h` is an hyperplane, it always returns `false`.
If `h` is an halfspace ``\\langle a, x \\rangle \\leq \\beta``, it returns whether `p` is in the open halfspace ``\\langle a, x \\rangle < \\beta``

    ininterior(p::VRepElement, h::HRep)

Returns whether `p` is in the interior of `h`, e.g. in the interior of all the hyperplanes and halfspaces supporting `h`.
"""
ininterior(v::VRepElement{N}, hr::HRep{N}) where {N} = _vinh(v, hr, ininterior)

"""
    inrelativeinterior(p::VRepElement, h::HRepElement)

Returns whether `p` is in the relative interior of `h`.
If `h` is an hyperplane, it is equivalent to `p in h` since the relative interior of an hyperplane is itself.
If `h` is an halfspace, it is equivalent to `ininterior(p, h)`.

    inrelativeinterior(p::VRepElement, h::HRep)

Returns whether `p` is in the relative interior of `h`, e.g. in the relative interior of all the hyperplanes and halfspaces supporting `h`.
"""
inrelativeinterior(v::VRepElement{N}, hr::HRep{N}) where {N} = _vinh(v, hr, inrelativeinterior)

function _hinv(h::HRepElement{N}, vr::ElemIt{<:VRepElement{N}}) where N
    all(in.(vr, h))
end
function _hinv(h::HRepElement{N}, vr::VRep{N}) where N
    all(_hinv.(h, vreps(vr)))
end
function _hinh(h::HalfSpace{N}, hr::HRep{N}, solver) where N
    # ⟨a, x⟩ ≦ β -> if β < max ⟨a, x⟩ then h is outside
    sol = MPB.linprog(-h.a, hr, solver)
    if sol.status == :Unbounded
        false
    elseif sol.status == :Infeasible
        true
    elseif sol.status == :Optimal
        _leq(-sol.objval, h.β)
    else
        error("Solver returned with status $(sol.status)")
    end
end
function _hinh(h::HyperPlane{N}, hr::HRep{N}, solver) where N
    _hinh(halfspace(h), hr, solver) && _hinh(halfspace(-h), hr, solver)
end

Base.issubset(vr::VRepresentation{N}, h::HRepElement{N}) where {N} = _hinv(h, vr)
Base.issubset(hr::HRepresentation{N}, h::HRepElement{N}) where {N} = _hinh(h, hr)

"""
    issubset(p::Rep, h::HRepElement)

Returns whether `p` is a subset of `h`, i.e. whether `h` supports the polyhedron `p`.
"""
function Base.issubset(p::Polyhedron{N}, h::HRepElement{N}, solver=Polyhedra.solver(p)) where N
    if vrepiscomputed(p)
        _hinv(h, p)
    else
        _hinh(h, p, solver)
    end
end

function Base.in(h::HRepElement, p::Rep)
    warn("in(h::HRepElement, p::Rep) is deprecated. Use issubset(p, h) instead.")
    issubset(p, h)
end

################
# INTERSECTION #
################
_intres(h::HyperPlane, ins, inp) = inp
_intres(h::HalfSpace, ins, inp) = [ins; inp]

# Unused as allpoints and allrays are used
#function _pushinout!(ins, out, l::Line, h::HalfSpace)
#    r1 = Ray(l.a)
#    r2 = Ray(-l.a)
#    if r1 in h
#        push!(ins, r1)
#        push!(out, r2)
#    else
#        push!(ins, r2)
#        push!(out, r1)
#    end
#end
#function _pushinout!(ins, out, p::SymPoint, h::HalfSpace)
#    p1 = Point(p.a)
#    p2 = Point(-p.a)
#    if p1 in h
#        push!(ins, p1)
#        push!(out, p2)
#    else
#        push!(ins, p2)
#        push!(out, p1)
#    end
#end

function _pushinout!(ins, out, pr::Union{AbstractPoint, Ray}, h::HalfSpace)
    if pr in h
        push!(ins, pr)
    else
        push!(out, pr)
    end
end

"""
    intersect(v::VRepresentation{N, T}, h::HRepElement)

Compute the intersection of `v` with an halfspace or hyperplane `h`.
The method used by default is to keep the V-representation element of `v`
that are in `h` and add new ones generated as the intersection between
the hyperplane defining `h` and the segment between two adjacent
V-representation elements of `v` that are in either sides of the hyperplane.
See Lemma 3 of [FP96] for more detail on the method.

[FP96] Fukuda, K. and Prodon, A.
**Double description method revisited**
*Combinatorics and computer science*, *Springer*, **1996**, 91-111
"""
function Base.intersect(v::VRepresentation{N, T}, h::HRepElement) where {N, T}
    PointT = pointtype(v)
    pins = PointT[] # Inside
    pinp = PointT[] # In plane
    pout = PointT[] # Outside
    hp = hyperplane(h)
    hs = halfspace(h)
    for p in points(v) # we want sympoints to be treated as 2 points
        if p in hp
            push!(pinp, p)
        else
            _pushinout!(pins, pout, p, hs)
        end
    end
    RayT = raytype(v)
    rins = RayT[]
    rinp = RayT[]
    rout = RayT[]
    for r in allrays(v) # we want lines to be treated as 2 rays
        if r in hp
            push!(rinp, r)
        else
            _pushinout!(rins, rout, r, hs)
        end
    end
    # \    For every pair of point inside/outside,
    # _.__ add the intersection of the segment with the hyperplane.
    #   \  In CDD and ConvexHull.jl, they only consider segments that
    #    \ belongs to the boundary which is way faster than what we do here
    for p in pins
        ap = h.a ⋅ p
        for q in pout
            aq = h.a ⋅ q
            λ = (aq - h.β) / (aq - ap)
            @assert 0 <= λ <= 1
            push!(pinp, simplify(λ * p + (1 - λ) * q))
        end
    end
    # Similar but with rays
    for r in rins
        ar = h.a ⋅ r
        for s in rout
            as = h.a ⋅ s
            # should take
            # λ = as / (as - ar)
            @assert 0 <= as / (as - ar) <= 1
            # By homogeneity we can avoid the division and do
            #newr = as * r - ar * s
            # but this can generate very large numbers (see JuliaPolyhedra/Polyhedra.jl#48)
            # so we still divide
            newr = (as * r - ar * s) / (as - ar)
            # In CDD, it does as * r - ar * s but then it normalize the ray
            # by dividing it by its smallest nonzero entry (see dd_CreateNewRay)
            if !isapproxzero(coord(newr))
                push!(rinp, simplify(newr))
            end
        end
    end
    # Similar but with one point and one ray
    for (ps, rs) in ((pins, rout), (pout, rins))
        for p in ps
            ap = h.a ⋅ p
            for r in rs
                ar = h.a ⋅ r
                λ = (h.β - ap) / ar
                push!(pinp, p + λ * r)
            end
        end
    end
    psout = _intres(h, pins, pinp)
    rsout = _intres(h, rins, rinp)
    if isempty(psout)
        # Empty polyhedron, there may be rays left,
        # Example 1: for 0x_1 + x_2 = -1 ∩ 0x_1 + x_2 = 1, the line (0, 1) is detected as correct
        # Example 2: for 0x_1 + 0x_2 = 1, the lines (1, 0) and (0, 1) are detected as correct
        # but since there is no point, the polyhedron is empty and we should drop all rays/lines
        empty!(rsout)
    end
    similar(v, psout, linetype(eltype(rsout))[], rsout)
end


text:
# ---
# title: 371. Sum of Two Integers
# id: problem371
# author: Indigo
# date: 2021-09-26
# difficulty: Medium
# categories: Bit Manipulation
# link: <https://leetcode.com/problems/sum-of-two-integers/description/>
# hidden: true
# ---
#
# Calculate the sum of two integers _a_ and _b_ , but you are **not allowed** to
# use the operator `+` and `-`.
#
# **Example 1:**
#
#
#
#     Input: a = 1, b = 2
#     Output: 3
#
#
# **Example 2:**
#
#
#
#     Input: a = -2, b = 3
#     Output: 1
#
#
#
## @lc code=start
using LeetCode

function get_sum371(a::Int, b::Int)::Int
    while b != 0
        carry = (a & b) << 1
        a = a ⊻ b
        b = carry
    end
    a
end
## @lc code=end

ext: jl


text:
"""
LP model construction routines

Function names list (order by appearance in code):
    build_OptStoic_model
    build_MinFlux_model
    build_MinRxn_model
"""

"""
    build_OptStoic_model(
        database::S,
        substrate::String,
        targets::Vector{String},
        co_reactants = String[],
        energy_dc = Dict(),
        optimizer;
        energy_dc = Dict(),
        db_id = bigg,
        variable_bounds = Dict("substrate" => -1, "reactants" => (-15, 15)),
        custom_bounds = Dict(),
        dG_thres = -5,
        IP = true,
    ) where {S<:COBREXA.StandardModel}

Construction of LP model for OptStoic procedure. OptStoic procedure is formulated via this optimisation problem:
```
max f(scⱼ)
s.t.
    ∑(nᵤⱼ scⱼ) = 0, ∀ u∈U   (Mass Balance)
    ∑(eⱼ scⱼ) = 0,          (Charge Balance)
    ∑(ΔGⱼ scⱼ) ≤ ΔGᵐⁱⁿ      (Energy Balance)
```
This formulation was derived and shortened for display. See "Chowdhury, A., Maranas, C. Designing overall stoichiometric conversions and intervening metabolic reactions. Sci Rep 5, 16009 (2015). https://doi.org/10.1038/srep16009" for more information. It is possible to formulate this problem as IP or MIP, hence the keyword binary `IP` with `true` for IP and `false` for MIP.

The `substrate` should be the limiting carbon source of the desired biochemical conversion (e.g. glucose). The `targets` include every target metabolite that should be maximised. The `co_reactants` include every metabolite that is allowed to appear in the stoichiometry but is not supposed to be targeted for maximisation. The `optimizer` has to be set to a `JuMP`-compatible optimiser, such as `JuMP.Gurobi` or `JuMP.GLPK` and supports (MI)LP (see https://jump.dev/JuMP.jl/stable/installation/#Supported-solvers for compatibility issues).

The construction process includes the collecting process of ΔG of formation for the metabolites within the `database`. Optionally a dictionary with the necessary thermodynamic data can be passed to the function via `energy_dc`. The default limits for the stoichiometric coefficients are set in `variable_bounds` and can be altered. Custom bounds for specific metabolites can be passed by the `custom_bounds` dictionary. The ΔGᵐⁱⁿ (`dG_thres`) is set to -5 kJ/mol by default.
# Example
```
Glucose -> Acetate conversion (anaerobic, E. coli core model (from http://bigg.ucsd.edu/models/e_coli_core))
build_OptStoic_model(
    ecoli_core,
    "glc__D_e",
    ["ac_e"],
    ["co2_e", "o2_e", "h2o_e", "h_e"],
    Gurobi,
    custom_bounds = Dict("o2_e" => (0, 0))
)
```
"""
function build_OptStoic_model(
    database::SM,
    substrates::Vector{String},
    targets::Vector{String},
    co_reactants::Vector{String},
    optimizer;
    db_id = bigg,
	energy_dc = Dict(),
    variable_bounds = Dict("substrates" => -1, "reactants" => (-15, 15)),
    custom_bounds = Dict(),
    dG_thres = -5,
    IP = true,
) where {SM<:COBREXA.StandardModel}

    # Constructing the LP model
    os_model = Model(optimizer.Optimizer)

    # Adds custom bounds to the variable bounds
    merge!(variable_bounds, custom_bounds)

    # Collecting elements for constraints
    participants = vcat(substrates, targets, co_reactants)
    elements = Vector{String}()
    for met in participants
        elements = vcat(elements, collect(keys(metabolite_formula(database, met))))
    end
    elements = Set(elements)

    # Metabolite formulae are extended by "empty" elements to allow mass balance in constraint construction.
    ### INEFFICIENT. WILL BE CHANGED SOON ###
    ext_formulae = _extend_formulae(database)

    # Assigning ΔGs for constraints
    dgf_substrates = Vector()
    for met in substrates
        push!(dgf_substrates, energy_dc[met].val.val)
        if met ∉ keys(variable_bounds)
            variable_bounds[met] = variable_bounds["substrates"]
        end
    end

    dgf_targets = Vector()
    for met in targets
        push!(dgf_targets, energy_dc[met].val.val)
        if met ∉ keys(variable_bounds)
            variable_bounds[met] = variable_bounds["reactants"]
        end
    end

    dgf_cor = Vector()
    for met in co_reactants
        push!(dgf_cor, energy_dc[met].val.val)
        if met ∉ keys(variable_bounds)
            variable_bounds[met] = variable_bounds["reactants"]
        end
    end

    # Assigning variables and constraints
    @variables(
        os_model,
        begin
            S[it = 1:length(substrates)] == variable_bounds[substrates[it]],
            (start = it, base_name = substrates[it], integer = IP)
            1 ≤ T[it = 1:length(targets)] ≤ variable_bounds[targets[it]][2],
            (start = it, base_name = targets[it], integer = IP)
            variable_bounds[co_reactants[it]][1] ≤
            CoR[it = 1:length(co_reactants)] ≤
            variable_bounds[co_reactants[it]][2],
            (start = it, base_name = co_reactants[it], integer = IP)
        end
    )

    @constraint(
        os_model,
        EnergyBalance,
        sum(T[it] * dgf_targets[it] for it = 1:length(targets)) +
        sum(CoR[it] * dgf_cor[it] for it = 1:length(co_reactants)) +
        sum(S[it] * dgf_substrates[it] for it = 1:length(substrates))
        ≤ dG_thres
    )
    @constraint(
        os_model,
        ChargeBalance,
        sum(T[it] * metabolite_charge(database, targets[it]) for it = 1:length(targets)) +
        sum(
            CoR[it] * metabolite_charge(database, co_reactants[it]) for
            it = 1:length(co_reactants)
        ) +
        sum(S[it] * metabolite_charge(database, substrates[it]) for it = 1:length(substrates))
        == 0
    )
    for elem in elements
        @constraint(
            os_model,
            (base_name = string("MassBalance_", elem)),
            sum(T[it] * ext_formulae[targets[it]][elem] for it = 1:length(targets)) +
            sum(
                CoR[it] * ext_formulae[co_reactants[it]][elem] for
                it = 1:length(co_reactants)
            ) +
            sum(S[it] * ext_formulae[substrates[it]][elem] for it = 1:length(substrates))
            == 0
        )

        c_norm = -1 * sum(variable_bounds[substrates[it]] * ext_formulae[substrates[it]]["C"] for it = 1:length(substrates)) # carbon normalization factor
        @objective(os_model, Max, sum(T) / c_norm) # Objective function
    end

    return os_model
end

"""
    build_MinFlux_model(
        database,
        optstoic_solution,
        dGr_dict = Dict();
        L = [],
        optimizer,
        loopless = false,
        N_red = [],
        ϵ = 10^(-5),
        M = 1000
    )
MinFlux formulation. Returns MinFlux MILP model. Takes an overall stoichiometry or a previously calculated OptStoic solution dictionary (`optstoic_solution`) as argument. Stoichiometry may be structured as a dictionary with metabolite IDs as keys and the corresponding stoichiometric coefficients as values (negative for substrates, positive for products). The IDs need to match the corresponding metabolite IDs in the metabolic model (`database`). The flux_bounds_dictionary argument is a dictionary with the preprocessed boundaries (see function `flux_bounds` and `MinFlux_preprocessing`). Loopless constraints can be added by setting `loopless` as `true`. A precomiled matrix `N_red` for loopless constraints can additionally be passed to avoid automatic matrix calculation.
)
"""
function build_MinFlux_model(
    database,
    optstoic_solution,
    flux_bounds_dictionary;
    L = [],
    optimizer,
    loopless = false,
    N_red = [],
    ϵ = 10^(-5),
    M = 1000
)
    mf_model = Model(optimizer.Optimizer)

    # If loopless constraints are activated and no constraint matrix L is passed via keyword, a matrix is constructed locally.
    if loopless
        if isempty(N_red)
            N_red = Nred(database)
        end
        red_dimensions = size(N_red)[1]
    end

    ex_vec = Vector()
    for (comp, coeff) in optstoic_solution
        push!(ex_vec, Reaction(string("EX_", comp), Dict(comp => -1)))
        flux_bounds_dictionary[string("EX_", comp)] = (coeff, coeff)
    end
    for ex in ex_vec
        if ex ∉ reactions(database)
            add_reaction!(database, ex)
        end
    end

    lbs = Vector()
    ubs = Vector()
    for x in collect(values(flux_bounds_dictionary))
        push!(lbs, x[1]) # Collecting lower bounds
        push!(ubs, x[2]) # Collecting upper bounds
    end

    rxn_size = length(reactions(database))
    @variable(mf_model, V[i = 1:rxn_size], Int)
    @variable(mf_model, X[i = 1:rxn_size])
    @variable(mf_model, Vf[i = 1:rxn_size])
    @variable(mf_model, Vr[i = 1:rxn_size])
    @variable(mf_model, Yf[i = 1:rxn_size], Bin)
    @variable(mf_model, Yr[i = 1:rxn_size], Bin)

    # Adding loopless constraints, if loopless is true
    if loopless
        @variable(mf_model, G[i = 1:red_dimensions])
        @variable(mf_model, a[i = 1:red_dimensions], Bin)

        @constraint(mf_model, LoopBalance, N_red' * G .== 0)
        @constraint(mf_model, L1, G .>= -M * a + (1 .- a))
        @constraint(mf_model, L2, G .>= -a .+ M * (1 .- a))
        @constraint(mf_model, L3, [V[it] for it in 1:length(V) if !startswith(reactions(database)[it], "EX_")] .>= -M * (1 .- a))
        @constraint(mf_model, L4, [V[it] for it in 1:length(V) if !startswith(reactions(database)[it], "EX_")] .<= M * a)
    end

    @constraint(mf_model, MassBalance, stoichiometry(database) * V .== balance(database))
    @constraint(mf_model, LowerBounds, lbs .<= V)
    @constraint(mf_model, Upperbounds, ubs .>= V)
    @constraint(mf_model, FluxDiff, V .== Vr - Vf)
    @constraint(mf_model, FluxSum, X .== Vr + Vf)
    @constraint(mf_model, ForwardFlux, Vf .>= 0)
    @constraint(mf_model, ReverseFlux, Vr .>= 0)
    @constraint(mf_model, abscon1, X .>= V)
    @constraint(mf_model, abscon2, X .>= -V)
    @constraint(mf_model, Vf .>= ϵ * Yf)
    @constraint(mf_model, M * Yf .>= Vf)
    @constraint(mf_model, Vr .>= ϵ * Yr)
    @constraint(mf_model, M * Yf .>= Vr)
    @constraint(mf_model, BinActive, 1 .>= Yf + Yr)
    if !isempty(L)
        for k in 1:length(L)
            @constraint(mf_model, base_name = string("IntegerCut_it", k),
            sum([1-Yf[it]-Yr[it] for it in 1:rxn_size if sum(L[k][it]) == 1 && !startswith(reactions(database)[it], "EX_")]) >= 1)
        end
    end
    @objective(mf_model, Min, sum(X))

    return database, mf_model

end

"""
    extract_binaries(minflux_model, arr = [], ϵ = 0)

Creates tuple vector for cut constraints. Can be added to previous vector (`arr`) to extend previous cut constraints. `ϵ` is used as a threshold for residual float values in the binary LP variables.
"""
function extract_binaries(minflux_model, arr = [], ϵ = 0)
    new_path = []
    for i in 1:length(minflux_model[:Yf])
        if value(minflux_model[:Vf][i]) <= 2*ϵ
            yf = 0.0
        else
            yf = value(minflux_model[:Yf][i])
        end
        if value(minflux_model[:Vr][i]) <= 2*ϵ
            yr = 0.0
        else
            yr = value(minflux_model[:Yr][i])
        end

        push!(new_path, (yr, yf))
    end

    return push!(arr, new_path)
end

max_stars_repo_name: VictorVeraFrazao/OptStoic

max_issues_repo_name: VictorVeraFrazao/OptStoic

max_forks_repo_name: VictorVeraFrazao/OptStoic


text:
using Tokenize

nt = @timed @eval(collect(Tokenize.tokenize("foo + bar")))
println("First run took $(nt.time) seconds with $(nt.bytes/1e6) MB allocated")

srcdir = joinpath(Sys.BINDIR, Base.DATAROOTDIR, "..")

allfiles = []
for (root, dirs, files) in walkdir(srcdir, follow_symlinks = true)
    for file in files
        splitext(file)[2] == ".jl" || continue
        push!(allfiles, joinpath(root, file))
    end
end

# warmup
let time_taken = 0.0, allocated = 0.0
    for file in allfiles
        content = IOBuffer(read(file, String))
        nt = @timed for t in Tokenize.tokenize(content) end
        time_taken += nt.time
        allocated += nt.bytes
    end
end

# actual run
let time_taken = 0.0, allocated = 0.0
    for file in allfiles
        content = IOBuffer(read(file, String))
        nt = @timed for t in Tokenize.tokenize(content) end
        time_taken += nt.time
        allocated += nt.bytes
    end
    println("Tokenized $(length(allfiles)) files in $(time_taken) seconds with $(allocated/1e6) MB allocated")
end

isempty(ARGS) && exit(0)

using PProf, Profile

# warm up profiler
let content = read(first(allfiles), String)
    @profile collect(Tokenize.tokenize(content))
end

Profile.clear()
for file in allfiles
    content = read(file, String)
    @profile collect(Tokenize.tokenize(content))
end
pprof()

println("Press any key to exit...")
readline()


text:
function accept(obj::StorelessUnivariateStatistic, arg0::jdouble)
    return jcall(obj, "accept", void, (jdouble,), arg0)
end

function and_then(obj::DoubleConsumer, arg0::DoubleConsumer)
    return jcall(obj, "andThen", DoubleConsumer, (DoubleConsumer,), arg0)
end

function clear(obj::FirstMoment)
    return jcall(obj, "clear", void, ())
end

function copy(obj::FirstMoment)
    return jcall(obj, "copy", FirstMoment, ())
end

function equals(obj::AbstractStorelessUnivariateStatistic, arg0::Object)
    return jcall(obj, "equals", jboolean, (Object,), arg0)
end

function evaluate(obj::StorelessUnivariateStatistic, arg0::Vector{jdouble}, arg1::jint, arg2::jint)
    return jcall(obj, "evaluate", jdouble, (Vector{jdouble}, jint, jint), arg0, arg1, arg2)
end

function evaluate(obj::UnivariateStatistic, arg0::Vector{jdouble})
    return jcall(obj, "evaluate", jdouble, (Vector{jdouble},), arg0)
end

function get_class(obj::Object)
    return jcall(obj, "getClass", Class, ())
end

function get_n(obj::FirstMoment)
    return jcall(obj, "getN", jlong, ())
end

function get_result(obj::FirstMoment)
    return jcall(obj, "getResult", jdouble, ())
end

function hash_code(obj::AbstractStorelessUnivariateStatistic)
    return jcall(obj, "hashCode", jint, ())
end

function increment(obj::FirstMoment, arg0::jdouble)
    return jcall(obj, "increment", void, (jdouble,), arg0)
end

function increment_all(obj::StorelessUnivariateStatistic, arg0::Vector{jdouble})
    return jcall(obj, "incrementAll", void, (Vector{jdouble},), arg0)
end

function increment_all(obj::StorelessUnivariateStatistic, arg0::Vector{jdouble}, arg1::jint, arg2::jint)
    return jcall(obj, "incrementAll", void, (Vector{jdouble}, jint, jint), arg0, arg1, arg2)
end

function notify(obj::Object)
    return jcall(obj, "notify", void, ())
end

function notify_all(obj::Object)
    return jcall(obj, "notifyAll", void, ())
end

function to_string(obj::AbstractStorelessUnivariateStatistic)
    return jcall(obj, "toString", JString, ())
end

function wait(obj::Object)
    return jcall(obj, "wait", void, ())
end

function wait(obj::Object, arg0::jlong)
    return jcall(obj, "wait", void, (jlong,), arg0)
end

function wait(obj::Object, arg0::jlong, arg1::jint)
    return jcall(obj, "wait", void, (jlong, jint), arg0, arg1)
end


text:
"""
    minimum_spantree(n, edges, weights, [root = 1])

[Prim's algorithm](https://en.wikipedia.org/wiki/Prim%27s_algorithm)
for minimum spanning tree.
Start from node `root` (will become the root node of the spanning tree).
Return the parent vector of the tree.
"""
function minimum_spantree(n, edges, weights, root = 1)::Vector{Int}
    finished, dist, parent, neighbors, pq = _init_spantree(edges, n)
    return _minimum_spantree(weights, finished,
                             dist, parent, neighbors, pq, root)
end

function _minimum_spantree(weights, finished, dist, parent, neighbors,
                           pq::PriorityQueue{Int, Float64}, root = 1)
    @assert isempty(pq)
    sizehint!(pq, length(parent))
    finished .= false
    finished[root] = true
    dist .= Inf
    dist[root] = 0.0
    parent[root] = root
    pq[root] = dist[root]
    while !isempty(pq)
        u = dequeue!(pq)
        for (v, eidx) in neighbors[u]
            v == u && continue
            if !finished[v] && weights[eidx] < dist[v]
                dist[v] = weights[eidx]
                pq[v] = dist[v]    # decrease_key!(v)
                parent[v] = u
            end
        end
        finished[u] = true
    end
    return parent
end

max_stars_repo_name: EQt/graphidx

max_issues_repo_name: EQt/graphidx

max_forks_repo_name: EQt/graphidx


text:
push!(LOAD_PATH,"../src/")
using Documenter, ReconTPCF, Pkg

#Pkg.add(path="C:/Users/James/.julia/dev/ReconTPCF")
makedocs(root ="./docs",
        source = "src",
        sitename="ReconTPCF.jl",
        doctest = true,
        modules = [ReconTPCF],
        pages = ["index.md", "histrecon.md", "library.md"],
        format = Documenter.HTML(prettyurls = false)
        )


text:
using ChainRulesCore, Zygote

#=
# forward differentiation rule:
function ChainRulesCore.frule(
    (_, _, Δgen),
    ::typeof(IndexFunArray{T,N,F}),
    gen::F,
    sz::NTuple{N, Int},
    ) where {N,F}
    Ω = IndexFunArray{T,N,typeof(gen)}(gen, sz)
    ∂Ω = IndexFunArray{T,N,typeof(gen)}(Δgen, sz)
    return (Ω, ∂Ω)
end
=#

# this function provides support for derivatives in reverse mode as calculated
# by automatic differentiation tools such as Zygote
function ChainRulesCore.rrule(::Type{IndexFunArray}, # ::typeof(IndexFunArray)
    myT::Type{T},
    gen::F,
    sz::NTuple{N, Int},  # This is the standard constructor, abeit not the direct contructor
    ) where {T,F,N}
    val_grad(idx) = Zygote._pullback(gen, idx)[2](1.0) # [2](1.0)
    # @show  val_grad([1,1])[1]  # this is a named tuple
    # gradgen(idx) = val_grad(idx)[1][:a] # (val_grad(x)[2](1.0))[2] # mygrad(x)[1][1] #
    mySymbols=keys(val_grad(sz)[1])
    gradgen(idx) = val_grad(idx)[1] # (val_grad(x)[2](1.0))[2] # mygrad(x)[1][1] #
    function IFA_pullback(ΔΩ)   # Zygote._pullback(f,pi/2.0)[2](1.0) # 1.0 is only the seed
        Fcts = ((idx)-> val_grad(idx)[1][aSymbol] for aSymbol in mySymbols)
        # Fcts = ((idx)-> ΔΩ[idx...] .* val_grad(idx)[1][aSymbol] for aSymbol in mySymbols)
        # TupleVals = (IndexFunArray(typeof(Fun(sz)), Fun, sz) for Fun in Fcts) # {T,N,typeof(Fun)} yields a tuple of values
        TupleVals = (apply_tuple_list.(.*,ΔΩ,IndexFunArray(typeof(Fun(sz)), Fun, sz)) for Fun in Fcts) # {T,N,typeof(Fun)} yields a tuple of values
        # TupleVals = (collect(ΔΩ .* IndexFunArray(typeof(Fun(sz)), Fun, sz)) for Fun in Fcts) # {T,N,typeof(Fun)} yields a tuple of values
        @show TupleVals
        print("ojo:\n\n")
        ∂gen = NamedTuple{mySymbols}(collect(TupleVals)) # converts the value tuple into a named tuple with the appropriate type names
        @show typeof(∂gen)
        @show ∂gen
        print("oji:\n\n")
        return (NO_FIELDS, NO_FIELDS, ∂gen, NO_FIELDS) # myT, gen, sz, closures   NO_FIELDS  (offset=∂gen[:offset],)
    end
    Ω = IndexFunArray(T, gen, sz) # {T,N,typeof(gen)}
    return (Ω, IFA_pullback)
end


text:
# ----------------------------------------------------------------------------------- #
# Copyright (c) 2016 Varnerlab
# Robert Frederick Smith School of Chemical and Biomolecular Engineering
# Cornell University, Ithaca NY 14850
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# ----------------------------------------------------------------------------------- #
#
# ----------------------------------------------------------------------------------- #
# Function: Control
# Description: Calculate the transcriptional control array at time t
# Generated on: 2016-11-02T07:00:01.342
#
# Input arguments:
# t::Float64 => Current time value (scalar)
# x::Array{Float64,1} => State array (number_of_species x 1)
# data_dictionary::Dict{AbstractString,Any} => Dictionary holding model parameters
#
# Output arguments:
# control_array::Array{Float64,1} => Transcriptional control array (number_of_genes x 1) at time t
# ----------------------------------------------------------------------------------- #
function Control(t::Float64,x::Array{Float64,1},data_dictionary::Dict{AbstractString,Any})

	# initialize the control -
	control_array = zeros(18)

	# Alias the species -
	gene_AP1 = x[1]
	gene_AhR = x[2]
	gene_CD11b = x[3]
	gene_CD14 = x[4]
	gene_CD38 = x[5]
	gene_CEBPa = x[6]
	gene_E2F = x[7]
	gene_EGR1 = x[8]
	gene_GFI1 = x[9]
	gene_IRF1 = x[10]
	gene_OCT1 = x[11]
	gene_OCT4 = x[12]
	gene_P21 = x[13]
	gene_P47Phox = x[14]
	gene_PPARg = x[15]
	gene_PU1 = x[16]
	gene_Trigger = x[17]
	gene_cRAF = x[18]
	mRNA_gene_AP1 = x[19]
	mRNA_gene_AhR = x[20]
	mRNA_gene_CD11b = x[21]
	mRNA_gene_CD14 = x[22]
	mRNA_gene_CD38 = x[23]
	mRNA_gene_CEBPa = x[24]
	mRNA_gene_E2F = x[25]
	mRNA_gene_EGR1 = x[26]
	mRNA_gene_GFI1 = x[27]
	mRNA_gene_IRF1 = x[28]
	mRNA_gene_OCT1 = x[29]
	mRNA_gene_OCT4 = x[30]
	mRNA_gene_P21 = x[31]
	mRNA_gene_P47Phox = x[32]
	mRNA_gene_PPARg = x[33]
	mRNA_gene_PU1 = x[34]
	mRNA_gene_Trigger = x[35]
	mRNA_gene_cRAF = x[36]
	protein_gene_AP1 = x[37]
	protein_gene_AhR = x[38]
	protein_gene_CD11b = x[39]
	protein_gene_CD14 = x[40]
	protein_gene_CD38 = x[41]
	protein_gene_CEBPa = x[42]
	protein_gene_E2F = x[43]
	protein_gene_EGR1 = x[44]
	protein_gene_GFI1 = x[45]
	protein_gene_IRF1 = x[46]
	protein_gene_OCT1 = x[47]
	protein_gene_OCT4 = x[48]
	protein_gene_P21 = x[49]
	protein_gene_P47Phox = x[50]
	protein_gene_PPARg = x[51]
	protein_gene_PU1 = x[52]
	protein_gene_Trigger = x[53]
	protein_gene_cRAF = x[54]

	# Alias the binding parameters -
	binding_parameter_dictionary = data_dictionary["binding_parameter_dictionary"]
	n_gene_AP1_gene_AhR = binding_parameter_dictionary["n_gene_AP1_gene_AhR"]
	K_gene_AP1_gene_AhR = binding_parameter_dictionary["K_gene_AP1_gene_AhR"]
	n_gene_AP1_gene_PU1 = binding_parameter_dictionary["n_gene_AP1_gene_PU1"]
	K_gene_AP1_gene_PU1 = binding_parameter_dictionary["K_gene_AP1_gene_PU1"]
	n_gene_AP1_gene_PPARg = binding_parameter_dictionary["n_gene_AP1_gene_PPARg"]
	K_gene_AP1_gene_PPARg = binding_parameter_dictionary["K_gene_AP1_gene_PPARg"]
	n_gene_AhR_gene_Trigger = binding_parameter_dictionary["n_gene_AhR_gene_Trigger"]
	K_gene_AhR_gene_Trigger = binding_parameter_dictionary["K_gene_AhR_gene_Trigger"]
	n_gene_CD11b_gene_PU1_gene_cRAF = binding_parameter_dictionary["n_gene_CD11b_gene_PU1_gene_cRAF"]
	K_gene_CD11b_gene_PU1_gene_cRAF = binding_parameter_dictionary["K_gene_CD11b_gene_PU1_gene_cRAF"]
	n_gene_CD14_gene_PPARg_gene_CEBPa_gene_EGR1_gene_cRAF = binding_parameter_dictionary["n_gene_CD14_gene_PPARg_gene_CEBPa_gene_EGR1_gene_cRAF"]
	K_gene_CD14_gene_PPARg_gene_CEBPa_gene_EGR1_gene_cRAF = binding_parameter_dictionary["K_gene_CD14_gene_PPARg_gene_CEBPa_gene_EGR1_gene_cRAF"]
	n_gene_CD38_gene_IRF1_gene_PPARg_gene_Trigger_gene_cRAF = binding_parameter_dictionary["n_gene_CD38_gene_IRF1_gene_PPARg_gene_Trigger_gene_cRAF"]
	K_gene_CD38_gene_IRF1_gene_PPARg_gene_Trigger_gene_cRAF = binding_parameter_dictionary["K_gene_CD38_gene_IRF1_gene_PPARg_gene_Trigger_gene_cRAF"]
	n_gene_CEBPa_gene_Trigger = binding_parameter_dictionary["n_gene_CEBPa_gene_Trigger"]
	K_gene_CEBPa_gene_Trigger = binding_parameter_dictionary["K_gene_CEBPa_gene_Trigger"]
	n_gene_CEBPa_gene_PPARg = binding_parameter_dictionary["n_gene_CEBPa_gene_PPARg"]
	K_gene_CEBPa_gene_PPARg = binding_parameter_dictionary["K_gene_CEBPa_gene_PPARg"]
	n_gene_CEBPa_gene_CEBPa = binding_parameter_dictionary["n_gene_CEBPa_gene_CEBPa"]
	K_gene_CEBPa_gene_CEBPa = binding_parameter_dictionary["K_gene_CEBPa_gene_CEBPa"]
	n_gene_CEBPa_gene_GFI1 = binding_parameter_dictionary["n_gene_CEBPa_gene_GFI1"]
	K_gene_CEBPa_gene_GFI1 = binding_parameter_dictionary["K_gene_CEBPa_gene_GFI1"]
	n_gene_E2F_gene_E2F = binding_parameter_dictionary["n_gene_E2F_gene_E2F"]
	K_gene_E2F_gene_E2F = binding_parameter_dictionary["K_gene_E2F_gene_E2F"]
	n_gene_E2F_gene_PPARg = binding_parameter_dictionary["n_gene_E2F_gene_PPARg"]
	K_gene_E2F_gene_PPARg = binding_parameter_dictionary["K_gene_E2F_gene_PPARg"]
	n_gene_E2F_gene_CEBPa = binding_parameter_dictionary["n_gene_E2F_gene_CEBPa"]
	K_gene_E2F_gene_CEBPa = binding_parameter_dictionary["K_gene_E2F_gene_CEBPa"]
	n_gene_E2F_gene_GFI1 = binding_parameter_dictionary["n_gene_E2F_gene_GFI1"]
	K_gene_E2F_gene_GFI1 = binding_parameter_dictionary["K_gene_E2F_gene_GFI1"]
	n_gene_E2F_gene_cRAF = binding_parameter_dictionary["n_gene_E2F_gene_cRAF"]
	K_gene_E2F_gene_cRAF = binding_parameter_dictionary["K_gene_E2F_gene_cRAF"]
	n_gene_EGR1_gene_Trigger = binding_parameter_dictionary["n_gene_EGR1_gene_Trigger"]
	K_gene_EGR1_gene_Trigger = binding_parameter_dictionary["K_gene_EGR1_gene_Trigger"]
	n_gene_EGR1_gene_PU1 = binding_parameter_dictionary["n_gene_EGR1_gene_PU1"]
	K_gene_EGR1_gene_PU1 = binding_parameter_dictionary["K_gene_EGR1_gene_PU1"]
	n_gene_EGR1_gene_PPARg = binding_parameter_dictionary["n_gene_EGR1_gene_PPARg"]
	K_gene_EGR1_gene_PPARg = binding_parameter_dictionary["K_gene_EGR1_gene_PPARg"]
	n_gene_EGR1_gene_GFI1 = binding_parameter_dictionary["n_gene_EGR1_gene_GFI1"]
	K_gene_EGR1_gene_GFI1 = binding_parameter_dictionary["K_gene_EGR1_gene_GFI1"]
	n_gene_GFI1_gene_CEBPa = binding_parameter_dictionary["n_gene_GFI1_gene_CEBPa"]
	K_gene_GFI1_gene_CEBPa = binding_parameter_dictionary["K_gene_GFI1_gene_CEBPa"]
	n_gene_GFI1_gene_EGR1 = binding_parameter_dictionary["n_gene_GFI1_gene_EGR1"]
	K_gene_GFI1_gene_EGR1 = binding_parameter_dictionary["K_gene_GFI1_gene_EGR1"]
	n_gene_IRF1_gene_Trigger = binding_parameter_dictionary["n_gene_IRF1_gene_Trigger"]
	K_gene_IRF1_gene_Trigger = binding_parameter_dictionary["K_gene_IRF1_gene_Trigger"]
	n_gene_IRF1_gene_AhR = binding_parameter_dictionary["n_gene_IRF1_gene_AhR"]
	K_gene_IRF1_gene_AhR = binding_parameter_dictionary["K_gene_IRF1_gene_AhR"]
	n_gene_IRF1_gene_PPARg = binding_parameter_dictionary["n_gene_IRF1_gene_PPARg"]
	K_gene_IRF1_gene_PPARg = binding_parameter_dictionary["K_gene_IRF1_gene_PPARg"]
	n_gene_OCT1_gene_PPARg = binding_parameter_dictionary["n_gene_OCT1_gene_PPARg"]
	K_gene_OCT1_gene_PPARg = binding_parameter_dictionary["K_gene_OCT1_gene_PPARg"]
	n_gene_OCT4_gene_Trigger = binding_parameter_dictionary["n_gene_OCT4_gene_Trigger"]
	K_gene_OCT4_gene_Trigger = binding_parameter_dictionary["K_gene_OCT4_gene_Trigger"]
	n_gene_OCT4_gene_AhR = binding_parameter_dictionary["n_gene_OCT4_gene_AhR"]
	K_gene_OCT4_gene_AhR = binding_parameter_dictionary["K_gene_OCT4_gene_AhR"]
	n_gene_OCT4_gene_cRAF = binding_parameter_dictionary["n_gene_OCT4_gene_cRAF"]
	K_gene_OCT4_gene_cRAF = binding_parameter_dictionary["K_gene_OCT4_gene_cRAF"]
	n_gene_P21_gene_Trigger_gene_AP1_gene_PPARg_gene_PU1_gene_IRF1_gene_CEBPa_gene_cRAF = binding_parameter_dictionary["n_gene_P21_gene_Trigger_gene_AP1_gene_PPARg_gene_PU1_gene_IRF1_gene_CEBPa_gene_cRAF"]
	K_gene_P21_gene_Trigger_gene_AP1_gene_PPARg_gene_PU1_gene_IRF1_gene_CEBPa_gene_cRAF = binding_parameter_dictionary["K_gene_P21_gene_Trigger_gene_AP1_gene_PPARg_gene_PU1_gene_IRF1_gene_CEBPa_gene_cRAF"]
	n_gene_P21_gene_GFI1 = binding_parameter_dictionary["n_gene_P21_gene_GFI1"]
	K_gene_P21_gene_GFI1 = binding_parameter_dictionary["K_gene_P21_gene_GFI1"]
	n_gene_P47Phox_gene_PU1_gene_CEBPa_gene_cRAF = binding_parameter_dictionary["n_gene_P47Phox_gene_PU1_gene_CEBPa_gene_cRAF"]
	K_gene_P47Phox_gene_PU1_gene_CEBPa_gene_cRAF = binding_parameter_dictionary["K_gene_P47Phox_gene_PU1_gene_CEBPa_gene_cRAF"]
	n_gene_P47Phox_gene_PPARg = binding_parameter_dictionary["n_gene_P47Phox_gene_PPARg"]
	K_gene_P47Phox_gene_PPARg = binding_parameter_dictionary["K_gene_P47Phox_gene_PPARg"]
	n_gene_PPARg_gene_Trigger = binding_parameter_dictionary["n_gene_PPARg_gene_Trigger"]
	K_gene_PPARg_gene_Trigger = binding_parameter_dictionary["K_gene_PPARg_gene_Trigger"]
	n_gene_PPARg_gene_CEBPa = binding_parameter_dictionary["n_gene_PPARg_gene_CEBPa"]
	K_gene_PPARg_gene_CEBPa = binding_parameter_dictionary["K_gene_PPARg_gene_CEBPa"]
	n_gene_PPARg_gene_EGR1 = binding_parameter_dictionary["n_gene_PPARg_gene_EGR1"]
	K_gene_PPARg_gene_EGR1 = binding_parameter_dictionary["K_gene_PPARg_gene_EGR1"]
	n_gene_PPARg_gene_PU1 = binding_parameter_dictionary["n_gene_PPARg_gene_PU1"]
	K_gene_PPARg_gene_PU1 = binding_parameter_dictionary["K_gene_PPARg_gene_PU1"]
	n_gene_PPARg_gene_AP1 = binding_parameter_dictionary["n_gene_PPARg_gene_AP1"]
	K_gene_PPARg_gene_AP1 = binding_parameter_dictionary["K_gene_PPARg_gene_AP1"]
	n_gene_PU1_gene_Trigger = binding_parameter_dictionary["n_gene_PU1_gene_Trigger"]
	K_gene_PU1_gene_Trigger = binding_parameter_dictionary["K_gene_PU1_gene_Trigger"]
	n_gene_PU1_gene_CEBPa = binding_parameter_dictionary["n_gene_PU1_gene_CEBPa"]
	K_gene_PU1_gene_CEBPa = binding_parameter_dictionary["K_gene_PU1_gene_CEBPa"]
	n_gene_PU1_gene_PU1 = binding_parameter_dictionary["n_gene_PU1_gene_PU1"]
	K_gene_PU1_gene_PU1 = binding_parameter_dictionary["K_gene_PU1_gene_PU1"]
	n_gene_PU1_gene_AP1 = binding_parameter_dictionary["n_gene_PU1_gene_AP1"]
	K_gene_PU1_gene_AP1 = binding_parameter_dictionary["K_gene_PU1_gene_AP1"]
	n_gene_PU1_gene_OCT1 = binding_parameter_dictionary["n_gene_PU1_gene_OCT1"]
	K_gene_PU1_gene_OCT1 = binding_parameter_dictionary["K_gene_PU1_gene_OCT1"]
	n_gene_PU1_gene_AhR = binding_parameter_dictionary["n_gene_PU1_gene_AhR"]
	K_gene_PU1_gene_AhR = binding_parameter_dictionary["K_gene_PU1_gene_AhR"]
	n_gene_PU1_gene_GFI1 = binding_parameter_dictionary["n_gene_PU1_gene_GFI1"]
	K_gene_PU1_gene_GFI1 = binding_parameter_dictionary["K_gene_PU1_gene_GFI1"]

	# Alias the control function parameters -
	control_parameter_dictionary = data_dictionary["control_parameter_dictionary"]
	W_gene_AP1_RNAP = control_parameter_dictionary["W_gene_AP1_RNAP"]
	W_gene_AP1_gene_AhR = control_parameter_dictionary["W_gene_AP1_gene_AhR"]
	W_gene_AP1_gene_PU1 = control_parameter_dictionary["W_gene_AP1_gene_PU1"]
	W_gene_AP1_gene_PPARg = control_parameter_dictionary["W_gene_AP1_gene_PPARg"]
	W_gene_AhR_RNAP = control_parameter_dictionary["W_gene_AhR_RNAP"]
	W_gene_AhR_gene_Trigger = control_parameter_dictionary["W_gene_AhR_gene_Trigger"]
	W_gene_CD11b_RNAP = control_parameter_dictionary["W_gene_CD11b_RNAP"]
	W_gene_CD11b_gene_PU1_gene_cRAF = control_parameter_dictionary["W_gene_CD11b_gene_PU1_gene_cRAF"]
	W_gene_CD14_RNAP = control_parameter_dictionary["W_gene_CD14_RNAP"]
	W_gene_CD14_gene_PPARg_gene_CEBPa_gene_EGR1_gene_cRAF = control_parameter_dictionary["W_gene_CD14_gene_PPARg_gene_CEBPa_gene_EGR1_gene_cRAF"]
	W_gene_CD38_RNAP = control_parameter_dictionary["W_gene_CD38_RNAP"]
	W_gene_CD38_gene_IRF1_gene_PPARg_gene_Trigger_gene_cRAF = control_parameter_dictionary["W_gene_CD38_gene_IRF1_gene_PPARg_gene_Trigger_gene_cRAF"]
	W_gene_CEBPa_RNAP = control_parameter_dictionary["W_gene_CEBPa_RNAP"]
	W_gene_CEBPa_gene_Trigger = control_parameter_dictionary["W_gene_CEBPa_gene_Trigger"]
	W_gene_CEBPa_gene_PPARg = control_parameter_dictionary["W_gene_CEBPa_gene_PPARg"]
	W_gene_CEBPa_gene_CEBPa = control_parameter_dictionary["W_gene_CEBPa_gene_CEBPa"]
	W_gene_CEBPa_gene_GFI1 = control_parameter_dictionary["W_gene_CEBPa_gene_GFI1"]
	W_gene_E2F_RNAP = control_parameter_dictionary["W_gene_E2F_RNAP"]
	W_gene_E2F_gene_E2F = control_parameter_dictionary["W_gene_E2F_gene_E2F"]
	W_gene_E2F_gene_PPARg = control_parameter_dictionary["W_gene_E2F_gene_PPARg"]
	W_gene_E2F_gene_CEBPa = control_parameter_dictionary["W_gene_E2F_gene_CEBPa"]
	W_gene_E2F_gene_GFI1 = control_parameter_dictionary["W_gene_E2F_gene_GFI1"]
	W_gene_E2F_gene_cRAF = control_parameter_dictionary["W_gene_E2F_gene_cRAF"]
	W_gene_EGR1_RNAP = control_parameter_dictionary["W_gene_EGR1_RNAP"]
	W_gene_EGR1_gene_Trigger = control_parameter_dictionary["W_gene_EGR1_gene_Trigger"]
	W_gene_EGR1_gene_PU1 = control_parameter_dictionary["W_gene_EGR1_gene_PU1"]
	W_gene_EGR1_gene_PPARg = control_parameter_dictionary["W_gene_EGR1_gene_PPARg"]
	W_gene_EGR1_gene_GFI1 = control_parameter_dictionary["W_gene_EGR1_gene_GFI1"]
	W_gene_GFI1_RNAP = control_parameter_dictionary["W_gene_GFI1_RNAP"]
	W_gene_GFI1_gene_CEBPa = control_parameter_dictionary["W_gene_GFI1_gene_CEBPa"]
	W_gene_GFI1_gene_EGR1 = control_parameter_dictionary["W_gene_GFI1_gene_EGR1"]
	W_gene_IRF1_RNAP = control_parameter_dictionary["W_gene_IRF1_RNAP"]
	W_gene_IRF1_gene_Trigger = control_parameter_dictionary["W_gene_IRF1_gene_Trigger"]
	W_gene_IRF1_gene_AhR = control_parameter_dictionary["W_gene_IRF1_gene_AhR"]
	W_gene_IRF1_gene_PPARg = control_parameter_dictionary["W_gene_IRF1_gene_PPARg"]
	W_gene_OCT1_RNAP = control_parameter_dictionary["W_gene_OCT1_RNAP"]
	W_gene_OCT1_gene_PPARg = control_parameter_dictionary["W_gene_OCT1_gene_PPARg"]
	W_gene_OCT4_RNAP = control_parameter_dictionary["W_gene_OCT4_RNAP"]
	W_gene_OCT4_gene_Trigger = control_parameter_dictionary["W_gene_OCT4_gene_Trigger"]
	W_gene_OCT4_gene_AhR = control_parameter_dictionary["W_gene_OCT4_gene_AhR"]
	W_gene_OCT4_gene_cRAF = control_parameter_dictionary["W_gene_OCT4_gene_cRAF"]
	W_gene_P21_RNAP = control_parameter_dictionary["W_gene_P21_RNAP"]
	W_gene_P21_gene_Trigger_gene_AP1_gene_PPARg_gene_PU1_gene_IRF1_gene_CEBPa_gene_cRAF = control_parameter_dictionary["W_gene_P21_gene_Trigger_gene_AP1_gene_PPARg_gene_PU1_gene_IRF1_gene_CEBPa_gene_cRAF"]
	W_gene_P21_gene_GFI1 = control_parameter_dictionary["W_gene_P21_gene_GFI1"]
	W_gene_P47Phox_RNAP = control_parameter_dictionary["W_gene_P47Phox_RNAP"]
	W_gene_P47Phox_gene_PU1_gene_CEBPa_gene_cRAF = control_parameter_dictionary["W_gene_P47Phox_gene_PU1_gene_CEBPa_gene_cRAF"]
	W_gene_P47Phox_gene_PPARg = control_parameter_dictionary["W_gene_P47Phox_gene_PPARg"]
	W_gene_PPARg_RNAP = control_parameter_dictionary["W_gene_PPARg_RNAP"]
	W_gene_PPARg_gene_Trigger = control_parameter_dictionary["W_gene_PPARg_gene_Trigger"]
	W_gene_PPARg_gene_CEBPa = control_parameter_dictionary["W_gene_PPARg_gene_CEBPa"]
	W_gene_PPARg_gene_EGR1 = control_parameter_dictionary["W_gene_PPARg_gene_EGR1"]
	W_gene_PPARg_gene_PU1 = control_parameter_dictionary["W_gene_PPARg_gene_PU1"]
	W_gene_PPARg_gene_AP1 = control_parameter_dictionary["W_gene_PPARg_gene_AP1"]
	W_gene_PU1_RNAP = control_parameter_dictionary["W_gene_PU1_RNAP"]
	W_gene_PU1_gene_Trigger = control_parameter_dictionary["W_gene_PU1_gene_Trigger"]
	W_gene_PU1_gene_CEBPa = control_parameter_dictionary["W_gene_PU1_gene_CEBPa"]
	W_gene_PU1_gene_PU1 = control_parameter_dictionary["W_gene_PU1_gene_PU1"]
	W_gene_PU1_gene_AP1 = control_parameter_dictionary["W_gene_PU1_gene_AP1"]
	W_gene_PU1_gene_OCT1 = control_parameter_dictionary["W_gene_PU1_gene_OCT1"]
	W_gene_PU1_gene_AhR = control_parameter_dictionary["W_gene_PU1_gene_AhR"]
	W_gene_PU1_gene_GFI1 = control_parameter_dictionary["W_gene_PU1_gene_GFI1"]
	W_gene_Trigger_RNAP = control_parameter_dictionary["W_gene_Trigger_RNAP"]
	W_gene_cRAF_RNAP = control_parameter_dictionary["W_gene_cRAF_RNAP"]

	# Transfer function target:gene_AP1 actor:gene_AhR
	actor_set_gene_AP1_gene_AhR = [
		protein_gene_AhR
	]
	actor = prod(actor_set_gene_AP1_gene_AhR)
	b_gene_AP1_gene_AhR = (actor^(n_gene_AP1_gene_AhR))/(K_gene_AP1_gene_AhR^(n_gene_AP1_gene_AhR)+actor^(n_gene_AP1_gene_AhR))

	# Transfer function target:gene_AP1 actor:gene_PU1
	actor_set_gene_AP1_gene_PU1 = [
		protein_gene_PU1
	]
	actor = prod(actor_set_gene_AP1_gene_PU1)
	b_gene_AP1_gene_PU1 = (actor^(n_gene_AP1_gene_PU1))/(K_gene_AP1_gene_PU1^(n_gene_AP1_gene_PU1)+actor^(n_gene_AP1_gene_PU1))

	# Transfer function target:gene_AP1 actor:gene_PPARg
	actor_set_gene_AP1_gene_PPARg = [
		protein_gene_PPARg
	]
	actor = prod(actor_set_gene_AP1_gene_PPARg)
	b_gene_AP1_gene_PPARg = (actor^(n_gene_AP1_gene_PPARg))/(K_gene_AP1_gene_PPARg^(n_gene_AP1_gene_PPARg)+actor^(n_gene_AP1_gene_PPARg))

	# Control function for gene_AP1 -
	control_array[1] = (W_gene_AP1_RNAP+W_gene_AP1_gene_AhR*b_gene_AP1_gene_AhR+W_gene_AP1_gene_PU1*b_gene_AP1_gene_PU1)/(1+W_gene_AP1_RNAP+W_gene_AP1_gene_AhR*b_gene_AP1_gene_AhR+W_gene_AP1_gene_PU1*b_gene_AP1_gene_PU1+W_gene_AP1_gene_PPARg*b_gene_AP1_gene_PPARg)

	# Transfer function target:gene_AhR actor:gene_Trigger
	actor_set_gene_AhR_gene_Trigger = [
		protein_gene_Trigger
	]
	actor = prod(actor_set_gene_AhR_gene_Trigger)
	b_gene_AhR_gene_Trigger = (actor^(n_gene_AhR_gene_Trigger))/(K_gene_AhR_gene_Trigger^(n_gene_AhR_gene_Trigger)+actor^(n_gene_AhR_gene_Trigger))

	# Control function for gene_AhR -
	control_array[2] = (W_gene_AhR_RNAP+W_gene_AhR_gene_Trigger*b_gene_AhR_gene_Trigger)/(1+W_gene_AhR_RNAP+W_gene_AhR_gene_Trigger*b_gene_AhR_gene_Trigger)

	# Transfer function target:gene_CD11b actor:gene_PU1_gene_cRAF
	actor_set_gene_CD11b_gene_PU1_gene_cRAF = [
		protein_gene_PU1
		protein_gene_cRAF
	]
	actor = prod(actor_set_gene_CD11b_gene_PU1_gene_cRAF)
	b_gene_CD11b_gene_PU1_gene_cRAF = (actor^(n_gene_CD11b_gene_PU1_gene_cRAF))/(K_gene_CD11b_gene_PU1_gene_cRAF^(n_gene_CD11b_gene_PU1_gene_cRAF)+actor^(n_gene_CD11b_gene_PU1_gene_cRAF))

	# Control function for gene_CD11b -
	control_array[3] = (W_gene_CD11b_RNAP+W_gene_CD11b_gene_PU1_gene_cRAF*b_gene_CD11b_gene_PU1_gene_cRAF)/(1+W_gene_CD11b_RNAP+W_gene_CD11b_gene_PU1_gene_cRAF*b_gene_CD11b_gene_PU1_gene_cRAF)

	# Transfer function target:gene_CD14 actor:gene_PPARg_gene_CEBPa_gene_EGR1_gene_cRAF
	actor_set_gene_CD14_gene_PPARg_gene_CEBPa_gene_EGR1_gene_cRAF = [
		protein_gene_PPARg
		protein_gene_CEBPa
		protein_gene_EGR1
		protein_gene_cRAF
	]
	actor = prod(actor_set_gene_CD14_gene_PPARg_gene_CEBPa_gene_EGR1_gene_cRAF)
	b_gene_CD14_gene_PPARg_gene_CEBPa_gene_EGR1_gene_cRAF = (actor^(n_gene_CD14_gene_PPARg_gene_CEBPa_gene_EGR1_gene_cRAF))/(K_gene_CD14_gene_PPARg_gene_CEBPa_gene_EGR1_gene_cRAF^(n_gene_CD14_gene_PPARg_gene_CEBPa_gene_EGR1_gene_cRAF)+actor^(n_gene_CD14_gene_PPARg_gene_CEBPa_gene_EGR1_gene_cRAF))

	# Control function for gene_CD14 -
	control_array[4] = (W_gene_CD14_RNAP+W_gene_CD14_gene_PPARg_gene_CEBPa_gene_EGR1_gene_cRAF*b_gene_CD14_gene_PPARg_gene_CEBPa_gene_EGR1_gene_cRAF)/(1+W_gene_CD14_RNAP+W_gene_CD14_gene_PPARg_gene_CEBPa_gene_EGR1_gene_cRAF*b_gene_CD14_gene_PPARg_gene_CEBPa_gene_EGR1_gene_cRAF)

	# Transfer function target:gene_CD38 actor:gene_IRF1_gene_PPARg_gene_Trigger_gene_cRAF
	actor_set_gene_CD38_gene_IRF1_gene_PPARg_gene_Trigger_gene_cRAF = [
		protein_gene_IRF1
		protein_gene_PPARg
		protein_gene_Trigger
		protein_gene_cRAF
	]
	actor = prod(actor_set_gene_CD38_gene_IRF1_gene_PPARg_gene_Trigger_gene_cRAF)
	b_gene_CD38_gene_IRF1_gene_PPARg_gene_Trigger_gene_cRAF = (actor^(n_gene_CD38_gene_IRF1_gene_PPARg_gene_Trigger_gene_cRAF))/(K_gene_CD38_gene_IRF1_gene_PPARg_gene_Trigger_gene_cRAF^(n_gene_CD38_gene_IRF1_gene_PPARg_gene_Trigger_gene_cRAF)+actor^(n_gene_CD38_gene_IRF1_gene_PPARg_gene_Trigger_gene_cRAF))

	# Control function for gene_CD38 -
	control_array[5] = (W_gene_CD38_RNAP+W_gene_CD38_gene_IRF1_gene_PPARg_gene_Trigger_gene_cRAF*b_gene_CD38_gene_IRF1_gene_PPARg_gene_Trigger_gene_cRAF)/(1+W_gene_CD38_RNAP+W_gene_CD38_gene_IRF1_gene_PPARg_gene_Trigger_gene_cRAF*b_gene_CD38_gene_IRF1_gene_PPARg_gene_Trigger_gene_cRAF)

	# Transfer function target:gene_CEBPa actor:gene_Trigger
	actor_set_gene_CEBPa_gene_Trigger = [
		protein_gene_Trigger
	]
	actor = prod(actor_set_gene_CEBPa_gene_Trigger)
	b_gene_CEBPa_gene_Trigger = (actor^(n_gene_CEBPa_gene_Trigger))/(K_gene_CEBPa_gene_Trigger^(n_gene_CEBPa_gene_Trigger)+actor^(n_gene_CEBPa_gene_Trigger))

	# Transfer function target:gene_CEBPa actor:gene_PPARg
	actor_set_gene_CEBPa_gene_PPARg = [
		protein_gene_PPARg
	]
	actor = prod(actor_set_gene_CEBPa_gene_PPARg)
	b_gene_CEBPa_gene_PPARg = (actor^(n_gene_CEBPa_gene_PPARg))/(K_gene_CEBPa_gene_PPARg^(n_gene_CEBPa_gene_PPARg)+actor^(n_gene_CEBPa_gene_PPARg))

	# Transfer function target:gene_CEBPa actor:gene_CEBPa
	actor_set_gene_CEBPa_gene_CEBPa = [
		protein_gene_CEBPa
	]
	actor = prod(actor_set_gene_CEBPa_gene_CEBPa)
	b_gene_CEBPa_gene_CEBPa = (actor^(n_gene_CEBPa_gene_CEBPa))/(K_gene_CEBPa_gene_CEBPa^(n_gene_CEBPa_gene_CEBPa)+actor^(n_gene_CEBPa_gene_CEBPa))

	# Transfer function target:gene_CEBPa actor:gene_GFI1
	actor_set_gene_CEBPa_gene_GFI1 = [
		protein_gene_GFI1
	]
	actor = prod(actor_set_gene_CEBPa_gene_GFI1)
	b_gene_CEBPa_gene_GFI1 = (actor^(n_gene_CEBPa_gene_GFI1))/(K_gene_CEBPa_gene_GFI1^(n_gene_CEBPa_gene_GFI1)+actor^(n_gene_CEBPa_gene_GFI1))

	# Control function for gene_CEBPa -
	control_array[6] = (W_gene_CEBPa_RNAP+W_gene_CEBPa_gene_Trigger*b_gene_CEBPa_gene_Trigger+W_gene_CEBPa_gene_PPARg*b_gene_CEBPa_gene_PPARg+W_gene_CEBPa_gene_CEBPa*b_gene_CEBPa_gene_CEBPa)/(1+W_gene_CEBPa_RNAP+W_gene_CEBPa_gene_Trigger*b_gene_CEBPa_gene_Trigger+W_gene_CEBPa_gene_PPARg*b_gene_CEBPa_gene_PPARg+W_gene_CEBPa_gene_CEBPa*b_gene_CEBPa_gene_CEBPa+W_gene_CEBPa_gene_GFI1*b_gene_CEBPa_gene_GFI1)

	# Transfer function target:gene_E2F actor:gene_E2F
	actor_set_gene_E2F_gene_E2F = [
		protein_gene_E2F
	]
	actor = prod(actor_set_gene_E2F_gene_E2F)
	b_gene_E2F_gene_E2F = (actor^(n_gene_E2F_gene_E2F))/(K_gene_E2F_gene_E2F^(n_gene_E2F_gene_E2F)+actor^(n_gene_E2F_gene_E2F))

	# Transfer function target:gene_E2F actor:gene_PPARg
	actor_set_gene_E2F_gene_PPARg = [
		protein_gene_PPARg
	]
	actor = prod(actor_set_gene_E2F_gene_PPARg)
	b_gene_E2F_gene_PPARg = (actor^(n_gene_E2F_gene_PPARg))/(K_gene_E2F_gene_PPARg^(n_gene_E2F_gene_PPARg)+actor^(n_gene_E2F_gene_PPARg))

	# Transfer function target:gene_E2F actor:gene_CEBPa
	actor_set_gene_E2F_gene_CEBPa = [
		protein_gene_CEBPa
	]
	actor = prod(actor_set_gene_E2F_gene_CEBPa)
	b_gene_E2F_gene_CEBPa = (actor^(n_gene_E2F_gene_CEBPa))/(K_gene_E2F_gene_CEBPa^(n_gene_E2F_gene_CEBPa)+actor^(n_gene_E2F_gene_CEBPa))

	# Transfer function target:gene_E2F actor:gene_GFI1
	actor_set_gene_E2F_gene_GFI1 = [
		protein_gene_GFI1
	]
	actor = prod(actor_set_gene_E2F_gene_GFI1)
	b_gene_E2F_gene_GFI1 = (actor^(n_gene_E2F_gene_GFI1))/(K_gene_E2F_gene_GFI1^(n_gene_E2F_gene_GFI1)+actor^(n_gene_E2F_gene_GFI1))

	# Transfer function target:gene_E2F actor:gene_cRAF
	actor_set_gene_E2F_gene_cRAF = [
		protein_gene_cRAF
	]
	actor = prod(actor_set_gene_E2F_gene_cRAF)
	b_gene_E2F_gene_cRAF = (actor^(n_gene_E2F_gene_cRAF))/(K_gene_E2F_gene_cRAF^(n_gene_E2F_gene_cRAF)+actor^(n_gene_E2F_gene_cRAF))

	# Control function for gene_E2F -
	control_array[7] = (W_gene_E2F_RNAP+W_gene_E2F_gene_E2F*b_gene_E2F_gene_E2F)/(1+W_gene_E2F_RNAP+W_gene_E2F_gene_E2F*b_gene_E2F_gene_E2F+W_gene_E2F_gene_PPARg*b_gene_E2F_gene_PPARg+W_gene_E2F_gene_CEBPa*b_gene_E2F_gene_CEBPa+W_gene_E2F_gene_GFI1*b_gene_E2F_gene_GFI1+W_gene_E2F_gene_cRAF*b_gene_E2F_gene_cRAF)

	# Transfer function target:gene_EGR1 actor:gene_Trigger
	actor_set_gene_EGR1_gene_Trigger = [
		protein_gene_Trigger
	]
	actor = prod(actor_set_gene_EGR1_gene_Trigger)
	b_gene_EGR1_gene_Trigger = (actor^(n_gene_EGR1_gene_Trigger))/(K_gene_EGR1_gene_Trigger^(n_gene_EGR1_gene_Trigger)+actor^(n_gene_EGR1_gene_Trigger))

	# Transfer function target:gene_EGR1 actor:gene_PU1
	actor_set_gene_EGR1_gene_PU1 = [
		protein_gene_PU1
	]
	actor = prod(actor_set_gene_EGR1_gene_PU1)
	b_gene_EGR1_gene_PU1 = (actor^(n_gene_EGR1_gene_PU1))/(K_gene_EGR1_gene_PU1^(n_gene_EGR1_gene_PU1)+actor^(n_gene_EGR1_gene_PU1))

	# Transfer function target:gene_EGR1 actor:gene_PPARg
	actor_set_gene_EGR1_gene_PPARg = [
		protein_gene_PPARg
	]
	actor = prod(actor_set_gene_EGR1_gene_PPARg)
	b_gene_EGR1_gene_PPARg = (actor^(n_gene_EGR1_gene_PPARg))/(K_gene_EGR1_gene_PPARg^(n_gene_EGR1_gene_PPARg)+actor^(n_gene_EGR1_gene_PPARg))

	# Transfer function target:gene_EGR1 actor:gene_GFI1
	actor_set_gene_EGR1_gene_GFI1 = [
		protein_gene_GFI1
	]
	actor = prod(actor_set_gene_EGR1_gene_GFI1)
	b_gene_EGR1_gene_GFI1 = (actor^(n_gene_EGR1_gene_GFI1))/(K_gene_EGR1_gene_GFI1^(n_gene_EGR1_gene_GFI1)+actor^(n_gene_EGR1_gene_GFI1))

	# Control function for gene_EGR1 -
	control_array[8] = (W_gene_EGR1_RNAP+W_gene_EGR1_gene_Trigger*b_gene_EGR1_gene_Trigger+W_gene_EGR1_gene_PU1*b_gene_EGR1_gene_PU1)/(1+W_gene_EGR1_RNAP+W_gene_EGR1_gene_Trigger*b_gene_EGR1_gene_Trigger+W_gene_EGR1_gene_PU1*b_gene_EGR1_gene_PU1+W_gene_EGR1_gene_PPARg*b_gene_EGR1_gene_PPARg+W_gene_EGR1_gene_GFI1*b_gene_EGR1_gene_GFI1)

	# Transfer function target:gene_GFI1 actor:gene_CEBPa
	actor_set_gene_GFI1_gene_CEBPa = [
		protein_gene_CEBPa
	]
	actor = prod(actor_set_gene_GFI1_gene_CEBPa)
	b_gene_GFI1_gene_CEBPa = (actor^(n_gene_GFI1_gene_CEBPa))/(K_gene_GFI1_gene_CEBPa^(n_gene_GFI1_gene_CEBPa)+actor^(n_gene_GFI1_gene_CEBPa))

	# Transfer function target:gene_GFI1 actor:gene_EGR1
	actor_set_gene_GFI1_gene_EGR1 = [
		protein_gene_EGR1
	]
	actor = prod(actor_set_gene_GFI1_gene_EGR1)
	b_gene_GFI1_gene_EGR1 = (actor^(n_gene_GFI1_gene_EGR1))/(K_gene_GFI1_gene_EGR1^(n_gene_GFI1_gene_EGR1)+actor^(n_gene_GFI1_gene_EGR1))

	# Control function for gene_GFI1 -
	control_array[9] = (W_gene_GFI1_RNAP+W_gene_GFI1_gene_CEBPa*b_gene_GFI1_gene_CEBPa)/(1+W_gene_GFI1_RNAP+W_gene_GFI1_gene_CEBPa*b_gene_GFI1_gene_CEBPa+W_gene_GFI1_gene_EGR1*b_gene_GFI1_gene_EGR1)

	# Transfer function target:gene_IRF1 actor:gene_Trigger
	actor_set_gene_IRF1_gene_Trigger = [
		protein_gene_Trigger
	]
	actor = prod(actor_set_gene_IRF1_gene_Trigger)
	b_gene_IRF1_gene_Trigger = (actor^(n_gene_IRF1_gene_Trigger))/(K_gene_IRF1_gene_Trigger^(n_gene_IRF1_gene_Trigger)+actor^(n_gene_IRF1_gene_Trigger))

	# Transfer function target:gene_IRF1 actor:gene_AhR
	actor_set_gene_IRF1_gene_AhR = [
		protein_gene_AhR
	]
	actor = prod(actor_set_gene_IRF1_gene_AhR)
	b_gene_IRF1_gene_AhR = (actor^(n_gene_IRF1_gene_AhR))/(K_gene_IRF1_gene_AhR^(n_gene_IRF1_gene_AhR)+actor^(n_gene_IRF1_gene_AhR))

	# Transfer function target:gene_IRF1 actor:gene_PPARg
	actor_set_gene_IRF1_gene_PPARg = [
		protein_gene_PPARg
	]
	actor = prod(actor_set_gene_IRF1_gene_PPARg)
	b_gene_IRF1_gene_PPARg = (actor^(n_gene_IRF1_gene_PPARg))/(K_gene_IRF1_gene_PPARg^(n_gene_IRF1_gene_PPARg)+actor^(n_gene_IRF1_gene_PPARg))

	# Control function for gene_IRF1 -
	control_array[10] = (W_gene_IRF1_RNAP+W_gene_IRF1_gene_Trigger*b_gene_IRF1_gene_Trigger+W_gene_IRF1_gene_AhR*b_gene_IRF1_gene_AhR+W_gene_IRF1_gene_PPARg*b_gene_IRF1_gene_PPARg)/(1+W_gene_IRF1_RNAP+W_gene_IRF1_gene_Trigger*b_gene_IRF1_gene_Trigger+W_gene_IRF1_gene_AhR*b_gene_IRF1_gene_AhR+W_gene_IRF1_gene_PPARg*b_gene_IRF1_gene_PPARg)

	# Transfer function target:gene_OCT1 actor:gene_PPARg
	actor_set_gene_OCT1_gene_PPARg = [
		protein_gene_PPARg
	]
	actor = prod(actor_set_gene_OCT1_gene_PPARg)
	b_gene_OCT1_gene_PPARg = (actor^(n_gene_OCT1_gene_PPARg))/(K_gene_OCT1_gene_PPARg^(n_gene_OCT1_gene_PPARg)+actor^(n_gene_OCT1_gene_PPARg))

	# Control function for gene_OCT1 -
	control_array[11] = (W_gene_OCT1_RNAP+W_gene_OCT1_gene_PPARg*b_gene_OCT1_gene_PPARg)/(1+W_gene_OCT1_RNAP+W_gene_OCT1_gene_PPARg*b_gene_OCT1_gene_PPARg)

	# Transfer function target:gene_OCT4 actor:gene_Trigger
	actor_set_gene_OCT4_gene_Trigger = [
		protein_gene_Trigger
	]
	actor = prod(actor_set_gene_OCT4_gene_Trigger)
	b_gene_OCT4_gene_Trigger = (actor^(n_gene_OCT4_gene_Trigger))/(K_gene_OCT4_gene_Trigger^(n_gene_OCT4_gene_Trigger)+actor^(n_gene_OCT4_gene_Trigger))

	# Transfer function target:gene_OCT4 actor:gene_AhR
	actor_set_gene_OCT4_gene_AhR = [
		protein_gene_AhR
	]
	actor = prod(actor_set_gene_OCT4_gene_AhR)
	b_gene_OCT4_gene_AhR = (actor^(n_gene_OCT4_gene_AhR))/(K_gene_OCT4_gene_AhR^(n_gene_OCT4_gene_AhR)+actor^(n_gene_OCT4_gene_AhR))

	# Transfer function target:gene_OCT4 actor:gene_cRAF
	actor_set_gene_OCT4_gene_cRAF = [
		protein_gene_cRAF
	]
	actor = prod(actor_set_gene_OCT4_gene_cRAF)
	b_gene_OCT4_gene_cRAF = (actor^(n_gene_OCT4_gene_cRAF))/(K_gene_OCT4_gene_cRAF^(n_gene_OCT4_gene_cRAF)+actor^(n_gene_OCT4_gene_cRAF))

	# Control function for gene_OCT4 -
	control_array[12] = (W_gene_OCT4_RNAP)/(1+W_gene_OCT4_RNAP+W_gene_OCT4_gene_Trigger*b_gene_OCT4_gene_Trigger+W_gene_OCT4_gene_AhR*b_gene_OCT4_gene_AhR+W_gene_OCT4_gene_cRAF*b_gene_OCT4_gene_cRAF)

	# Transfer function target:gene_P21 actor:gene_Trigger_gene_AP1_gene_PPARg_gene_PU1_gene_IRF1_gene_CEBPa_gene_cRAF
	actor_set_gene_P21_gene_Trigger_gene_AP1_gene_PPARg_gene_PU1_gene_IRF1_gene_CEBPa_gene_cRAF = [
		protein_gene_Trigger
		protein_gene_AP1
		protein_gene_PPARg
		protein_gene_PU1
		protein_gene_IRF1
		protein_gene_CEBPa
		protein_gene_cRAF
	]
	actor = prod(actor_set_gene_P21_gene_Trigger_gene_AP1_gene_PPARg_gene_PU1_gene_IRF1_gene_CEBPa_gene_cRAF)
	b_gene_P21_gene_Trigger_gene_AP1_gene_PPARg_gene_PU1_gene_IRF1_gene_CEBPa_gene_cRAF = (actor^(n_gene_P21_gene_Trigger_gene_AP1_gene_PPARg_gene_PU1_gene_IRF1_gene_CEBPa_gene_cRAF))/(K_gene_P21_gene_Trigger_gene_AP1_gene_PPARg_gene_PU1_gene_IRF1_gene_CEBPa_gene_cRAF^(n_gene_P21_gene_Trigger_gene_AP1_gene_PPARg_gene_PU1_gene_IRF1_gene_CEBPa_gene_cRAF)+actor^(n_gene_P21_gene_Trigger_gene_AP1_gene_PPARg_gene_PU1_gene_IRF1_gene_CEBPa_gene_cRAF))

	# Transfer function target:gene_P21 actor:gene_GFI1
	actor_set_gene_P21_gene_GFI1 = [
		protein_gene_GFI1
	]
	actor = prod(actor_set_gene_P21_gene_GFI1)
	b_gene_P21_gene_GFI1 = (actor^(n_gene_P21_gene_GFI1))/(K_gene_P21_gene_GFI1^(n_gene_P21_gene_GFI1)+actor^(n_gene_P21_gene_GFI1))

	# Control function for gene_P21 -
	control_array[13] = (W_gene_P21_RNAP+W_gene_P21_gene_Trigger_gene_AP1_gene_PPARg_gene_PU1_gene_IRF1_gene_CEBPa_gene_cRAF*b_gene_P21_gene_Trigger_gene_AP1_gene_PPARg_gene_PU1_gene_IRF1_gene_CEBPa_gene_cRAF)/(1+W_gene_P21_RNAP+W_gene_P21_gene_Trigger_gene_AP1_gene_PPARg_gene_PU1_gene_IRF1_gene_CEBPa_gene_cRAF*b_gene_P21_gene_Trigger_gene_AP1_gene_PPARg_gene_PU1_gene_IRF1_gene_CEBPa_gene_cRAF+W_gene_P21_gene_GFI1*b_gene_P21_gene_GFI1)

	# Transfer function target:gene_P47Phox actor:gene_PU1_gene_CEBPa_gene_cRAF
	actor_set_gene_P47Phox_gene_PU1_gene_CEBPa_gene_cRAF = [
		protein_gene_PU1
		protein_gene_CEBPa
		protein_gene_cRAF
	]
	actor = prod(actor_set_gene_P47Phox_gene_PU1_gene_CEBPa_gene_cRAF)
	b_gene_P47Phox_gene_PU1_gene_CEBPa_gene_cRAF = (actor^(n_gene_P47Phox_gene_PU1_gene_CEBPa_gene_cRAF))/(K_gene_P47Phox_gene_PU1_gene_CEBPa_gene_cRAF^(n_gene_P47Phox_gene_PU1_gene_CEBPa_gene_cRAF)+actor^(n_gene_P47Phox_gene_PU1_gene_CEBPa_gene_cRAF))

	# Transfer function target:gene_P47Phox actor:gene_PPARg
	actor_set_gene_P47Phox_gene_PPARg = [
		protein_gene_PPARg
	]
	actor = prod(actor_set_gene_P47Phox_gene_PPARg)
	b_gene_P47Phox_gene_PPARg = (actor^(n_gene_P47Phox_gene_PPARg))/(K_gene_P47Phox_gene_PPARg^(n_gene_P47Phox_gene_PPARg)+actor^(n_gene_P47Phox_gene_PPARg))

	# Control function for gene_P47Phox -
	control_array[14] = (W_gene_P47Phox_RNAP+W_gene_P47Phox_gene_PU1_gene_CEBPa_gene_cRAF*b_gene_P47Phox_gene_PU1_gene_CEBPa_gene_cRAF)/(1+W_gene_P47Phox_RNAP+W_gene_P47Phox_gene_PU1_gene_CEBPa_gene_cRAF*b_gene_P47Phox_gene_PU1_gene_CEBPa_gene_cRAF+W_gene_P47Phox_gene_PPARg*b_gene_P47Phox_gene_PPARg)

	# Transfer function target:gene_PPARg actor:gene_Trigger
	actor_set_gene_PPARg_gene_Trigger = [
		protein_gene_Trigger
	]
	actor = prod(actor_set_gene_PPARg_gene_Trigger)
	b_gene_PPARg_gene_Trigger = (actor^(n_gene_PPARg_gene_Trigger))/(K_gene_PPARg_gene_Trigger^(n_gene_PPARg_gene_Trigger)+actor^(n_gene_PPARg_gene_Trigger))

	# Transfer function target:gene_PPARg actor:gene_CEBPa
	actor_set_gene_PPARg_gene_CEBPa = [
		protein_gene_CEBPa
	]
	actor = prod(actor_set_gene_PPARg_gene_CEBPa)
	b_gene_PPARg_gene_CEBPa = (actor^(n_gene_PPARg_gene_CEBPa))/(K_gene_PPARg_gene_CEBPa^(n_gene_PPARg_gene_CEBPa)+actor^(n_gene_PPARg_gene_CEBPa))

	# Transfer function target:gene_PPARg actor:gene_EGR1
	actor_set_gene_PPARg_gene_EGR1 = [
		protein_gene_EGR1
	]
	actor = prod(actor_set_gene_PPARg_gene_EGR1)
	b_gene_PPARg_gene_EGR1 = (actor^(n_gene_PPARg_gene_EGR1))/(K_gene_PPARg_gene_EGR1^(n_gene_PPARg_gene_EGR1)+actor^(n_gene_PPARg_gene_EGR1))

	# Transfer function target:gene_PPARg actor:gene_PU1
	actor_set_gene_PPARg_gene_PU1 = [
		protein_gene_PU1
	]
	actor = prod(actor_set_gene_PPARg_gene_PU1)
	b_gene_PPARg_gene_PU1 = (actor^(n_gene_PPARg_gene_PU1))/(K_gene_PPARg_gene_PU1^(n_gene_PPARg_gene_PU1)+actor^(n_gene_PPARg_gene_PU1))

	# Transfer function target:gene_PPARg actor:gene_AP1
	actor_set_gene_PPARg_gene_AP1 = [
		protein_gene_AP1
	]
	actor = prod(actor_set_gene_PPARg_gene_AP1)
	b_gene_PPARg_gene_AP1 = (actor^(n_gene_PPARg_gene_AP1))/(K_gene_PPARg_gene_AP1^(n_gene_PPARg_gene_AP1)+actor^(n_gene_PPARg_gene_AP1))

	# Control function for gene_PPARg -
	control_array[15] = (W_gene_PPARg_RNAP+W_gene_PPARg_gene_Trigger*b_gene_PPARg_gene_Trigger+W_gene_PPARg_gene_CEBPa*b_gene_PPARg_gene_CEBPa+W_gene_PPARg_gene_EGR1*b_gene_PPARg_gene_EGR1)/(1+W_gene_PPARg_RNAP+W_gene_PPARg_gene_Trigger*b_gene_PPARg_gene_Trigger+W_gene_PPARg_gene_CEBPa*b_gene_PPARg_gene_CEBPa+W_gene_PPARg_gene_EGR1*b_gene_PPARg_gene_EGR1+W_gene_PPARg_gene_PU1*b_gene_PPARg_gene_PU1+W_gene_PPARg_gene_AP1*b_gene_PPARg_gene_AP1)

	# Transfer function target:gene_PU1 actor:gene_Trigger
	actor_set_gene_PU1_gene_Trigger = [
		protein_gene_Trigger
	]
	actor = prod(actor_set_gene_PU1_gene_Trigger)
	b_gene_PU1_gene_Trigger = (actor^(n_gene_PU1_gene_Trigger))/(K_gene_PU1_gene_Trigger^(n_gene_PU1_gene_Trigger)+actor^(n_gene_PU1_gene_Trigger))

	# Transfer function target:gene_PU1 actor:gene_CEBPa
	actor_set_gene_PU1_gene_CEBPa = [
		protein_gene_CEBPa
	]
	actor = prod(actor_set_gene_PU1_gene_CEBPa)
	b_gene_PU1_gene_CEBPa = (actor^(n_gene_PU1_gene_CEBPa))/(K_gene_PU1_gene_CEBPa^(n_gene_PU1_gene_CEBPa)+actor^(n_gene_PU1_gene_CEBPa))

	# Transfer function target:gene_PU1 actor:gene_PU1
	actor_set_gene_PU1_gene_PU1 = [
		protein_gene_PU1
	]
	actor = prod(actor_set_gene_PU1_gene_PU1)
	b_gene_PU1_gene_PU1 = (actor^(n_gene_PU1_gene_PU1))/(K_gene_PU1_gene_PU1^(n_gene_PU1_gene_PU1)+actor^(n_gene_PU1_gene_PU1))

	# Transfer function target:gene_PU1 actor:gene_AP1
	actor_set_gene_PU1_gene_AP1 = [
		protein_gene_AP1
	]
	actor = prod(actor_set_gene_PU1_gene_AP1)
	b_gene_PU1_gene_AP1 = (actor^(n_gene_PU1_gene_AP1))/(K_gene_PU1_gene_AP1^(n_gene_PU1_gene_AP1)+actor^(n_gene_PU1_gene_AP1))

	# Transfer function target:gene_PU1 actor:gene_OCT1
	actor_set_gene_PU1_gene_OCT1 = [
		protein_gene_OCT1
	]
	actor = prod(actor_set_gene_PU1_gene_OCT1)
	b_gene_PU1_gene_OCT1 = (actor^(n_gene_PU1_gene_OCT1))/(K_gene_PU1_gene_OCT1^(n_gene_PU1_gene_OCT1)+actor^(n_gene_PU1_gene_OCT1))

	# Transfer function target:gene_PU1 actor:gene_AhR
	actor_set_gene_PU1_gene_AhR = [
		protein_gene_AhR
	]
	actor = prod(actor_set_gene_PU1_gene_AhR)
	b_gene_PU1_gene_AhR = (actor^(n_gene_PU1_gene_AhR))/(K_gene_PU1_gene_AhR^(n_gene_PU1_gene_AhR)+actor^(n_gene_PU1_gene_AhR))

	# Transfer function target:gene_PU1 actor:gene_GFI1
	actor_set_gene_PU1_gene_GFI1 = [
		protein_gene_GFI1
	]
	actor = prod(actor_set_gene_PU1_gene_GFI1)
	b_gene_PU1_gene_GFI1 = (actor^(n_gene_PU1_gene_GFI1))/(K_gene_PU1_gene_GFI1^(n_gene_PU1_gene_GFI1)+actor^(n_gene_PU1_gene_GFI1))

	# Control function for gene_PU1 -
	control_array[16] = (W_gene_PU1_RNAP+W_gene_PU1_gene_Trigger*b_gene_PU1_gene_Trigger+W_gene_PU1_gene_CEBPa*b_gene_PU1_gene_CEBPa+W_gene_PU1_gene_PU1*b_gene_PU1_gene_PU1+W_gene_PU1_gene_AP1*b_gene_PU1_gene_AP1+W_gene_PU1_gene_OCT1*b_gene_PU1_gene_OCT1)/(1+W_gene_PU1_RNAP+W_gene_PU1_gene_Trigger*b_gene_PU1_gene_Trigger+W_gene_PU1_gene_CEBPa*b_gene_PU1_gene_CEBPa+W_gene_PU1_gene_PU1*b_gene_PU1_gene_PU1+W_gene_PU1_gene_AP1*b_gene_PU1_gene_AP1+W_gene_PU1_gene_OCT1*b_gene_PU1_gene_OCT1+W_gene_PU1_gene_AhR*b_gene_PU1_gene_AhR+W_gene_PU1_gene_GFI1*b_gene_PU1_gene_GFI1)

	# Control function for gene_Trigger -
	control_array[17] = (W_gene_Trigger_RNAP)/(1+W_gene_Trigger_RNAP)

	# Control function for gene_cRAF -
	control_array[18] = (W_gene_cRAF_RNAP)/(1+W_gene_cRAF_RNAP)

	# return -
	return control_array
end


text:
@testset "BaseNode" begin

@testset "BaseNode" begin
    node = BaseNode( "Node" )
    @test all( [node.name == "Node", node.target == -1,
        isempty( node.requirements )] )
end  # @testset "Constructor"

node = BaseNode( "State" )

@testset "function setNodeName!" begin
    setNodeName!( node, "Beep" )
    @test node.name == "Beep"
    setNodeName!( node, "Node" )
    @test node.name == "Node"
end  # @testset "function setNodeName!"

@testset "function setNodeTarget!" begin
    setNodeTarget!( node, 1000 )
    @test node.target == 1000
    setNodeTarget!( node, -5 )
    @test node.target == -1
    setNodeTarget!( node, 250 )
    @test node.target == 250
end  # @testset "function setNodeTarget!"

@testset "function setNodeAttritionScheme!" begin
    setNodeAttritionScheme!( node, "Attrition 1" )
    @test node.attrition === "Attrition 1"
    setNodeAttritionScheme!( node, "Attrition 2" )
    @test node.attrition === "Attrition 2"
end  # @testset "function setNodeAttritionScheme!"

@testset "function addNodeRequirement!" begin
    addNodeRequirement!( node, "rank category", "officer" )
    @test haskey( node.requirements, "rank category" ) &&
        ( node.requirements["rank category"] == "officer" )
    addNodeRequirement!( node, "rank", "captain" )
    @test haskey( node.requirements, "rank" ) &&
        ( node.requirements["rank"] == "captain" )
    addNodeRequirement!( node, ("branch", "ground force"), ("rank", "major") )
    @test all( [haskey( node.requirements, "branch" ),
        node.requirements["branch"] == "ground force",
        node.requirements["rank"] == "major"] )
    @test !addNodeRequirement!( node, ("sub branch", "artillery"),
        ("rank", "lieutenant"), ("sub branch", "engineers") )
    @test !haskey( node.requirements, "sub branch" ) &&
        ( node.requirements["rank"] == "major" )
end  # @testset "function addNodeRequirement!"

@testset "function removeNodeRequirement!" begin
    removeNodeRequirement!( node, "rank category" )
    @test !haskey( node.requirements, "rank category" )
    removeNodeRequirement!( node, "branch", "rank category" )
    @test !haskey( node.requirements, "branch" )
    @test !removeNodeRequirement!( node, "branch" )
end  # @testset "function removeNodeRequirement!"

@testset "function clearNodeRequirements!" begin
    clearNodeRequirements!( node )
    @test isempty( node.requirements )
end  # @testset "function clearNodeRequirements!"

@testset "function setNodeRequirements!" begin
    setNodeRequirements!( node, Dict( "rank" => "captain", "grade" => "A" ) )
    @test all( [length( node.requirements ) == 2,
        haskey( node.requirements, "rank" ),
        haskey( node.requirements, "grade" ),
        node.requirements["rank"] == "captain",
        node.requirements["grade"] == "A"] )
    setNodeRequirements!( node, ("rank", "corporal"), ("branch", "air") )
    @test all( [length( node.requirements ) == 2,
        haskey( node.requirements, "rank" ),
        haskey( node.requirements, "branch" ),
        node.requirements["rank"] == "corporal",
        node.requirements["branch"] == "air"] )
    setNodeRequirements!( node, ["grade"], ["D"] )
    @test all( [length( node.requirements ) == 1,
        haskey( node.requirements, "grade" ),
        node.requirements["grade"] == "D"] )
    @test !setNodeRequirements!( node, ("rank", "private"), ("grade", "D"),
        ("rank", "corporal") )
    @test !setNodeRequirements!( node, ["rank", "grade", "rank"],
        ["lieutenant", "A", "colonel"] )
    @test !setNodeRequirements!( node, ["rank"], ["colonel", "A"] )
end  # @testset "function setNodeRequirements!"

@testset "function isPersonnelOfNode" begin
    addNodeRequirement!( node, ("rank", "corporal") )
    @test MP.isPersonnelOfNode( Dict( "rank" => "corporal", "branch" => "navy",
        "grade" => "D" ), node )
    @test !MP.isPersonnelOfNode( Dict( "rank" => "sergeant", "grade" => "D" ),
        node )
    @test !MP.isPersonnelOfNode( Dict( "rank" => "corporal" ), node )
end  # @testset "function isPersonnelOfNode" begin

end  # @testset "BaseNode"


text:
module HTMLRenderer

import Revise
import Markdown, Logging, FilePaths, Gumbo
using Genie, Genie.Flax

const HTML_FILE_EXT      = [".flax.jl", "html.jl"]
const TEMPLATE_EXT  = [".flax.html", ".jl.html"]
const MARKDOWN_FILE_EXT = [".md", ".jl.md"]

const SUPPORTED_HTML_OUTPUT_FILE_FORMATS = TEMPLATE_EXT

const HTMLString = String
const HTMLParser = Gumbo

const MD_SEPARATOR_START = "---\n"
const MD_SEPARATOR_END   = "---\n"

const NBSP_REPLACEMENT = (" "=>"!!nbsp;;")

const NORMAL_ELEMENTS = [ :html, :head, :body, :title, :style, :address, :article, :aside, :footer,
                          :header, :h1, :h2, :h3, :h4, :h5, :h6, :hgroup, :nav, :section,
                          :dd, :div, :d, :dl, :dt, :figcaption, :figure, :li, :main, :ol, :p, :pre, :ul, :span,
                          :a, :abbr, :b, :bdi, :bdo, :cite, :code, :data, :dfn, :em, :i, :kbd, :mark,
                          :q, :rp, :rt, :rtc, :ruby, :s, :samp, :small, :spam, :strong, :sub, :sup, :time,
                          :u, :var, :wrb, :audio, :map, :void, :embed, :object, :canvas, :noscript, :script,
                          :del, :ins, :caption, :col, :colgroup, :table, :tbody, :td, :tfoot, :th, :thead, :tr,
                          :button, :datalist, :fieldset, :form, :label, :legend, :meter, :optgroup, :option,
                          :output, :progress, :select, :textarea, :details, :dialog, :menu, :menuitem, :summary,
                          :slot, :template, :blockquote, :center]
const VOID_ELEMENTS   = [:base, :link, :meta, :hr, :br, :area, :img, :track, :param, :source, :input]
const BOOL_ATTRIBUTES = [:checked, :disabled, :selected]

export HTMLString

"""
    normal_element(f::Function, elem::String, attrs::Vector{Pair{Symbol,Any}} = Pair{Symbol,Any}[]) :: HTMLString

Generates a HTML element in the form <...></...>
"""
@inline function normal_element(f::Function, elem::String, args = [], attrs::Vector{Pair{Symbol,Any}} = Pair{Symbol,Any}[]) :: HTMLString
  normal_element(f(), elem, args, attrs...)
end
@inline function normal_element(children::Union{String,Vector{String}}, elem::String, args, attrs::Pair{Symbol,Any}) :: HTMLString
  normal_element(children, elem, args, Pair{Symbol,Any}[attrs])
end
@inline function normal_element(children::Union{String,Vector{String}}, elem::String, args, attrs...) :: HTMLString
  normal_element(children, elem, args, Pair{Symbol,Any}[attrs...])
end
@inline function normal_element(children::Union{String,Vector{String}}, elem::String, args = [], attrs::Vector{Pair{Symbol,Any}} = Pair{Symbol,Any}[]) :: HTMLString
  children = join(children)
  elem = normalize_element(elem)
  attribs = rstrip(attributes(attrs))
  string("<", elem, (isempty(attribs) ? "" : " $attribs"), (isempty(args) ? "" : " $(join(args, " "))"), ">", prepare_template(children), "</", elem, ">")
end
@inline function normal_element(elem::String, attrs::Vector{Pair{Symbol,Any}} = Pair{Symbol,Any}[]) :: HTMLString
  normal_element("", elem, attrs...)
end
@inline function normal_element(elems::Vector, elem::String, args = [], attrs...) :: HTMLString
  io = IOBuffer()

  for e in elems
    e === nothing && continue

    if isa(e, Function)
      print(io, e(), "\n")
    else
      print(io, e, "\n")
    end
  end

  normal_element(String(take!(io)), elem, args, attrs...)
end
@inline function normal_element(_::Nothing, __::Any) :: HTMLString
  ""
end

"""
    prepare_template(s::String)
    prepare_template{T}(v::Vector{T})

Cleans up the template before rendering (ex by removing empty nodes).
"""
@inline function prepare_template(s::String) :: String
  s
end
@inline function prepare_template(v::Vector{T})::String where {T}
  filter!(v) do (x)
    ! isa(x, Nothing)
  end

  join(v)
end

"""
    attributes(attrs::Vector{Pair{Symbol,String}} = Vector{Pair{Symbol,String}}()) :: Vector{String}

Parses HTML attributes.
"""
function attributes(attrs::Vector{Pair{Symbol,Any}} = Vector{Pair{Symbol,Any}}()) :: String
  a = IOBuffer()

  for (k,v) in attrs
    sk = string(k)
    # startswith(sk, "_") && (k = sk = sk[2:end])
    # k = replace(sk, "_"=>"-")

    print(a, "$(k)=\"$(v)\" ")
  end

  String(take!(a))
end

"""
    normalize_element(elem::String)

Cleans up problematic characters or DOM elements.
"""
@inline function normalize_element(elem::String)
  replace(string(lowercase(elem)), "_____"=>"-")
end
@inline function denormalize_element(elem::String)
  replace(string(lowercase(elem)), "-"=>"_____")
end

"""
    void_element(elem::String, attrs::Vector{Pair{Symbol,String}} = Vector{Pair{Symbol,String}}()) :: HTMLString

Generates a void HTML element in the form <...>
"""
@inline function void_element(elem::String, args = [], attrs::Vector{Pair{Symbol,Any}} = Pair{Symbol,Any}[]) :: HTMLString
  attribs = rstrip(attributes(attrs))
  string("<", normalize_element(elem), (isempty(attribs) ? "" : " $attribs"), (isempty(args) ? "" : " $(join(args, " "))"), ">")
end

"""
    skip_element(f::Function) :: HTMLString
    skip_element() :: HTMLString

Cleans up empty elements.
"""
@inline function skip_element(f::Function) :: HTMLString
  "$(prepare_template(f()))"
end
@inline function skip_element() :: HTMLString
  ""
end

"""
    include_markdown(path::String; context::Module = @__MODULE__)

Includes and renders a markdown view file
"""
function include_markdown(path::String; context::Module = @__MODULE__)
  md = read(path, String)

  vars_injection = ""

  if startswith(md, MD_SEPARATOR_START)
    close_sep_pos = findfirst(MD_SEPARATOR_END, md[length(MD_SEPARATOR_START)+1:end])
    metadata = md[length(MD_SEPARATOR_START)+1:close_sep_pos[end]] |> YAML.load

    vars_injection = ""
    for (k,v) in metadata
      task_local_storage(:__vars)[Symbol(k)] = v
      vars_injection *= """@vars($(repr(Symbol(k)))) = $(v)\n"""
    end

    md = replace(md[close_sep_pos[end]+length(MD_SEPARATOR_END)+1:end], "\"\"\""=>"\\\"\\\"\\\"")
  end

  content = string( "\"\"\"", md, "\"\"\"")

  vars_injection, (include_string(context, content) |> Markdown.parse |> Markdown.html)
end

"""
    get_template(path::String; partial::Bool = true, context::Module = @__MODULE__) :: Function

Resolves the inclusion and rendering of a template file
"""
function get_template(path::String; partial::Bool = true, context::Module = @__MODULE__) :: Function
  orig_path = path

  path, extension = view_file_info(path)

  isfile(path) || error("Template file \"$orig_path\" with extensions $SUPPORTED_HTML_OUTPUT_FILE_FORMATS does not exist")

  extension in HTML_FILE_EXT && return (() -> Base.include(context, path))

  f_name = Flax.function_name(string(path, partial)) |> Symbol
  mod_name = Flax.m_name(string(path, partial)) * ".jl"
  f_path = joinpath(Genie.config.path_build, Flax.BUILD_NAME, mod_name)
  f_stale = Flax.build_is_stale(path, f_path)

  if f_stale || ! isdefined(context, f_name)
    content = if extension in MARKDOWN_FILE_EXT
      vars_injection, md = include_markdown(path, context = context)
      Flax.string_to_flax(md, partial = partial, f_name = f_name, prepend = vars_injection)
    else
      Flax.html_to_flax(path, partial = partial)
    end

    f_stale && Flax.build_module(content, path, mod_name)

    return Base.include(context, joinpath(Genie.config.path_build, Flax.BUILD_NAME, mod_name))
  end

  getfield(context, f_name)
end

"""
Outputs document's doctype.
"""
@inline function doctype(doctype::Symbol = :html) :: HTMLString
  "<!DOCTYPE $doctype>"
end

"""
Outputs document's doctype.
"""
@inline function doc(html::String) :: HTMLString
  doctype() * "\n" * html
end
@inline function doc(doctype::Symbol, html::String) :: HTMLString
  doctype(doctype) * "\n" * html
end

"""
    view_file_info(path::String) :: Tuple{String,String}

Extracts path and extension info about a file
"""
function view_file_info(path::String) :: Tuple{String,String}
  _path, _extension = "", ""

  if isfile(path)
    _path, _extension = relpath(path), "." * split(path, ".", limit = 2)[end]
  else
    for file_extension in SUPPORTED_HTML_OUTPUT_FILE_FORMATS
      if isfile(path * file_extension)
        _path, _extension = path * file_extension, file_extension
        break
      end
    end
  end

  _path, _extension
end

"""
"""
function render(data::String; context::Module = @__MODULE__, layout::Union{String,Nothing} = nothing, vars...) :: Function
  Flax.registervars(vars...)

  if layout !== nothing
    task_local_storage(:__yield, Flax.parseview(data, partial = true, context = context))
    Flax.parseview(layout, partial = false, context = context)
  else
    Flax.parseview(data, partial = false, context = context)
  end
end

"""
"""
function render(viewfile::FilePaths.PosixPath; layout::Union{Nothing,FilePaths.PosixPath} = nothing, context::Module = @__MODULE__, vars...) :: Function
  Flax.registervars(vars...)

  if layout !== nothing
    task_local_storage(:__yield, get_template(string(viewfile), partial = true, context = context))
    get_template(string(layout), partial = false, context = context)
  else
    get_template(string(viewfile), partial = false, context = context)
  end
end

function parsehtml(input::String; partial::Bool = true) :: String
  parsehtml(HTMLParser.parsehtml(replace(input, NBSP_REPLACEMENT)).root, 0, partial = partial)
end

"""
    parsehtml(elem, output, depth; partial = true) :: String

Parses a HTML tree structure into a `string` of Flax code.
"""
function parsehtml(elem::HTMLParser.HTMLElement, depth::Int = 0; partial::Bool = true) :: String
  io = IOBuffer()

  tag_name = denormalize_element(string(HTMLParser.tag(elem)))

  invalid_tag = partial && (tag_name == "html" || tag_name == "head" || tag_name == "body")

  if tag_name == "script" && in("type", collect(keys(HTMLParser.attrs(elem))))
    if HTMLParser.attrs(elem)["type"] == "julia/eval"
      isempty(HTMLParser.children(elem)) || print(io, repeat("\t", depth), string(HTMLParser.children(elem)[1].text), "\n")
    end

  else
    print(io, repeat("\t", depth), ( ! invalid_tag ? "Html.$(tag_name)(" : "Html.HTMLRenderer.skip_element(" ))

    attributes = IOBuffer()
    attributes_keys = String[]
    attributes_values = String[]

    for (k,v) in HTMLParser.attrs(elem)
      x = v
      k = string(k) |> lowercase

      if startswith(k, raw"$") # do not process embedded julia code
        print(attributes, k[2:end], ", ") # strip the $, this is rendered directly in Julia code
        continue
      end

      if in(Symbol(lowercase(k)), BOOL_ATTRIBUTES)
        if x == true || x == "true" || x == :true || x == ":true" || x == "" || x == "on"
          print(attributes, "$k=\"$k\"", ", ") # boolean attributes can have the same value as the attribute -- or be empty
        end
      else
        if occursin('-', k) || occursin(':', k) || occursin('@', k) || occursin('.', k)
          push!(attributes_keys, Symbol(k) |> repr)

          v = string(v) |> repr
          occursin(raw"\$", v) && (v = replace(v, raw"\$"=>raw"$"))
          push!(attributes_values, v)
        else
          print(attributes, """$k="$v" """, ", ")
        end
      end
    end

    attributes_string = String(take!(attributes))
    endswith(attributes_string, ", ") && (attributes_string = attributes_string[1:end-2])

    print(io, attributes_string)
    ! isempty(attributes_string) && ! isempty(attributes_keys) && print(io, ", ")
    isempty(attributes_string) && ! isempty(attributes_keys) && print(io, "; ")
    ! isempty(attributes_keys) &&
      print(io, "NamedTuple{($(join(attributes_keys, ", "))$(length(attributes_keys) == 1 ? ", " : ""))}(($(join(attributes_values, ", "))$(length(attributes_keys) == 1 ? ", " : "")))...")
    print(io, ")")

    inner = ""
    if ! isempty(HTMLParser.children(elem))
      children_count = size(HTMLParser.children(elem))[1]

      print(io, " do;[\n")

      idx = 0
      for child in HTMLParser.children(elem)
        idx += 1
        inner *= isa(child, HTMLParser.HTMLText) ? parsehtml(child, depth + 1) : parsehtml(child, depth + 1, partial = partial)
        if idx < children_count
          if  ( isa(child, HTMLParser.HTMLText) ) ||
              ( isa(child, HTMLParser.HTMLElement) &&
              ( ! in("type", collect(keys(HTMLParser.attrs(child)))) ||
                ( in("type", collect(keys(HTMLParser.attrs(child)))) && (HTMLParser.attrs(child)["type"] != "julia/eval") ) ) )
              isempty(inner) || (inner = string(repeat("\t", depth), inner, "\n"))
          end
        end
      end

      if ! isempty(inner)
        endswith(inner, "\n\n") && (inner = inner[1:end-2])
        print(io, inner, repeat("\t", depth))
      end

      print(io, "]end\n")
    end

  end

  String(take!(io))
end

function parsehtml(elem::HTMLParser.HTMLText, depth::Int = 0; partial::Bool = true) :: String
  content = elem.text
  endswith(content, "\"") && (content *= Char(0x0))
  content = replace(content, NBSP_REPLACEMENT[2]=>NBSP_REPLACEMENT[1])
  string(repeat("\t", depth), "\"\"\"$(content)\"\"\"")
end

end