text:
"""
Julia-fjåge Gateway.

Notes:
- This implementation is not thread-safe.
- Gateway does not automatically reconnect if connection to server is lost.

# Examples

Assuming fjåge master container is running on `localhost` at port 1100:

```julia-repl
julia> using Fjage
julia> ShellExecReq = MessageClass("org.arl.fjage.shell.ShellExecReq");
julia> gw = Gateway("localhost", 1100);
julia> shell = agentforservice(gw, "org.arl.fjage.shell.Services.SHELL")
shell
julia> request(gw, ShellExecReq(recipient=shell, cmd="ps"))
AGREE
julia> request(shell, ShellExecReq(cmd="ps"))
AGREE
julia> shell << ShellExecReq(cmd="ps")
AGREE
julia> close(gw)
```
"""
module Fjage

# install and use dependencies
# using Pkg
# Pkg.add("JSON")

using Sockets, Distributed, Base64, UUIDs, Dates, JSON

# exported symbols
export Performative, AgentID, Gateway, Message, GenericMessage, MessageClass
export agent, topic, send, receive, request, agentforservice, agentsforservice, subscribe, unsubscribe

# package settings
const MAX_QUEUE_LEN = 256

"An action represented by a message."
module Performative
  const REQUEST = "REQUEST"
  const AGREE = "AGREE"
  const REFUSE = "REFUSE"
  const FAILURE = "FAILURE"
  const INFORM = "INFORM"
  const CONFIRM = "CONFIRM"
  const DISCONFIRM = "DISCONFIRM"
  const QUERY_IF = "QUERY_IF"
  const NOT_UNDERSTOOD = "NOT_UNDERSTOOD"
  const CFP = "CFP"
  const PROPOSE = "PROPOSE"
  const CANCEL = "CANCEL"
end

# respond to master container
function _respond(gw, rq::Dict, rsp::Dict)
  s = JSON.json(merge(Dict("id" => rq["id"], "inResponseTo" => rq["action"]), rsp))
  println(gw.sock, s)
end

# ask master container a question, and wait for reply
function _ask(gw, rq::Dict)
  id = string(uuid4())
  s = JSON.json(merge(rq, Dict("id" => id)))
  ch = Channel{Dict}(1)
  gw.pending[id] = ch
  try
    println(gw.sock, s)
    return take!(ch)
  finally
    delete!(gw.pending, id)
  end
end

# update master container about changes to recipient watch list
function _update_watch(gw)
  watch = [gw.agentID.name]
  for s in keys(gw.subscriptions)
    push!(watch, s)
  end
  s = JSON.json(Dict(
    "action" => "wantsMessagesFor",
    "agentIDs" => watch
  ))
  println(gw.sock, s)
end

# task monitoring incoming JSON messages from master container
function _run(gw)
  println(gw.sock, "{\"alive\": true}")
  _update_watch(gw)
  while isopen(gw.sock)
    s = readline(gw.sock)
    json = JSON.parse(s)
    if haskey(json, "id") && haskey(gw.pending, json["id"])
      put!(gw.pending[json["id"]], json)
    elseif haskey(json, "action")
      if json["action"] == "agents"
        _respond(gw, json, Dict("agentIDs" => [gw.agentID.name]))
      elseif json["action"] == "agentForService"
        _respond(gw, json, Dict())
      elseif json["action"] == "agentsForService"
        _respond(gw, json, Dict("agentIDs" => []))
      elseif json["action"] == "services"
        _respond(gw, json, Dict("services" => []))
      elseif json["action"] == "containsAgent"
        ans = (json["agentID"] == gw.agentID.name)
        _respond(gw, json, Dict("answer" => ans))
      elseif json["action"] == "send"
        rcpt = json["message"]["data"]["recipient"]
        if rcpt == gw.agentID.name || get(gw.subscriptions, rcpt, false)
          try
            msg = _inflate(json["message"])
            while length(gw.queue.data) >= MAX_QUEUE_LEN
              take!(gw.queue)
            end
            put!(gw.queue, msg)
          catch ex
            # silently ignore bad messages
          end
        end
      end
    elseif haskey(json, "alive") && json["alive"]
      println(gw.sock, "{\"alive\": true}")
    end
  end
end

"Base class for messages transmitted by one agent to another."
abstract type Message end

"An identifier for an agent or a topic."
struct AgentID
  name::String
  istopic::Bool
  owner
end

"""
    aid = AgentID(name[, istopic])

Create an unowned AgentID.

See also: [`agent`](@ref), [`topic`](@ref)
"""
AgentID(name::String) = name[1] == '#' ? AgentID(name[2:end], true, nothing) : AgentID(name, false, nothing)
AgentID(name::String, istopic::Bool) = AgentID(name, istopic, nothing)
Base.show(io::IO, aid::AgentID) = print(io, aid.istopic ? "#"*aid.name : aid.name)
JSON.lower(aid::AgentID) = aid.istopic ? "#"*aid.name : aid.name

"""
    gw = Gateway([name,] host, port)

Open a new TCP/IP gateway to communicate with fjåge agents from Julia.

See also: [`Fjage`](@ref)
"""
struct Gateway
  agentID::AgentID
  sock::TCPSocket
  subscriptions::Dict{String,Bool}
  pending::Dict{String,Channel}
  queue::Channel
  function Gateway(name::String, host::String, port::Integer)
    gw = new(
      AgentID(name, false),
      connect(host, port),
      Dict{String,Bool}(),
      Dict{String,Channel}(),
      Channel(MAX_QUEUE_LEN)
    )
    @async _run(gw)
    return gw
  end
end

Gateway(host::String, port::Integer) = Gateway("julia-gw-" * string(uuid1()), host, port)
Base.show(io::IO, gw::Gateway) = print(io, gw.agentID.name)

"""
    aid = agent([gw,] name)

Creates an AgentID for a named agent, optionally owned by a gateway. AgentIDs that are
associated with gateways can be used directly in `send()` and `request()` calls.
"""
agent(name::String) = AgentID(name, false)
agent(gw::Gateway, name::String) = AgentID(name, false, gw)

"""
    aid = topic([gw,] name[, subtopic])

Creates an AgentID for a named topic, optionally owned by a gateway. AgentIDs that are
associated with gateways can be used directly in `send()` and `request()` calls.
"""
topic(name::String) = AgentID(name, true)
topic(aid::AgentID) = aid.istopic ? aid : AgentID(aid.name*"__ntf", true)
topic(aid::AgentID, topic2::String) = AgentID(aid.name*"__"*topic2*"__ntf", true)
topic(gw::Gateway, name::String) = AgentID(name, true, gw)
topic(gw::Gateway, aid::AgentID) = aid.istopic ? aid : AgentID(aid.name*"__ntf", true, gw)
topic(gw::Gateway, aid::AgentID, topic2::String) = AgentID(aid.name*"__"*topic2*"__ntf", true, gw)

"Find an agent that provides a named service."
function agentforservice(gw::Gateway, svc::String)
  rq = Dict("action" => "agentForService", "service" => svc)
  rsp = _ask(gw, rq)
  if haskey(rsp, "agentID")
    return AgentID(rsp["agentID"], false, gw)
  else
    return nothing
  end
end

"Find all agents that provides a named service."
function agentsforservice(gw::Gateway, svc::String)
  rq = Dict("action" => "agentsForService", "service" => svc)
  rsp = _ask(gw, rq)
  return [AgentID(a, false, gw) for a in rsp["agentIDs"]]
end

"Subscribe to receive all messages sent to the given topic."
function subscribe(gw::Gateway, aid::AgentID)
  gw.subscriptions[string(topic(gw, aid))] = true
  _update_watch(gw)
  return true
end

"Unsubscribe from receiving messages sent to the given topic."
function unsubscribe(gw::Gateway, aid::AgentID)
  k = string(topic(gw, aid))
  if haskey(gw.subscriptions, k)
    delete!(gw.subscriptions, k)
    _update_watch(gw)
    return true
  end
  return false
end

"Close a gateway connection to the master container."
function close(gw::Gateway)
  println(gw.sock, "{\"alive\": false}")
  Base.close(gw.sock)
end

# create a Message subclass from a qualified classname
macro _define_message(sname::Symbol, clazz, perf)
  quote
    struct $(esc(sname)) <: Message
      clazz::String
      data::Dict{String,Any}
    end
    function $(esc(sname))(; kwargs...)
      dict = Dict{String,Any}(
        "msgID" => string(uuid4()),
        "perf" => string($perf)
      )
      for k in keys(kwargs)
        dict[string(k)] = kwargs[k]
      end
      return $(esc(sname))(string($clazz), dict)
    end
  end
end

"""
    mtype = MessageClass(clazz[, perf])

Create a message class from a fully qualified class name. If a performative is not
specified, it is guessed based on the class name. For class names ending with "Req",
the performative is assumed to be REQUEST, and for all other messages, INFORM.

# Examples

```julia-repl
julia> using Fjage
julia> ShellExecReq = MessageClass("org.arl.fjage.shell.ShellExecReq");
julia> req = ShellExecReq(cmd="ps")
ShellExecReq: REQUEST [cmd:"ps"]
```
"""
function MessageClass(clazz::String, perf=nothing)
  if perf == nothing
    if match(r"Req$", clazz) != nothing
      perf = Performative.REQUEST
    else
      perf = Performative.INFORM
    end
  end
  sname = Symbol(replace(clazz, "." => "_"))
  return @eval @_define_message($sname, $clazz, $perf)
end

# prepares a message to be sent to the server
function _prepare!(gw::Gateway, msg::Message)
  msg.sender = gw.agentID
  for k in keys(msg.__data__)
    v = msg.__data__[k]
    if typeof(v) <: Array && typeof(v).parameters[1] <: Complex
      btype = typeof(v).parameters[1].parameters[1]
      msg.__data__[k] = reinterpret(btype, v)
    end
  end
end

# converts Base64 encoded arrays to Julia arrays
function _b64toarray(v)
  try
    dtype = v["clazz"]
    if dtype == "[B"  # byte array
      dtype = Int8
    elseif dtype == "[S"  # short array
      dtype = Int16
    elseif dtype == "[I"  # integer array
      dtype = Int32
    elseif dtype == "[J"  # long array
      dtype = Int64
    elseif dtype == "[F"  # float array
      dtype = Float32
    elseif dtype == "[D"  # double array
      dtype = Float64
    else
      return v
    end
    return Array{dtype}(reinterpret(dtype, base64decode(v["data"])))
  catch ex
    return v
  end
end

# creates a message object from a JSON representation of the object
function _inflate(json)
  if typeof(json) == String
    json = JSON.parse(json)
  end
  clazz = json["clazz"]
  data = json["data"]
  stype = MessageClass(clazz)
  obj = @eval $stype()
  for k in keys(data)
    v = data[k]
    if endswith(k, "__isComplex")
      continue
    end
    if k == "sender" || k == "recipient"
      v = AgentID(v)
    end
    if typeof(v) <: Dict && haskey(v, "clazz") && match(r"^\[.$", v["clazz"]) != nothing
      v = _b64toarray(v)
    end
    if typeof(v) <: Array && length(v) > 0
      t = typeof(v[1])
      v = Array{t}(v)
      kcplx = k*"__isComplex"
      if haskey(data, kcplx) && data[kcplx]
        v = Array{Complex{t}}(reinterpret(Complex{t}, v))
      end
    end
    obj.__data__[k] = v
  end
  return obj
end

"""
    send(gw, msg)
    send(aid, msg)

Send a message via the gateway to the specified agent. If the gateway (`gw`) is specified then the
`recipient` field of the message must be populated with an agentID. If the agentID (`aid`) is specified,
it must be an "owned" agentID obtained from the `agent(gw, name)` function or returned by the
`agentforservice(gw, service)` function.
"""
function send(gw::Gateway, msg::Message)
  _prepare!(gw, msg)
  json = JSON.json(Dict("action" => "send", "relay" => true, "message" => msg))
  println(gw.sock, json)
end

function send(aid::AgentID, msg::Message)
  if aid.owner == nothing
    error("cannot send message to an unowned agentID")
  end
  msg.recipient = aid
  send(aid.owner, msg)
end

# helper function to see if a message matches a filter
function _matches(filt, msg)
  if msg == nothing
    return true
  end
  if typeof(filt) == DataType
    return typeof(msg) <: filt
  elseif typeof(filt) <: Message
    return msg.inReplyTo == filt.msgID
  elseif typeof(filt) <: Function
    return filt(msg)
  end
  return false
end

"""
    msg = receive(gw[, filter][, timeout])

Receive an incoming message from other agents or topics. Timeout is specified in
milliseconds. If no timeout is specified, the call is non-blocking. If a negative timeout
is specified, the call is blocking until a message is available.

If a `filter` is specified, only messages matching the filter are retrieved. A filter
may be a message type, a message or a function. If it is a message type, only messages
of that type or a subtype are retrieved. If it is a message, any message whose `inReplyTo`
field is set to the `msgID` of the specified message is retrieved. If it is a function,
it must take in a message and return `true` or `false`. A message for which it returns
`true` is retrieved.
"""
function receive(gw::Gateway, timeout::Integer=0)
  if isready(gw.queue)
    return take!(gw.queue)
  end
  if timeout == 0
    return nothing
  end
  waiting = true
  if timeout > 0
    @async begin
      timer = Timer(timeout/1000.0)
      wait(timer)
      if waiting
        push!(gw.queue, nothing)
      end
    end
  end
  rv = take!(gw.queue)
  waiting = false
  return rv
end

function receive(gw::Gateway, filt, timeout::Integer=0)
  t1 = now() + Millisecond(timeout)
  cache = []
  while true
    msg = receive(gw, (t1-now()).value)
    if _matches(filt, msg)
      if length(cache) > 0
        while isready(gw.queue)
          push!(cache, take!(gw.queue))
        end
        for m in cache
          push!(gw.queue, m)
        end
      end
      return msg
    end
    push!(cache, msg)
  end
end

"""
    rsp = request(gw, msg[, timeout])
    rsp = request(aid, msg[, timeout])

Send a request via the gateway to the specified agent, and wait for a response. The response is returned.
If the gateway (`gw`) is specified then the `recipient` field of the request message (`msg`) must be
populated with an agentID. If the agentID (`aid`) is specified, it must be an "owned" agentID obtained
from the `agent(gw, name)` function or returned by the `agentforservice(gw, service)` function. The timeout
is specified in milliseconds, and defaults to 1 second if unspecified.
"""
function request(gw::Gateway, msg::Message, timeout::Integer=1000)
  send(gw, msg)
  return receive(gw, msg, timeout)
end

function request(aid::AgentID, msg::Message, timeout::Integer=1000)
  send(aid, msg)
  return receive(aid.owner, msg, timeout)
end

"""
    rsp = aid << msg

Send a request via the gateway to the specified agent, and wait for a response.

See also: [`request`](@ref), [`Fjage`](@ref)
"""
Base.:<<(aid::AgentID, msg::Message) = request(aid, msg)

"Flush the incoming message queue."
function flush(gw::Gateway)
  while isready(gw.queue)
    take!(gw.queue)
  end
end

# adds notation message.field
function Base.getproperty(s::Message, p::Symbol)
  if p == :__clazz__
    return getfield(s, :clazz)
  elseif p == :__data__
    return getfield(s, :data)
  else
    p1 = string(p)
    if p1 == "performative"
      p1 = "perf"
    elseif p1 == "messageID"
      p1 = "msgID"
    end
    v = getfield(s, :data)
    if !haskey(v, p1)
      return nothing
    end
    v = v[p1]
    return v
  end
end

# adds notation message.field
function Base.setproperty!(s::Message, p::Symbol, v)
  if p == :__clazz__ || p == :__data__
    error("read-only property cannot be set")
  else
    p1 = string(p)
    if p1 == "performative"
      p1 = "perf"
    elseif p1 == "messageID"
      p1 = "msgID"
    end
    getfield(s, :data)[p1] = v
  end
end

# pretty prints arrays without type names
function _repr(x)
  x = repr(x)
  m = match(r"[A-Za-z0-9]+(\[.+\])", x)
  if m != nothing
    x = m[1]
  end
  return x
end

# pretty printing of messages
function Base.show(io::IO, msg::Message)
  ndx = findlast(".", msg.__clazz__)
  s = ndx == nothing ? msg.__clazz__ : msg.__clazz__[ndx[1]+1:end]
  p = ""
  data_suffix = ""
  signal_suffix = ""
  suffix = ""
  data = msg.__data__
  for k in keys(data)
    x = data[k]
    if k == "perf"
      s *= ": " * x
    elseif k == "data"
      if typeof(x) <: Array
        data_suffix *= "($(length(x)) bytes)"
      else
        p *= " $k:" * _repr(data[k])
      end
    elseif k == "signal"
      if typeof(x) <: Array
        signal_suffix *= "($(length(x)) samples)"
      else
        p *= " $k:" * _repr(data[k])
      end
    elseif k != "sender" && k != "recipient" && k != "msgID" && k != "inReplyTo"
      if typeof(x) <: Number || typeof(x) == String || typeof(x) <: Array || typeof(x) == Bool
        p *= " $k:" * _repr(x)
      else
        suffix = "..."
      end
    end
  end
  if length(suffix) > 0
    p *= " " * suffix
  end
  if length(signal_suffix) > 0
    p *= " " * signal_suffix
  end
  if length(data_suffix) > 0
    p *= " " * data_suffix
  end
  p = strip(p)
  if length(p) > 0
    s *= " [$p]"
  end
  if msg.__clazz__ == "org.arl.fjage.Message"
    m = match(r"^Message: (.*)$", s)
    if m != nothing
      s = m[1]
    end
  end
  print(io, s)
end

"Generic message type that can carry arbitrary name-value pairs as data."
GenericMessage = MessageClass("org.arl.fjage.GenericMessage", Performative.INFORM)

"""
    msg = Message([perf])
    msg = Message(inreplyto[, perf])

Create a message with just a performative (`perf`) and no data. If the performative
is not specified, it defaults to INFORM. If the inreplyto is specified, the message
`inReplyTo` and `recipient` fields are set accordingly.
"""
Message(perf::String=Performative.INFORM) = GenericMessage(performative=perf)
Message(inreplyto::Message, perf::String=Performative.INFORM) = GenericMessage(performative=perf, inReplyTo=inreplyto.msgID, recipient=inreplyto.sender)

# Base functions to add local methods
Base.close(gw::Gateway) = close(gw)
Base.flush(gw::Gateway) = flush(gw)

end


text:
#=
 * sais
 * Copyright (c) 2010 Yuta Mori. All Rights Reserved.
 *
 * 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.
=#

sais(text::Vector) = sais(text, Array{Int}(undef,length(text)), 0, length(text), 65536)

function sais(text::Vector{T}, sa::Vector{Int}, fs::Int, n::Int, k::Int) where T
    pidx = 0
    flags = 0
    if k <= 256
        C = zeros(Int, k)
        if k <= fs
            B = offset_to_array(sa, n+fs-k+1)
            flags = 1
        else
            B = zeros(Int, k)
            flags = 3
        end
    elseif k <= fs
        C = offset_to_array(sa, n+fs-k+1)
        if k <= fs-k
            B = offset_to_array(sa, n+fs-2k+1)
            flags = 0
        elseif k <= 1024
            B = zeros(Int, k)
            flags = 2
        else
            B = C
            flags = 8
        end
    else
        C = B = zeros(Int, k)
        flags = 4 | 8
    end

    # stage 1: reduce the problem by at least 1/2
    # sort all the LMS-substrings
    setcounts!(text, C, n, k)
    getbuckets(C, B, k, true)
    for i = 1:n
        sa[i] = 0
    end
    b = -1
    i = j = n
    m = 0
    c0 = c1 = text[n]
    i -= 1
    while 1 <= i && ((c0 = text[i]) >= c1)
        c1 = c0
        i -= 1
    end
    while 1 <= i
        c1 = c0
        i -= 1
        while 1 <= i && ((c0 = text[i]) <= c1)
            c1 = c0
            i -= 1
        end
        if 1 <= i
            0 <= b && (sa[b+1] = j)
            b = (B[c1+1] -= 1)
            j = i-1
            m += 1
            c1 = c0
            i -= 1
            while 1 <= i && ((c0 = text[i]) >= c1)
                c1 = c0
                i -= 1
            end
        end
    end
    if 1 < m
        LMSsort(text, sa, C, B, n, k)
        name = LMSpostproc(text, sa, n, m)
    elseif m == 1
        sa[b+1] = j + 1
        name = 1
    else
        name = 0
    end

    # stage 2
    if name < m
        newfs = n + fs - 2m
        if flags & (1 | 4 | 8) == 0
            if (k + name) <= newfs
                newfs -= k
            else
                flags |= 8
            end
        end
        j = 2m + newfs
        for i = (m + (n >> 1)):-1:(m+1)
            if sa[i] != 0
                sa[j] = sa[i] - 1
                j -= 1
            end
        end
        RA = offset_to_array(sa, m+newfs+1)
        sais(RA, sa, newfs, m, name)

        i = n
        j = 2m
        c0 = c1 = text[n]
        while 1 <= (i -= 1) && ((c0 = text[i]) >= c1)
            c1 = c0
        end
        while 1 <= i
            c1 = c0
            while 1 <= (i -= 1) && ((c0 = text[i]) <= c1)
                c1 = c0
            end
            if 1 <= i
                sa[j] = i
                j -= 1
                c1 = c0
                while 1 <= (i -= 1) && ((c0 = text[i]) >= c1)
                    c1 = c0
                end
            end
        end
        for i = 1:m
            sa[i] = sa[m+sa[i]+1]
        end
        if flags & 4 != 0
            C = B = zeros(Int, k)
        end
        if flags & 2 != 0
            B = zeros(Int, k)
        end
    end

    # stage 3
    flags & 8 != 0 && setcounts!(text, C, n, k)
    if 1 < m
        getbuckets(C, B, k, true)
        i = m - 1
        j = n
        p = sa[m]
        c1 = text[p+1]
        while true
            c0 = c1
            q = B[c0+1]
            while q < j
                j -= 1
                sa[j+1] = 0
            end
            while true
                j -= 1
                sa[j+1] = p
                i -= 1
                i < 0 && break
                p = sa[i+1]
                c1 = text[p+1]
                c1 != c0 && break
            end
            i < 0 && break
        end
        while 0 < j
            j -= 1
            sa[j+1] = 0
        end
    end
    #if (isbwt == false) { induceSA(T, SA, C, B, n, k); }
    #else { pidx = computeBWT(T, SA, C, B, n, k); }
    induceSA(text, sa, C, B, n, k)
    sa+1
end

function setcounts!(text::Vector{T}, C::Vector{Int}, n::Int, k::Int) where T
    for i = 1:k
        C[i] = 0
    end
    for i = 1:n
        C[text[i]+1] += 1
    end
end

function getbuckets(C::Vector{Int}, B::Vector{Int}, k::Int, isend::Bool)
    sum = 0
    if isend
        for i = 1:k
            sum += C[i]
            B[i] = sum
        end
    else
        for i = 1:k
            sum += C[i]
            B[i] = sum - C[i]
        end
    end
end

offset_to_array(x::Vector, i::Int) = unsafe_wrap(Array, pointer(x,i), length(x)-i+1)

function LMSsort(text::Vector{T}, sa, C, B, n::Int, k::Int) where T<:Integer
    C == B && setcounts!(text, C, n, k)
    getbuckets(C, B, k, false)
    j = n - 1
    c1 = text[j+1]
    b = B[c1+1]
    j -= 1
    sa[b+1] = text[j+1] < c1 ? ~j : j
    b += 1
    for i = 1:n
        if 0 < (j = sa[i])
            if (c0 = text[j+1]) != c1
                B[c1+1] = b
                c1 = c0
                b = B[c1+1]
            end
            j -= 1
            sa[b+1] = text[j+1] < c1 ? ~j : j
            b += 1
            sa[i] = 0
        elseif j < 0
            sa[i] = ~j
        end
    end
    C == B && setcounts!(text, C, n, k)
    getbuckets(C, B, k, true)
    c1 = 0
    b = B[c1+1]
    for i = n:-1:1
        if 0 < (j = sa[i])
            c0 = text[j+1]
            if c0 != c1
                B[c1+1] = b
                c1 = c0
                b = B[c1+1]
            end
            j -= 1
            b -= 1
            sa[b+1] = text[j+1] > c1 ? ~(j+1) : j
            sa[i] = 0
        end
    end
end

function LMSpostproc(text::Vector{T}, sa::Vector{Int}, n::Int, m::Int) where T
    i = 1
    while (p = sa[i]) < 0
        sa[i] = ~p
        i += 1
    end
    if i-1 < m
        j = i
        i += 1
        while true
            if (p = sa[i]) < 0
                sa[j] = ~p
                j += 1
                sa[i] = 0
                j-1 == m && break
            end
            i += 1
        end
    end

    i = j = n
    c0 = c1 = text[n]
    while 1 <= (i -= 1) && ((c0 = text[i]) >= c1)
        c1 = c0
    end
    while 1 <= i
        c1 = c0
        while 1 <= (i -= 1) && ((c0 = text[i]) <= c1)
            c1 = c0
        end
        if 1 <= i
            sa[m + (i >> 1) + 1] = j - i
            j = i + 1
            c1 = c0
            while 1 <= (i -= 1) && ((c0 = text[i]) >= c1)
                c1 = c0
            end
        end
    end
    name = 0
    q = n
    qlen = 0
    for i = 1:m
        p = sa[i]
        plen = sa[m + (p >> 1) + 1]
        diff = true
        if plen == qlen && (q + plen < n)
            j = 0
            while j < plen && text[p+j+1] == text[q+j+1]
                j += 1
            end
            j == plen && (diff = false)
        end
        if diff != false
            name += 1
            q = p
            qlen = plen
        end
        sa[m + (p >> 1) + 1] = name
    end
    return name
end

function induceSA(text::Vector{T}, sa::Vector{Int}, C::Vector{Int}, B::Vector{Int}, n::Int, k::Int) where T
    C == B && setcounts!(text, C, n, k)
    getbuckets(C, B, k, false)
    j = n - 1
    c1 = text[j+1]
    b = B[c1+1]
    sa[b+1] = 0 < j && text[j] < c1 ? ~j : j
    b += 1
    for i = 1:n
        j = sa[i]
        sa[i] = ~j
        if 0 < j
            j -= 1
            if (c0 = text[j+1]) != c1
                B[c1+1] = b
                c1 = c0
                b = B[c1+1]
            end
            sa[b+1] = 0 < j && text[j] < c1 ? ~j : j
            b += 1
        end
    end
    C == B && setcounts!(text, C, n, k)
    getbuckets(C, B, k, true)
    c1 = 0
    b = B[c1+1]
    for i = n:-1:1
        if 0 < (j = sa[i])
            j -= 1
            if (c0 = text[j+1]) != c1
                B[c1+1] = b
                c1 = c0
                b = B[c1+1]
            end
            b -= 1
            sa[b+1] = j == 0 || text[j] > c1 ? ~j : j
        else
            sa[i] = ~j
        end
    end
end

ext: jl


text:
type Quality
	qual::ASCIIString
end

Base.length(q::Quality) = length(q.qual)
Base.sizeof(q::Quality) = sizeof(q.qual)
Base.getindex(q::Quality, i::Int64) = getindex(q.qual, i)
Base.getindex(q::Quality, r::UnitRange{Int64}) = Quality(getindex(q.qual, r))
Base.getindex(q::Quality, indx::AbstractArray{Int64,1}) = Quality(getindex(q.qual, indx))
Base.endof(q::Quality) = length(q)
Base.reverse(q::Quality) = Quality(reverse(q.qual))
==(s1::Quality, s2::Quality) = s1.qual == s2.qual
-(s1::Quality) = Quality(reverse(s1.qual))

function qual2num(q::Char)
    return UInt8(q) - 33
end

function num2qual(num::Int64)
    return Char(num+33)
end

function qual_str(q::Char)
    qnum = qual2num(q)
    str = "Q$qnum"
    return str
end

function qual_str(qual::ASCIIString)
    ret = ""
    for i in 1: length(qual)
        q = qual[i]
        if i > 1
            ret *= " "
        end
        ret *= qual_str(q)
    end
    return ret
end

function qual_str(qual::Quality)
    return qual_str(qual.qual)
end


text:
module LitteringModel

    using Agents
    using DataFrames
    using LightGraphs
    using Random
    using StatsBase
    using Feather
    using JSON
    using Distributions
    using GraphIO
    using Distributed
    using Pipe
    using Query
    using Statistics
    using ProgressMeter

    include("citizen.jl")
    include("config.jl")
    include("io.jl")
    include("formatting.jl")
    include("initialization.jl")
    include("agent_step.jl")
    include("model_step.jl")
    include("simulation.jl")

    export Config
    export initialize_model

end


text:
using Starlight

const window_width = 600
const window_height = 400
const paddle_width = 10
const paddle_height = 60
const ball_width = 10
const ball_height = 10
const wall_height = 10
const goal_width = 10
const hz = 1

# collision margins
const wmx = 0 # wall
const wmy = 0
const gmx = 0 # goal
const gmy = 0
const pmx = 0 # paddle
const pmy = 0
const bmx = 0 # ball
const bmy = 0

const pv = window_height # paddle velocity
const ball_vel_x_mult = 0.25
const ball_vel_y_mult = 1.5
const ball_vel_x = ball_vel_x_mult * window_width
const ball_vel_y_max = ball_vel_y_mult * window_height
const paddle_ball_x_tolerance = 2
ball_vel_y(i) =  -i * ball_vel_y_max
const score_scale = 10
const score_y_offset = 50
const msg_scale = 2
const center_line_dash_w = 10
const center_line_dash_h = 40
const center_line_dash_spacing = 20
const asset_base = joinpath(artifact"test", "test")
const secs_between_rounds = 2
const score_to_win = 10

a = App(; wdth=window_width, hght=window_height, bgrd=colorant"black")

# center line
center_line = []
for i in (wall_height + center_line_dash_spacing):(center_line_dash_h + center_line_dash_spacing):(window_height - wall_height - center_line_dash_h - center_line_dash_spacing)
  push!(center_line, ColorRect(center_line_dash_w, center_line_dash_h;
  color=colorant"grey", pos=XYZ((window_width - center_line_dash_w) / 2, i)))
end

# working with Cellphone strings
cpchars = Dict(
  ' ' => [0,0],
  '!' => [0,1],
  '\"' => [0,2],
  '#' => [0,3],
  '$' => [0,4],
  '%' => [0,5],
  '&' => [0,6],
  '\'' => [0,7],
  '(' => [0,8],
  ')' => [0,9],
  '*' => [0,10],
  '+' => [0,11],
  ',' => [0,12],
  '-' => [0,13],
  '.' => [0,14],
  '/' => [0,15],
  '0' => [0,16],
  '1' => [0,17],
  '2' => [1,0],
  '3' => [1,1],
  '4' => [1,2],
  '5' => [1,3],
  '6' => [1,4],
  '7' => [1,5],
  '8' => [1,6],
  '9' => [1,7],
  ':' => [1,8],
  ';' => [1,9],
  '<' => [1,10],
  '=' => [1,11],
  '>' => [1,12],
  '?' => [1,13],
  '@' => [1,14],
  'A' => [1,15],
  'B' => [1,16],
  'C' => [1,17],
  'D' => [2,0],
  'E' => [2,1],
  'F' => [2,2],
  'G' => [2,3],
  'H' => [2,4],
  'I' => [2,5],
  'J' => [2,6],
  'K' => [2,7],
  'L' => [2,8],
  'M' => [2,9],
  'N' => [2,10],
  'O' => [2,11],
  'P' => [2,12],
  'Q' => [2,13],
  'R' => [2,14],
  'S' => [2,15],
  'T' => [2,16],
  'U' => [2,17],
  'V' => [3,0],
  'W' => [3,1],
  'X' => [3,2],
  'Y' => [3,3],
  'Z' => [3,4],
  '[' => [3,5],
  '\\' => [3,6],
  ']' => [3,7],
  '^' => [3,8],
  '_' => [3,9],
  '`' => [3,10],
  'a' => [3,11],
  'b' => [3,12],
  'c' => [3,13],
  'd' => [3,14],
  'e' => [3,15],
  'f' => [3,16],
  'g' => [3,17],
  'h' => [4,0],
  'i' => [4,1],
  'j' => [4,2],
  'k' => [4,3],
  'l' => [4,4],
  'm' => [4,5],
  'n' => [4,6],
  'o' => [4,7],
  'p' => [4,8],
  'q' => [4,9],
  'r' => [4,10],
  's' => [4,11],
  't' => [4,12],
  'u' => [4,13],
  'v' => [4,14],
  'w' => [4,15],
  'x' => [4,16],
  'y' => [4,17],
  'z' => [5,0],
  '{' => [5,1],
  '|' => [5,2],
  '}' => [5,3],
  '~' => [5,4],
)

mutable struct CellphoneString <: Renderable
  function CellphoneString(str="", white=true;
    scale=XYZ(1,1), color=colorant"white", kw...)
    instantiate!(new(); str=str, white=white, scale=scale, color=color, kw...)
  end
end

function Starlight.draw(s::CellphoneString)
  img = (s.white) ? joinpath(asset_base, "sprites", "charmap-cellphone_white.png") : joinpath(asset_base, "sprites", "charmap-cellphone_black.png")
  for (i,c) in enumerate(s.str)
    cell_ind = cpchars[c]
    TS_VkCmdDrawSprite(img, vulkan_colors(s.color)...,
    0, 0, 0, 0,
    7, 9, cell_ind[1], cell_ind[2],
    Int(floor(s.scale.x * 7)) * (i - 1) + s.abs_pos.x, s.abs_pos.y,
              s.scale.x, s.scale.y)
  end
end

# p1 score
score1 = CellphoneString('0'; color=colorant"grey",
  scale=XYZ(score_scale, score_scale),
  pos=XYZ((window_width / 2) - (window_width / 4) -
  (7 * score_scale / 2), score_y_offset))

# p2 score
score2 = CellphoneString('0'; color=colorant"grey",
  scale=XYZ(score_scale, score_scale),
  pos=XYZ((window_width / 2) + (window_width / 4) -
  (7 * score_scale / 2), score_y_offset))

# welcome message
msg = CellphoneString("Press SPACE to start", false;
  scale=XYZ(msg_scale, msg_scale),
  pos=XYZ((window_width - 140 * msg_scale) / 2,
  (window_height - 9 * msg_scale) / 2))

mutable struct PongPaddle <: Starlight.Renderable
  function PongPaddle(w, h; kw...)
    instantiate!(new(); w=w, h=h, color=colorant"white", kw...)
  end
end

Starlight.draw(p::PongPaddle) = defaultDrawRect(p)

function Starlight.awake!(p::PongPaddle)
  hw = paddle_width / 2
  hh = paddle_height / 2
  addTriggerBox!(p, hw, hh, hz, p.pos.x + hw, p.pos.y + hh, 0, pmx, pmy, 0)
end

function Starlight.shutdown!(p::PongPaddle)
  removePhysicsObject!(p)
end

function Starlight.handleMessage!(p::PongPaddle, col::TS_CollisionEvent)
  otherId = other(p, col)
  if otherId == wallt.id
    if p.id == p1.id
      pg.p1TouchingTopWall = col.colliding
    elseif p.id == p2.id
      pg.p2TouchingTopWall = col.colliding
    end
  elseif otherId == wallb.id
    if p.id == p1.id
      pg.p1TouchingBottomWall = col.colliding
    elseif p.id == p2.id
      pg.p2TouchingBottomWall = col.colliding
    end
  end
end

# p1
p1 = PongPaddle(paddle_width, paddle_height;
  pos=XYZ(paddle_width, (window_height - paddle_height) / 2))

# p2
p2 = PongPaddle(paddle_width, paddle_height;
  pos=XYZ(window_width - 2 * paddle_width,
  (window_height - paddle_height) / 2))

mutable struct PongArenaWall <: Starlight.Renderable
  function PongArenaWall(w, h; kw...)
    instantiate!(new(); w=w, h=h, color=colorant"white", kw...)
  end
end

Starlight.draw(p::PongArenaWall) = defaultDrawRect(p)

function Starlight.awake!(p::PongArenaWall)
  hw = window_width / 2
  hh = wall_height / 2
  addTriggerBox!(p, hw, hh, hz, p.pos.x + hw, p.pos.y + hh, 0, wmx, wmy, 0)
end

function Starlight.shutdown!(p::PongArenaWall)
  removePhysicsObject!(p)
end

# top wall
wallt = PongArenaWall(window_width, wall_height; pos=XYZ(0, 0))

# bottom wall
wallb = PongArenaWall(window_width, wall_height;
  pos=XYZ(0, window_height - wall_height))

mutable struct PongArenaGoal <: Starlight.Entity
  function PongArenaGoal(w, h; kw...)
    instantiate!(new(); w=w, h=h, kw...)
  end
end

function Starlight.awake!(p::PongArenaGoal)
  hw = goal_width / 2
  hh = window_height / 2
  addTriggerBox!(p, hw, hh, hz, p.pos.x + hw, p.pos.y + hh, 0, gmx, gmy, 0)
end

function Starlight.shutdown!(p::PongArenaGoal)
  removePhysicsObject!(p)
end

# left goal
goal1 = PongArenaGoal(window_height * 2, goal_width;
  pos=XYZ(-goal_width, 0))

# right goal
goal2 = PongArenaGoal(window_height * 2, goal_width;
  pos=XYZ(window_width, 0))

mutable struct PongBall <: Starlight.Renderable
  function PongBall(w, h; kw...)
    instantiate!(new(); w=w, h=h, color=colorant"white", kw...)
  end
end

Starlight.draw(p::PongBall) = defaultDrawRect(p)

function Starlight.awake!(p::PongBall)
  hw = ball_width / 2
  hh = ball_height / 2
  addTriggerBox!(p, hw, hh, hz, p.pos.x + hw, p.pos.y + hh, 0, bmx, bmy, 0)
end

function Starlight.shutdown!(p::PongBall)
  removePhysicsObject!(p)
end

function hit_edge(p::PongBall, o::PongPaddle)
  if o.id == p1.id # left
    return p.abs_pos.x < (o.abs_pos.x + paddle_width - paddle_ball_x_tolerance)
  else # right
    return p.abs_pos.x > (o.abs_pos.x - ball_width + paddle_ball_x_tolerance)
  end
end

function hit_angle(p::PongBall, o::PongPaddle)
  paddle_top = o.abs_pos.y - ball_height / 2
  ball_center = p.abs_pos.y + ball_height / 2
  paddle_hit_area = paddle_height + ball_height
  return -(2 * ((ball_center - paddle_top) / paddle_hit_area) - 1)
end

function wait_and_start_new_round(arg)
  sleep(SLEEP_SEC(secs_between_rounds))
  pg.ball = newball()
end

getP1Score() = parse(Int, score1.str)
getP2Score() = parse(Int, score2.str)

function Starlight.handleMessage!(p::PongBall, col::TS_CollisionEvent)
  otherId = other(p, col)
  vel = TS_BtGetLinearVelocity(p.id)
  if col.colliding
    if otherId ∈ [wallt.id, wallb.id]
      TS_PlaySound(joinpath(asset_base,
        "sounds", "ping_pong_8bit_plop.ogg"), 0, -1)
      TS_BtSetLinearVelocity(p.id, vel.x, -vel.y, vel.z)
    elseif otherId ∈ [goal1.id, goal2.id]
      TS_PlaySound(joinpath(asset_base,
        "sounds", "ping_pong_8bit_peeeeeep.ogg"), 0, -1)
      destroy!(p)

      if otherId == goal2.id
        score1.str = string(getP1Score() + 1)
      elseif otherId == goal1.id
        score2.str = string(getP2Score() + 1)
      end

      if getP1Score() == score_to_win || getP2Score() == score_to_win
        msg.hidden = false
        score1.str = "0"
        score2.str = "0"
      else
        oneshot!(clk(), wait_and_start_new_round)
      end
    elseif otherId ∈ [p1.id, p2.id]
      TS_PlaySound(joinpath(asset_base,
        "sounds", "ping_pong_8bit_beeep.ogg"), 0, -1)
      o = getEntityById(otherId)
      TS_BtSetLinearVelocity(p.id, (hit_edge(p, o) ? 1 : -1) * vel.x,
        ball_vel_y(hit_angle(p, o)), vel.z)
    end
  end
end

mutable struct PongGame <: Starlight.Entity
  function PongGame()
    instantiate!(new(); ball=nothing, w=false, s=false, up=false, down=false,
      p1TouchingTopWall=false, p2TouchingTopWall=false,
      p1TouchingBottomWall=false, p2TouchingBottomWall=false)
  end
end

function Starlight.awake!(p::PongGame)
  listenFor(p, SDL_KeyboardEvent)
  listenFor(p, SDL_QuitEvent)
  TS_BtSetGravity(0, 0, 0)
end

function Starlight.shutdown!(p::PongGame)
  unlistenFrom(p, SDL_KeyboardEvent)
  unlistenFrom(p, SDL_QuitEvent)
end

function newball()
  p = PongBall(ball_width, ball_height;
    pos=XYZ((window_width - ball_width) / 2,
    (window_height - ball_height) / 2))
  TS_BtSetLinearVelocity(p.id,
    ((rand(Bool)) ? 1 : -1) * ball_vel_x, ball_vel_y(2 * rand() - 1), 0)
  return p
end

function Starlight.handleMessage!(p::PongGame, key::SDL_KeyboardEvent)
  if key.keysym.scancode == SDL_SCANCODE_SPACE && !msg.hidden
    msg.hidden = true
    p.ball = newball()
  elseif key.keysym.scancode == SDL_SCANCODE_W
    p.w = key.state == SDL_PRESSED
  elseif key.keysym.scancode == SDL_SCANCODE_S
    p.s = key.state == SDL_PRESSED
  elseif key.keysym.scancode == SDL_SCANCODE_UP
    p.up = key.state == SDL_PRESSED
  elseif key.keysym.scancode == SDL_SCANCODE_DOWN
    p.down = key.state == SDL_PRESSED
  end
end

function Starlight.handleMessage!(p::PongGame, q::SDL_QuitEvent)
  shutdown!(a)
end

function Starlight.update!(p::PongGame, Δ::AbstractFloat)
  TS_BtSetLinearVelocity(p1.id, 0, 0, 0)
  TS_BtSetLinearVelocity(p2.id, 0, 0, 0)
  if p.w && !p.p1TouchingTopWall
    TS_BtSetLinearVelocity(p1.id, 0, -pv, 0)
  elseif p.s && !p.p1TouchingBottomWall
    TS_BtSetLinearVelocity(p1.id, 0, pv, 0)
  end
  if p.up && !p.p2TouchingTopWall
    TS_BtSetLinearVelocity(p2.id, 0, -pv, 0)
  elseif p.down && !p.p2TouchingBottomWall
    TS_BtSetLinearVelocity(p2.id, 0, pv, 0)
  end
end

pg = PongGame()

run!(a)


text:
"""
Run multiple tests in a controlled context.

This provides the following features which are missing from the default `@testset` macro:

* Test cases are logged using `@debug`, to make it easier to debug and trace test execution.

* Test cases can be filtered using regular expression patterns, to allow debugging specific test
  cases.

* Each test case starts with a controlled environment whose content is independent from the other
  test cases. This environment can be created incrementally by nesting test sets, allowing
  setup/teardown steps to be reused for multiple test cases.
"""
module TestContexts

using Test

import Base: getproperty

export PrivateValue
export SharedValue
export tc
export test_case
export test_name
export test_patterns
export PropertyValue
export test_set

mutable struct TestContext
    _patterns::Vector{Regex}
    _names::Vector{String}
    _data::Dict{Symbol,Any}
    _values::Union{Dict{Symbol,Any},Nothing}
    TestContext() = new(Vector{Regex}(), Vector{String}(), Dict{Symbol,Any}(), nothing)
end

"""
    SharedValue(value::Any)

A shared value will be used as-is by all tests. If the value is mutable, the test cases are
responsible to never change it (or at least ensure the original value is restored by the end of each
test).
"""
struct SharedValue
    value::Any
end

"""
    PrivateValue(make::Function, finalize::Union{Function,Nothing}=nothing)

A private value will be (lazily) re-created for each test (that accesses it) by invoking the `make`
function. This value can be mutated at will by the test case without affecting any other test case.
If the `finalize` function was specified, it is invoked at the end of each test case (that accessed
the value) and is given the value so it can be properly disposed of.
"""
struct PrivateValue
    make::Function
    finalize::Union{Function,Nothing}
    PrivateValue(make::Function, finalize::Union{Function,Nothing} = nothing) =
        new(make, finalize)
end

"""
Possible values for a test property.
"""
const PropertyValue = Union{SharedValue,PrivateValue}

function getproperty(context::TestContext, property::Symbol)::Any
    if String(property)[1] == '_'
        return getfield(context, property)
    end

    values = getfield(context, :_values)
    if values == nothing
        error(
            "Trying to access property :$(property) outside test case in test context $(join(context._names, "/"))",
        )
    end

    value = get(values, property, missing)
    if !ismissing(value)
        return value
    end

    property_value = get(getfield(context, :_data), property, missing)
    if ismissing(property_value)
        throw(
            KeyError(
                "Test context $(join(context._names, "/")) has no property :$(property)",
            ),
        )
    end

    if property_value isa SharedValue
        value = property_value.value
    else
        @assert property_value isa PrivateValue
        value = property_value.make()
    end

    values[property] = value
    return value
end

"""
The global context for running tests. This is mainly used to access the test environment; by
accessing `tc.foo` one obtains the value of some `foo` property which was previously set up by a
`test_set` or by the `test_case` itself.
"""
tc = TestContext()

"""
    test_name()::AbstractString

Return the full name of the current test context. This is a `/`-separated path containing the names
of all the nested `test_set` and `test_case` calls. This full name is automatically logged using
`@debug` at the start of each test case. It is also matched against any `test_patterns` to allow
executing only a specific subset of the tests.
"""
function test_name()::AbstractString
    return join(tc._names, "/")
end

"""
    test_patterns(patterns::Vector{Union{String,Regex}})::Nothing

Specify patterns for the tests to run. Only tests whose full `test_name` matches one of the patterns
will be run. If the vector is empty, all tests will be run.
"""
function test_patterns(patterns::Vector)::Nothing
    tc._patterns = [pattern isa Regex ? pattern : Regex(pattern) for pattern in patterns]

    return nothing
end

"""
    test_set(body::Function, name::String, data...)

Similar to @testset but uses the global `tc` test context for running tests under the given `name`.
The optional `data` must a series of zero or more entries, each in the format `property => value`
where `property` is a symbol and `value` is a `PropertyValue`.

Nesting test sets is allowed. This is a common pattern for incrementally setting up a test
environment for the actual test cases. In BDD terminology, a test set is similar to the "given" or
"when" clauses.

The property values are not accessible (yet). See `test_case` for actually accessing the data.
"""
function test_set(body::Function, name::String, data...)::Nothing
    @assert tc._values == nothing
    push!(tc._names, name)
    data = Dict{Symbol,PropertyValue}(data...)
    for property in keys(data)
        if property in keys(tc._data)
            error("Trying to override property $(property) of test context $(test_name())")
        end
    end

    merge!(tc._data, data)

    try
        @testset "$name" begin
            body()
        end
    finally
        pop!(tc._names)
        for property in keys(data)
            delete!(tc._data, property)
        end
    end

    return nothing
end

"""
    test_case(body::Function, name::String, data...)

Similar to `test_set` but is used to wrap actual `@test` code. Allows access to any data previously
setup by the containing `test_set` calls, if any, or in the `test_case` call itself. The properties
data is available during the test by accessing `tc.property`. A separate instance is created
(lazily) for any private data for each test case. If a `finalize` function was specified, it is
invoked to properly dispose of the data at the end of the test case.

Nesting a test set or a test case inside a test case is forbidden. That is, a test case is expected
to actually test some specific scenario which was set up by the containing test sets. In BDD
terminology, a test case is similar to the "then" clause.

If any `test_patterns` were specified, and the full `test_name` does not match any of these
patterns, then the test case is silently ignored. Otherwise, the test name is logged using `@debug`
before the test case code is executed.
"""
function test_case(body::Function, name::String, data...)::Nothing
    test_set(name, data...) do
        full_name = test_name()
        patterns = tc._patterns
        if !isempty(patterns)
            include = false

            for pattern in patterns
                if match(pattern, full_name) != nothing
                    include = true
                    break
                end
            end

            if !include
                return
            end
        end

        tc._values = Dict{String,Any}()

        try
            @testset "$name" begin
                @debug "Test $(full_name)..."
                body()
            end
        finally
            for (property, value) in tc._values
                property_value = tc._data[property]
                if property_value isa PrivateValue && property_value.finalize != nothing
                    property_value.finalize(value)
                end
            end

            tc._values = nothing
        end
    end
end

end # module


text:
include("Canonical/includes.jl")
include("StronglyTyped/includes.jl")
include("GeneExpressionProgramming/includes.jl")
include("GrammaticalEvolution/includes.jl")
include("miscTreeFunctions.jl")
include("evaluation.jl")
include("initialization.jl")
include("mutation.jl")

max_stars_repo_name: SergioGmezM/GeneticJulia

max_issues_repo_name: SergioGmezM/GeneticJulia

max_forks_repo_name: SergioGmezM/GeneticJulia


text:
"""
一些常见的相互作用
"""

module Interactions

using ..Basics

export triangular_system_heisenberg

"""
三角格子上交换相互作用的Γ4
"""
function triangular_system_heisenberg(patcs::Vector{Point2D}, kadd, J)
    pnum = length(patcs)
    result = zeros(pnum, pnum, pnum)
    co1 = 0.5
    co2 = sqrt(3) * 0.5
    for idxs in CartesianIndices(result)
        i1, i2, i3 = Tuple(idxs)
        k1, k2, k3 = patcs[i1], patcs[i2], patcs[i3]
        q1 = kadd(k3, -k1)
        q2 = kadd(k3, -k2)
        phase = cos(-co1*q1.x + co2*q1.y)
        phase += cos(co1*q1.x + co2*q1.y)
        phase += cos(q1.x)
        phase += 0.5*cos(-co1*q2.x + co2*q2.y)
        phase += 0.5*cos(co1*q2.x + co2*q2.y)
        phase += 0.5*cos(q2.x)
        result[i1, i2, i3] = -J * phase
    end
    return result
end

end


text:
module Stats

using ..Fed: STATS, Statistics

# --------------------------------
# Include
# --------------------------------

include("metrics.jl")
include("base_stats.jl")

include("vanilla/vanilla_net.jl")
include("vanilla/vanilla_stats.jl")

include("gd/gd_net.jl")
include("gd/gd_stats.jl")

"""
    update_stats!(stat, round_num, loss, accuracy)

Updates all the statistics at once. This function is intended to be used at the
end of each communication round. It assumes that some values have been updated
while calling the `PayloadSerde` functions.
"""
function update_stats!(
    stats::T,
    round_num::Int,
    loss::Float32,
    accuracy::Float32
) where T <: Statistics
    update_stats!(stats)
    update_stats!(stats.base, loss, accuracy)
    update_stats!(stats.network, round_num)
end

# --------------------------------
# Export
# --------------------------------

export BaseStats, VanillaStats, GDStats, update_stats!

end # module


text:
try
    kill(run(`vim --servername`,wait=false))
    @info "vim editor support enabled (required by JuliaTeX)"
catch
    @warn "vim editor not installed! (required by JuliaTeX)"
end
try
    kill(run(`latexmk`,wait=false))
    @info "latexmk compiler support enabled (required by JuliaTeX)"
catch
    @warn "latexmk compiler not installed! (required by JuliaTeX)"
end
try
    kill(run(`zathura`,wait=false))
    @info "zathura viewer support enabled (required by JuliaTeX)"
catch
    @warn "zathura viewer not installed! (required by JuliaTeX)"
end
@info "vimtex is the recommended plugin for vim & JuliaTeX"


text:
using ModernGL, GeometryTypes, GLAbstraction, GLWindow

# Create the window. This sets all the hints and makes the context current.
window = create_glcontext("Drawing polygons exercise 1", resolution=(800,600))

# A slightly-simplified VAO generator call
vao = glGenVertexArrays()
glBindVertexArray(vao)

# The positions of the vertices in our rectangle
vertex_positions = Point{2,Float32}[(-0.5,  0.5),     # top-left
                                    ( 0.5,  0.5),     # top-right
                                    ( 0.0, -0.5)]     # bottom-center
# The vertex shader---note the `vert` in front of """
vertex_shader = vert"""
#version 150

in vec2 position;

void main()
{
    gl_Position = vec4(position, 0.0, 1.0);
}
"""

# The fragment shader
fragment_shader = frag"""
# version 150

out vec4 outColor;

void main()
{
    outColor = vec4(1.0, 1.0, 1.0, 1.0);
}
"""

# Link everything together, using the corresponding shader variable as
# the Dict key
bufferdict = Dict(:position=>Buffer(vertex_positions))

ro = std_renderobject(bufferdict,
                      LazyShader(vertex_shader, fragment_shader))

# Draw until we receive a close event
glClearColor(0,0,0,0)
while !GLFW.WindowShouldClose(window)
    glClear(GL_COLOR_BUFFER_BIT)
    GLAbstraction.render(ro)
    GLFW.SwapBuffers(window)
    GLFW.PollEvents()
    if GLFW.GetKey(window, GLFW.KEY_ESCAPE) == GLFW.PRESS
        GLFW.SetWindowShouldClose(window, true)
    end
end

GLFW.DestroyWindow(window)  # needed if you're running this from the REPL


text:
id_counter = 0
ECS = [[]]
components = [[]]
pop!(ECS)
pop!(components)
entities = []

function CreateEntity()::UInt16
    global id_counter += 1
end

function AddComponent(entity, Component)
    if !(entity in entities)
        push!(entities, entity)
        push!(ECS, [])
        push!(components, [])
    end

    i = findall(x->x == entity, entities)
    push!(ECS[i[1]], Component)
    push!(components[i[1]], Type{typeof(Component)})
end

function RemoveComponent(entity, Component)
    if !(entity in entities)
       println("no such an entity!!!")
    end
	i = findall(x->x == entity, entities)
	if !(Component in components[i[1]])
		println("entity $(entity) does not contain this component!!!")
	end
	c = findall(x->x == Component, components[i[1]])
    deleteat!(ECS[i[1]], c[1])
	deleteat!(components[i[1]], c[1])
end

function GetComponent(entity, Component)
    i = findall(x->x == entity, entities)
	if !(Component in components[i[1]])
		println("entity $(entity) does not contain this component!!!")
		return nothing
	end

    c = findall(x->x == Component, components[i[1]])
    return ECS[i[1]][c[1]]
end

#ecs = EntityComponentSystem()
#=
e1 = createEntity()
e2 = createEntity()
e3 = createEntity()

println(e1)
println(e2)
println(e3)

addComponent(e2, SpriteRenderer())
println(ECS)

addComponent(e3, Transform(0, 0, 0))
println(ECS)

addComponent(e1, Transform(5, 46, 8))
println(ECS)
addComponent(e1, SpriteRenderer())
println(ECS)

addComponent(e2, Transform(0, 1453, 5))
println(ECS)

removeComponent(e2, Type{Transform})
println(ECS)
=#


text:
function type2col(i)
    if i == 0
        return colorant"black"
    elseif i == 1
        return colorant"blue"
    elseif i == 2
        return colorant"white"
    elseif i == 3
         return colorant"red"
    elseif i == 4
         return colorant"green"
    else
        return colorant"black"
    end
end

function display_flag(flag::Array{Float64,2},title_string::String)
    heatmap(type2col.(flag),xticks = false,yticks = false,title = title_string, titlefont=font(10,"Computer Modern"))
end

function display_flag(flag::Array{Float64,2})
    heatmap(type2col.(flag),xticks = false,yticks = false)
end

max_stars_repo_name: harrybooth/FractalDevelopment

max_issues_repo_name: harrybooth/FractalDevelopment

max_forks_repo_name: harrybooth/FractalDevelopment


text:
@testset "#465" begin
  G, mG = unit_group(quo(ZZ, 8)[1]);
  H = collect(G)
  X = map(mG, H)
  @test H == map(x->preimage(mG, x), X)
end


text:
module equalityga
    # implement the GA interface inside here
type EqualityMonster <: Entity
    abcde::Array
    fitness

    EqualityMonster() = new(Array(Int, 5), nothing)
    EqualityMonster(abcde) = new(abcde, nothing)
end

function create_entity(num)
    # for simplicity sake, let's limit the values for abcde to be integers in [-42, 42]
    EqualityMonster(rand(Int, 5) % 43)
end

function fitness(ent)
    # we want the expression `a + 2b + 3c + 4d + 5e - 42`
    # to be as close to 0 as possible
    score = ent.abcde[1] +
            2 * ent.abcde[2] +
            3 * ent.abcde[3] +
            4 * ent.abcde[4] +
            5 * ent.abcde[5]

    abs(score - 42)
end

function isless(lhs::EqualityMonster, rhs::EqualityMonster)
    abs(lhs.fitness) > abs(rhs.fitness)
end

function group_entities(pop)
    if pop[1].fitness == 0
        return
    end

    # simple naive groupings that pair the best entitiy with every other
    for i in 1:length(pop)
        produce([1, i])
    end
end

function crossover(group)
    child = EqualityMonster()

    # grab each element from a random parent
    num_parents = length(group)
    for i in 1:length(group[1].abcde)
        parent = (rand(Uint) % num_parents) + 1
        child.abcde[i] = group[parent].abcde[i]
    end

    child
end

function mutate(ent)
    # let's go crazy and mutate 20% of the time
    rand(Float64) < 0.8 && return

    rand_element = rand(Uint) % 5 + 1
    ent.abcde[rand_element] = rand(Int) % 43
end

end

max_stars_repo_path: Julia/Untitled Folder 1/2-ga.jl

max_issues_repo_path: Julia/Untitled Folder 1/2-ga.jl

max_forks_repo_path: Julia/Untitled Folder 1/2-ga.jl


text:
# Use
#    @warnpcfail precompile(args...)
# if you want to be warned when a precompile directive fails
macro warnpcfail(ex::Expr)
    modl = __module__
    file = __source__.file === nothing ? "?" : String(__source__.file)
    line = __source__.line
    quote
        $(esc(ex)) || @warn """precompile directive
     $($(Expr(:quote, ex)))
 failed. Please report an issue in $($modl) (after checking for duplicates) or remove this directive.""" _file=$file _line=$line
    end
end

function _precompile_()
    ccall(:jl_generating_output, Cint, ()) == 1 || return nothing
    isdefined(Alexya, Symbol("##Scale#11")) && precompile(Tuple{Alexya.var"##Scale#11", Iterators.Pairs{Symbol, Any, Tuple{Symbol, Symbol}, NamedTuple{(:margin, :align), Tuple{NamedTuple{(:top, :left, :right, :bottom), Tuple{Int64, Int64, Int64, Int64}}, Array{Base.Pair{A, B} where B where A, 1}}}}, typeof(Alexya.Scale), Bool, Vararg{Any}})
    isdefined(Alexya, Symbol("##Scale#11")) && precompile(Tuple{Alexya.var"##Scale#11", Iterators.Pairs{Symbol, Bool, Tuple{Symbol}, NamedTuple{(:hexpand,), Tuple{Bool}}}, typeof(Alexya.Scale), Bool, Vararg{Any}})
    isdefined(Alexya, Symbol("##Scale#11")) && precompile(Tuple{Alexya.var"##Scale#11", Iterators.Pairs{Symbol, Integer, Tuple{Symbol, Symbol}, NamedTuple{(:margin_bottom, :hexpand), Tuple{Int64, Bool}}}, typeof(Alexya.Scale), Bool, Vararg{Any}})
    isdefined(Alexya, Symbol("##Scale#11")) && precompile(Tuple{Alexya.var"##Scale#11", Iterators.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, typeof(Alexya.Scale), Bool, Vararg{Any}})
    isdefined(Alexya, Symbol("#@align")) && precompile(Tuple{Alexya.var"#@align", LineNumberNode, Module, Int, Int})
    isdefined(Alexya, Symbol("#@button_str")) && precompile(Tuple{Alexya.var"#@button_str", LineNumberNode, Module, Int})
    isdefined(Alexya, Symbol("#@canvas")) && precompile(Tuple{Alexya.var"#@canvas", LineNumberNode, Module})
    isdefined(Alexya, Symbol("#@colorbtn_str")) && precompile(Tuple{Alexya.var"#@colorbtn_str", LineNumberNode, Module, Int})
    isdefined(Alexya, Symbol("#@create")) && precompile(Tuple{Alexya.var"#@create", LineNumberNode, Module, Int})
    isdefined(Alexya, Symbol("#@entry_str")) && precompile(Tuple{Alexya.var"#@entry_str", LineNumberNode, Module, Int})
    isdefined(Alexya, Symbol("#@framecount")) && precompile(Tuple{Alexya.var"#@framecount", LineNumberNode, Module})
    isdefined(Alexya, Symbol("#@framerate")) && precompile(Tuple{Alexya.var"#@framerate", LineNumberNode, Module})
    isdefined(Alexya, Symbol("#@height")) && precompile(Tuple{Alexya.var"#@height", LineNumberNode, Module})
    isdefined(Alexya, Symbol("#@hexpand")) && precompile(Tuple{Alexya.var"#@hexpand", LineNumberNode, Module})
    isdefined(Alexya, Symbol("#@homogeneous")) && precompile(Tuple{Alexya.var"#@homogeneous", LineNumberNode, Module, Int, Int})
    isdefined(Alexya, Symbol("#@homogeneous")) && precompile(Tuple{Alexya.var"#@homogeneous", LineNumberNode, Module})
    isdefined(Alexya, Symbol("#@init")) && precompile(Tuple{Alexya.var"#@init", LineNumberNode, Module, Int, Int, Int})
    isdefined(Alexya, Symbol("#@label_str")) && precompile(Tuple{Alexya.var"#@label_str", LineNumberNode, Module, Int})
    isdefined(Alexya, Symbol("#@layout")) && precompile(Tuple{Alexya.var"#@layout", LineNumberNode, Module, Int})
    isdefined(Alexya, Symbol("#@margin")) && precompile(Tuple{Alexya.var"#@margin", LineNumberNode, Module, Int, Int, Int, Int})
    isdefined(Alexya, Symbol("#@margin")) && precompile(Tuple{Alexya.var"#@margin", LineNumberNode, Module, Int, Int})
    isdefined(Alexya, Symbol("#@margin")) && precompile(Tuple{Alexya.var"#@margin", LineNumberNode, Module, Int})
    isdefined(Alexya, Symbol("#@on")) && precompile(Tuple{Alexya.var"#@on", LineNumberNode, Module, Vararg{Any}})
    isdefined(Alexya, Symbol("#@options")) && precompile(Tuple{Alexya.var"#@options", LineNumberNode, Module, Int})
    isdefined(Alexya, Symbol("#@use")) && precompile(Tuple{Alexya.var"#@use", LineNumberNode, Module, Int})
    isdefined(Alexya, Symbol("#@vexpand")) && precompile(Tuple{Alexya.var"#@vexpand", LineNumberNode, Module, Int})
    isdefined(Alexya, Symbol("#@width")) && precompile(Tuple{Alexya.var"#@width", LineNumberNode, Module})
    isdefined(Alexya, Symbol("#@window")) && precompile(Tuple{Alexya.var"#@window", LineNumberNode, Module})
    isdefined(Alexya, Symbol("#Box##kw")) && precompile(Tuple{Alexya.var"#Box##kw", NamedTuple{(:margin, :hexpand, :vexpand, :align), Tuple{NamedTuple{(:top, :left, :right, :bottom), Tuple{Int64, Int64, Int64, Int64}}, Bool, Bool, Array{Base.Pair{A, B} where B where A, 1}}}, typeof(Alexya.Box), Tuple{}, Symbol})
    isdefined(Alexya, Symbol("#Button##kw")) && precompile(Tuple{Alexya.var"#Button##kw", NamedTuple{(:hexpand,), Tuple{Bool}}, typeof(Alexya.Button), String})
    isdefined(Alexya, Symbol("#Entry##kw")) && precompile(Tuple{Alexya.var"#Entry##kw", NamedTuple{(:text, :margin), Tuple{String, NamedTuple{(:top, :left, :right, :bottom), Tuple{Int64, Int64, Int64, Int64}}}}, typeof(Alexya.Entry)})
    isdefined(Alexya, Symbol("#Entry##kw")) && precompile(Tuple{Alexya.var"#Entry##kw", NamedTuple{(:text,), Tuple{String}}, typeof(Alexya.Entry)})
    isdefined(Alexya, Symbol("#Grid##kw")) && precompile(Tuple{Alexya.var"#Grid##kw", NamedTuple{(:____,), Tuple{Array{(Base.Pair{A, B} where B) where A, 1}}}, typeof(Alexya.Grid), typeof(identity)})
    isdefined(Alexya, Symbol("#Grid##kw")) && precompile(Tuple{Alexya.var"#Grid##kw", NamedTuple{(:____,), Tuple{Array{Base.Pair{A, B} where B where A, 1}}}, typeof(Alexya.Grid), Array{Any, 2}})
    isdefined(Alexya, Symbol("#Grid##kw")) && precompile(Tuple{Alexya.var"#Grid##kw", NamedTuple{(:homogeneous,), Tuple{Array{Base.Pair{A, B} where B where A, 1}}}, typeof(Alexya.Grid), Array{Any, 2}})
    isdefined(Alexya, Symbol("#Label##kw")) && precompile(Tuple{Alexya.var"#Label##kw", NamedTuple{(:halign,), Tuple{Int32}}, typeof(Alexya.Label), String})
    isdefined(Alexya, Symbol("#Label##kw")) && precompile(Tuple{Alexya.var"#Label##kw", NamedTuple{(:margin_left, :halign), Tuple{Int64, Int32}}, typeof(Alexya.Label), String})
    isdefined(Alexya, Symbol("#Slider##kw")) && precompile(Tuple{Alexya.var"#Slider##kw", NamedTuple{(:init,), Tuple{Int64}}, typeof(Alexya.Slider), Base.UnitRange{Int64}})
    isdefined(Alexya, Symbol("#Slider##kw")) && precompile(Tuple{Alexya.var"#Slider##kw", NamedTuple{(:margin, :align), Tuple{NamedTuple{(:top, :left, :right, :bottom), Tuple{Int64, Int64, Int64, Int64}}, Array{Base.Pair{A, B} where B where A, 1}}}, typeof(Alexya.Slider), Base.UnitRange{Int64}})
    isdefined(Alexya, Symbol("#SpinButton##kw")) && precompile(Tuple{Alexya.var"#SpinButton##kw", NamedTuple{(:init, :halign), Tuple{Float64, Int32}}, typeof(Alexya.SpinButton), Base.UnitRange{Int64}})
    isdefined(Alexya, Symbol("#SpinButton##kw")) && precompile(Tuple{Alexya.var"#SpinButton##kw", NamedTuple{(:init, :halign), Tuple{Int64, Int32}}, typeof(Alexya.SpinButton), Base.UnitRange{Int64}})
    isdefined(Alexya, Symbol("#Switch##kw")) && precompile(Tuple{Alexya.var"#Switch##kw", NamedTuple{(:halign,), Tuple{Int32}}, typeof(Alexya.Switch), Bool})
    isdefined(Alexya, Symbol("#set!##kw")) && precompile(Tuple{Alexya.var"#set!##kw", NamedTuple{(:active,), Tuple{Bool}}, typeof(Alexya.set!), Gtk.GtkSwitchLeaf})
    isdefined(Alexya, Symbol("#set!##kw")) && precompile(Tuple{Alexya.var"#set!##kw", NamedTuple{(:margin,), Tuple{NamedTuple{(:top, :left, :right, :bottom), Tuple{Int64, Int64, Int64, Int64}}}}, typeof(Alexya.set!), Gtk.GtkBoxLeaf})
    isdefined(Alexya, Symbol("#set!##kw")) && precompile(Tuple{Alexya.var"#set!##kw", NamedTuple{(:rgba,), Tuple{ColorTypes.RGB{ColorTypes.FixedPointNumbers.Normed{UInt8, 8}}}}, typeof(Alexya.set!), Gtk.GtkColorButtonLeaf})
    isdefined(Alexya, Symbol("#set!##kw")) && precompile(Tuple{Alexya.var"#set!##kw", NamedTuple{(:text,), Tuple{String}}, typeof(Alexya.set!), Gtk.GtkEntryLeaf})
    isdefined(Alexya, Symbol("#start##kw")) && precompile(Tuple{Alexya.var"#start##kw", NamedTuple{(:async,), Tuple{Bool}}, typeof(Alexya.start)})
    precompile(Tuple{typeof(Alexya.ColorButton), ColorTypes.RGB{ColorTypes.FixedPointNumbers.Normed{UInt8, 8}}})
    precompile(Tuple{typeof(Alexya.ColorButton)})
    precompile(Tuple{typeof(Alexya.Label), String})
    precompile(Tuple{typeof(Alexya.ProgressBar)})
    precompile(Tuple{typeof(Alexya.Scale), Bool, Vararg{Any}})
    precompile(Tuple{typeof(Alexya.SpinButton), Base.UnitRange{Int64}})
    precompile(Tuple{typeof(Alexya.Spinner)})
    precompile(Tuple{typeof(Alexya.Switch), Bool})
    precompile(Tuple{typeof(Alexya.add!), Gtk.GtkBoxLeaf, Gtk.GtkButtonLeaf, Gtk.GtkSpinButtonLeaf, Vararg{Gtk.GtkWidget}})
    precompile(Tuple{typeof(Alexya.add!), Gtk.GtkBoxLeaf, Gtk.GtkButtonLeaf})
    precompile(Tuple{typeof(Alexya.add!), Gtk.GtkBoxLeaf, Gtk.GtkCheckButtonLeaf})
    precompile(Tuple{typeof(Alexya.add!), Gtk.GtkBoxLeaf, Gtk.GtkColorButtonLeaf})
    precompile(Tuple{typeof(Alexya.add!), Gtk.GtkBoxLeaf, Gtk.GtkEntryLeaf, Gtk.GtkScaleLeaf, Vararg{Gtk.GtkWidget}})
    precompile(Tuple{typeof(Alexya.add!), Gtk.GtkBoxLeaf, Gtk.GtkEntryLeaf})
    precompile(Tuple{typeof(Alexya.add!), Gtk.GtkBoxLeaf, Gtk.GtkLabelLeaf})
    precompile(Tuple{typeof(Alexya.add!), Gtk.GtkBoxLeaf, Gtk.GtkScaleLeaf, Gtk.GtkSpinButtonLeaf, Vararg{Gtk.GtkWidget}})
    precompile(Tuple{typeof(Alexya.add!), Gtk.GtkBoxLeaf, Gtk.GtkScaleLeaf})
    precompile(Tuple{typeof(Alexya.add!), Gtk.GtkBoxLeaf, Gtk.GtkSpinButtonLeaf})
    precompile(Tuple{typeof(Alexya.add!), Gtk.GtkBoxLeaf, Gtk.GtkSwitchLeaf})
    precompile(Tuple{typeof(Alexya.add!), Gtk.GtkBoxLeaf, Tuple{Gtk.GtkButtonLeaf, Gtk.GtkSpinButtonLeaf, Gtk.GtkColorButtonLeaf}})
    precompile(Tuple{typeof(Alexya.add!), Gtk.GtkScrolledWindowLeaf, Gtk.GtkGridLeaf})
    precompile(Tuple{typeof(Alexya.add!), Gtk.GtkWindowLeaf, Gtk.GtkCanvas})
    precompile(Tuple{typeof(Alexya.add!), Gtk.GtkWindowLeaf, Gtk.GtkPanedLeaf})
    precompile(Tuple{typeof(Alexya.addwidget), Alexya.Controls})
    precompile(Tuple{typeof(Alexya.addwidget), Gtk.GtkEntryLeaf})
    precompile(Tuple{typeof(Alexya.addwidget), Gtk.GtkGridLeaf})
    precompile(Tuple{typeof(Alexya.addwidget), Gtk.GtkScaleLeaf})
    precompile(Tuple{typeof(Alexya.aside), Symbol, Int64})
    precompile(Tuple{typeof(Alexya.canvasonly), Gtk.GtkCanvas})
    precompile(Tuple{typeof(Alexya.create_option), Base.Complex{Int64}, Symbol})
    precompile(Tuple{typeof(Alexya.create_option), Base.UnitRange{Int64}, Symbol})
    precompile(Tuple{typeof(Alexya.create_option), Bool, Symbol})
    precompile(Tuple{typeof(Alexya.create_option), ColorTypes.RGB{ColorTypes.FixedPointNumbers.Normed{UInt8, 8}}, Symbol})
    precompile(Tuple{typeof(Alexya.create_option), Int64, Symbol})
    precompile(Tuple{typeof(Alexya.create_option), Luxor.Point, Symbol})
    precompile(Tuple{typeof(Alexya.create_option), NamedTuple{(:complex, :point), Tuple{Base.Complex{Int64}, Luxor.Point}}, Symbol})
    precompile(Tuple{typeof(Alexya.create_option), NamedTuple{(:inspect, :close), Tuple{Gtk.GtkButtonLeaf, Gtk.GtkButtonLeaf}}, Symbol})
    precompile(Tuple{typeof(Alexya.create_option), NamedTuple{(:slider, :φ, :color, :switch), Tuple{Base.UnitRange{Int64}, Tuple{Base.UnitRange{Int64}, Int64}, ColorTypes.RGB{ColorTypes.FixedPointNumbers.Normed{UInt8, 8}}, Bool}}, Symbol})
    precompile(Tuple{typeof(Alexya.create_option), NamedTuple{(:text_field, :number, :δ), Tuple{String, Int64, Tuple{Int64, Base.UnitRange{Int64}}}}, Symbol})
    precompile(Tuple{typeof(Alexya.create_option), String, Symbol})
    precompile(Tuple{typeof(Alexya.create_option), Tuple{Base.UnitRange{Int64}, Int64}, Symbol})
    precompile(Tuple{typeof(Alexya.create_option), Tuple{Int64, Base.UnitRange{Int64}}, Symbol})
    precompile(Tuple{typeof(Alexya.current_app), Symbol})
    precompile(Tuple{typeof(Alexya.extend!), Array{Int64, 1}})
    precompile(Tuple{typeof(Alexya.getpoints), String})
    precompile(Tuple{typeof(Alexya.getprop), Gtk.GtkBoxLeaf, String, Type{Int64}})
    precompile(Tuple{typeof(Alexya.getprop), Gtk.GtkBoxLeaf, Symbol, Type{Bool}})
    precompile(Tuple{typeof(Alexya.getprop), Gtk.GtkBoxLeaf, Symbol, Type{UInt32}})
    precompile(Tuple{typeof(Alexya.getprop), Gtk.GtkEntryLeaf, Symbol, Type{String}})
    precompile(Tuple{typeof(Alexya.init), String, Int64, Int64})
    precompile(Tuple{typeof(Alexya.limit), Array{Int64, 1}, Int64})
    precompile(Tuple{typeof(Alexya.loadsprite), String})
    precompile(Tuple{typeof(Alexya.mag), Array{Int64, 1}})
    precompile(Tuple{typeof(Alexya.onevent), typeof(identity), Symbol, Alexya.Option{Gtk.GtkButton}})
    precompile(Tuple{typeof(Alexya.point), Array{Float64, 1}})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkBoxLeaf, Symbol, Array{Base.Pair{A, B} where B where A, 1}})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkBoxLeaf, Symbol, Bool})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkBoxLeaf, Symbol, Int32})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkBoxLeaf, Symbol, Int64})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkBoxLeaf, Symbol, NamedTuple{(:top, :left, :right, :bottom), Tuple{Int64, Int64, Int64, Int64}}})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkButtonLeaf, Symbol, typeof(identity)})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkCheckButtonLeaf, Symbol, typeof(identity)})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkEntryLeaf, Symbol, Bool})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkEntryLeaf, Symbol, NamedTuple{(:top, :left, :right, :bottom), Tuple{Int64, Int64, Int64, Int64}}})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkEntryLeaf, Symbol, String})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkEntryLeaf, Symbol, typeof(identity)})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkGridLeaf, Symbol, Bool})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkGridLeaf, Symbol, Int64})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkGridLeaf, Symbol, NamedTuple{(:top, :left, :right, :bottom), Tuple{Int64, Int64, Int64, Int64}}})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkLabelLeaf, Symbol, Int32})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkLabelLeaf, Symbol, Int64})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkScaleLeaf, Symbol, Array{Base.Pair{A, B} where B where A, 1}})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkScaleLeaf, Symbol, Bool})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkScaleLeaf, Symbol, Int32})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkScaleLeaf, Symbol, Int64})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkScaleLeaf, Symbol, NamedTuple{(:top, :left, :right, :bottom), Tuple{Int64, Int64, Int64, Int64}}})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkScaleLeaf, Symbol, typeof(identity)})
    precompile(Tuple{typeof(Alexya.set!), Gtk.GtkSpinButtonLeaf, Symbol, typeof(identity)})
    precompile(Tuple{typeof(Alexya.setevent), Alexya.Event{:appclosed}})
    precompile(Tuple{typeof(Alexya.setevent), Alexya.Event{:keypress}})
    precompile(Tuple{typeof(Alexya.setevent), Alexya.Event{:mousemotion}})
    precompile(Tuple{typeof(Alexya.setevent), Alexya.Event{:mousemove}})
    precompile(Tuple{typeof(Alexya.setevent), Alexya.Event{:mousepress}})
    precompile(Tuple{typeof(Alexya.setevent), Alexya.Event{:mouserelease}})
    precompile(Tuple{typeof(Alexya.setevent), Alexya.Event{:setup}})
    precompile(Tuple{typeof(Alexya.setevent), Alexya.Event{:update}})
    precompile(Tuple{typeof(Alexya.setvalue!), Gtk.GtkColorButtonLeaf, ColorTypes.RGB{ColorTypes.FixedPointNumbers.Normed{UInt8, 8}}})
    precompile(Tuple{typeof(Alexya.setvalue!), Gtk.GtkScaleLeaf, Float64})
    precompile(Tuple{typeof(Alexya.setvalue!), Gtk.GtkSpinButtonLeaf, Float64})
    precompile(Tuple{typeof(Alexya.setvalue!), Gtk.GtkSpinButtonLeaf, Int64})
    precompile(Tuple{typeof(Alexya.setvalue!), Gtk.GtkSwitchLeaf, Bool})
    precompile(Tuple{typeof(Alexya.start)})
    precompile(Tuple{typeof(Alexya.use), Symbol, typeof(identity)})
    precompile(Tuple{typeof(Alexya.uselayout), typeof(identity)})
    precompile(Tuple{typeof(Alexya.value), Gtk.GtkColorButtonLeaf})
    precompile(Tuple{typeof(Alexya.value), Gtk.GtkEntryLeaf})
    precompile(Tuple{typeof(Alexya.value), Gtk.GtkScaleLeaf})
    precompile(Tuple{typeof(Alexya.value), Gtk.GtkSpinButtonLeaf})
    precompile(Tuple{typeof(Alexya.value), Gtk.GtkSwitchLeaf})
    precompile(Tuple{typeof(Alexya.withangle), Base.Irrational{:π}, Int64})
    precompile(Tuple{typeof(Alexya.withangle), Float64, Float64})
end


text:
export MPProblem, MPSolution

struct MPSolution{T}
    status::Symbol
    cost::T
    elapsed::Float64
    metadata::Dict{Symbol,Any}
end

mutable struct MPProblem
    state_space::StateSpace
    bvp::SteeringBVP
    init::State
    goal::Goal
    collision_checker::CollisionChecker
    status::Symbol
    graph::NearNeighborGraph
    solution::MPSolution

    function MPProblem(state_space::StateSpace,
                       bvp::SteeringBVP,
                       init::State,
                       goal::Goal,
                       collision_checker::CollisionChecker)
        new(state_space, bvp, init, goal, collision_checker, :unsolved)
    end
end

@recipe function f(P::MPProblem; dims=(1, 2),
                                 statespace_color=:black, statespace_alpha=1,
                                 goal_color=:green, goal_alpha=1, goal_markershape=:star, goal_markersize=10,
                                 obstacle_color=:red, obstacle_alpha=1,
                                 show_tree=false, tree_color=:grey, tree_alpha=0.5, tree_markersize=2, tree_edge_waypoints=10,
                                 solution_color=:blue, solution_alpha=1, solution_markersize=2, solution_edge_waypoints=10)
    dims  --> dims
    label --> ""
    x, y = dims
    @series begin
        color --> statespace_color
        alpha --> statespace_alpha
        P.state_space
    end
    @series begin
        color       --> goal_color
        alpha       --> goal_alpha
        markershape --> goal_markershape
        markersize  --> goal_markersize
        P.goal
    end
    @series begin
        color --> obstacle_color
        alpha --> obstacle_alpha
        P.collision_checker
    end
    if show_tree && isdefined(P, :solution) && :tree in keys(P.solution.metadata)
        for (j, i) in P.solution.metadata[:tree]    # tree pairs are child => parent
            @series begin
                color          --> tree_color
                alpha          --> tree_alpha
                edge_waypoints --> tree_edge_waypoints
                plot_endpoints --> false
                SteeringEdge(P.collision_checker.state2config, P.bvp, P.graph[i], P.graph[j])
            end
        end
        @series begin
            seriestype  --> :scatter
            color       --> tree_color
            alpha       --> tree_alpha
            markersize  --> tree_markersize
            delete!(plotattributes, :dims)
            pts = [P.collision_checker.state2config(P.graph[i]) for i in keys(P.solution.metadata[:tree])]
            [p[x] for p in pts], [p[y] for p in pts]
        end
    end
    if P.status === :solved
        for (i, j) in pairwise(P.solution.metadata[:solution_nodes])
            @series begin
                color          --> solution_color
                alpha          --> solution_alpha
                markersize     --> solution_markersize
                edge_waypoints --> solution_edge_waypoints
                plot_endpoints --> true
                SteeringEdge(P.collision_checker.state2config, P.bvp, P.graph[i], P.graph[j])
            end
        end
    end
end

max_stars_repo_name: pbpf/clean

max_issues_repo_name: pbpf/clean

max_forks_repo_name: pbpf/clean


text:
"""
    struct BrewsModel <: TransistorModel
    # Arguments
    MOS::Union{MOSStructure,Nothing} Optional the mos Structure that was used to define the other parameters
    W:: Transistor width in cm
    L:: Transistor length
    Cox:: Oxide Thickness
    γ:: Bulk Factor
    ni:: Intrinsic carriers concentration in cm^-3
    Nb:: Bulk doping concentration in cm^-3
    T0:: Temperature in which parameters are taken
    VFB:: The flatband voltage
    ϵᵣ:: Relative permitivity of the substrate
    μ:: Low Field Mobility

"""

mutable struct BrewsModel <: TransistorModel
    mos::Union{MOSStructure,Nothing}
    W::Number
    L::Number
    Cox
    γ
    ni
    Nb
    T0
    VFB
    ϵᵣ
    μ
end

BrewsModel(W,L,mos::MOSStructure;μ=0.52) = BrewsModel(mos,W,L,Cox(mos),γ(mos),ni(mos),abs(C(mos)),Temperature(mos),VFB(mos),ϵᵣ(mos),μ)

function ψsV(Vgs,V,mdl::BrewsModel)
    @unpack mos,W,L,Cox,G,n_i,Nb,T0,Vfb,er,μ = mdl
    ϕt = kb*T0
    f(ψ) = Vfb-Vgs+ψ+G*sqrt(ψ/ϕt+(n_i/Nb)^2*exp((ψ-V)/ϕt))
    return fzero(f,V)
end

function Id(Vg,Vd,Vs,Vb,mdl::BrewsModel)
    @unpack mos,W,L,Cox,G,n_i,Nb,T0,VFB,er,μ = mdl
    Vgs = Vg-Vs
    ϕt = T0*kb
    ψsD = ψsV(Vgs,Vd,mdl)
    ψsS = ψsV(Vgs,Vs,mdl)
    f(ψ) = (Vgs-Vfb-ψ)-G+2*ϕt*((Vgs-Vfb-ψ)+ϵ₀*er*q*Nb)/((Vgs-Vfb-ψ)-G)
    D = hcubature(x->f(x[1]), [ψsS], [ψsD];maxevals=500,reltol=1e-12)[1]
    return W/L*Cox*μ*D
end

Id(Vg,Vd,Vs,m::BrewsModel) = Id(Vg,Vd,Vs,Vs,m::BrewsModel)
Id(Vg,Vd,m::BrewsModel) = Id(Vg,Vd,0.0,m::BrewsModel)
gm(Vg,Vd,Vs,Vb,m::BrewsModel;order=5) = central_fdm(order,1)(x->Id(x,Vd,Vs,Vb,m),Vg)
gm(Vg,Vd,Vs,m::BrewsModel;order=5) = central_fdm(order,1)(x->Id(x,Vd,Vs,m),Vg)
gm(Vg,Vd,m::BrewsModel;order=5) = central_fdm(order,1)(x->Id(x,Vd,0.0,m),Vg)
gmId(Vg,Vd,m::BrewsModel;order=5) = gm(Vg,Vd,m;order=order)/Id(Vd,Vg,m)
gds(Vg,Vd,m::BrewsModel;order=5) = central_fdm(order,1)(x->Id(Vg,x,m),Vd)
gdsId(Vg,Vd,m::BrewsModel;order=5) = gds(Vg,Vd,m;order=order)/Id(Vd,Vg,m)


text:
import SpecialFunctions: digamma, loggamma

@node Dirichlet Stochastic [ out, a ]

@average_energy Dirichlet (q_out::Dirichlet, q_a::PointMass) = -loggamma(sum(mean(q_a))) + sum(loggamma.(mean(q_a))) - sum((mean(q_a) .- 1.0) .* mean(log, q_out))


text:
module MagnaGA

using SparseArrays
using Random
using ..GAFramework
import ..GAFramework: fitness, crossover!, mutation!, selection, randcreature, genauxga, printfitness
using ..CayleyCrossover
using ..Spmap

export MagnaCreature, MagnaModel

# Represents a permutation, i.e. 1-1 mapping from one set to another
struct MagnaCreature
    f :: Vector{Int}
    edge_score :: Float64
    node_score :: Float64
    score :: Float64 # alignment score
end

fitness(x::MagnaCreature) where {T} = x.score

"""
Model to find network alignment by optimizing S3 (see MAGNA paper)
A network alignment is represented using a permutation
Faster implementation, slightly slower than the C++ code from the MAGNA++ paper
    using GAFramework, GAFramework.MagnaGA
    using LightGraphs
    using Random
    mv = 100
    me = 400
    G1 = adjacency_matrix(LightGraphs.erdos_renyi(mv,me))
    perm = randperm(mv)
    G2 = G1[invperm(perm),invperm(perm)]
    # G1.|V| <= G2.|V|
    S = zeros(mv,mv)
    alpha = 1.0
    model = MagnaModel(G1,G2,S,alpha)
    st = GAState(model, ngen=100, npop=6_000, elite_fraction=0.1,
        params=Dict(:print_fitness_iter=>1))
    ga!(st)
    println("accuracy = ", sum(st.pop[1].f .== perm)/mv)
    st.pop[1]
"""
struct MagnaModel <: GAModel
    G1   :: SparseMatrixCSC{Int,Int}
    G2   :: SparseMatrixCSC{Int,Int}
    S :: Matrix{Float64}
    alpha :: Float64
    function MagnaModel(G1::SparseMatrixCSC,G2::SparseMatrixCSC,S::Matrix,alpha::Number)
        (size(G1,1)==size(G1,2) && size(G2,1)==size(G2,1) &&
            size(S,1)==size(G1,1) && size(S,2)==size(G2,1)) || error("input sizes")
        new(G1,G2,S,alpha)
    end
end

"""
    using GAFramework, GAFramework.MagnaGA, GAFramework.PermGA
    using LightGraphs, SparseArrays
    using Random
    GAFramework.setthreads(false)
    nv = 100
    ne = 400
    G2 = adjacency_matrix(LightGraphs.erdos_renyi(nv,ne))
    perm = randperm(nv)
    mv = 75
    G1 = G2[perm[1:mv], perm[1:mv]]
    S = rand(Float64, mv, nv)/10
    for i in 1:mv
        S[i,i] = 0.95
    end
    alpha = 0.5
    model1 = MagnaModel(G1,G2,S,alpha)
    model2 = NetalignModel(G1,G2)
    aux1 = genauxga(model1)
    f = randperm(size(G2,1));
    c1 = MagnaCreature(f, model1, aux1)
    c2 = PermCreature(f, model2)
    c1.score, c2.score

    st1 = GAState(model1, ngen=10, npop=60_000, elite_fraction=0.1, rng=MersenneTwister(10));
    st2 = GAState(model2, ngen=10, npop=60_000, elite_fraction=0.1, rng=MersenneTwister(10));

    @time ga!(st1)
    @time ga!(st2)

"""

function genauxga(m::MagnaModel)
    crossover_aux = randperm(size(m.G2,1)), fill(false, size(m.G2,1))
    Spmap.map_index_aux(m.G1, m.G2), crossover_aux
end

# alpha * S_E + (1-alpha) * S_N
function MagnaCreature(h::AbstractVector, m::MagnaModel, aux)
    length(h)==size(m.G2,1) || error("length of h")
    # aux = genauxga(..) can be used to reduce allocations here
    # by using auxiliary space instead of reallocating
    ((K, hinv, hinvrowvals), _) = aux
    # Assumes that all edge weights are 1
    Spmap.plus_getindex!(K, m.G1, m.G2, h, hinv, hinvrowvals) # K = G1 + G2[h,h][1:m,1:m]

    w = nonzeros(K)
    Nc = count(x->x==2, w)
    Nn = count(x->x==1, w)

    Nc,cr = divrem(Nc,2)
    Nn,nr = divrem(Nn,2) # need this & above so it works well with sim. ann. code
    if cr!=0 || nr!=0 error("G1 and G2 need to be symmetric"); end
    edge_score = Nc/(Nc + Nn)

    node_score = 0.0
    if m.alpha != 1.0
        S = m.S
        @inbounds for i in 1:size(m.G1,1)
            node_score += S[i, h[i]]
        end
        node_score /= size(m.G1,1)
    end

    score = m.alpha*edge_score + (1.0-m.alpha) * node_score

    MagnaCreature(h, edge_score, node_score, score)
end

function randcreature(m::MagnaModel, aux, rng::AbstractRNG) where {T}
    f = randperm(rng, size(m.G2,1))
    MagnaCreature(f, m, aux)
end

function crossover!(z, x, y, st::GAState{MagnaModel}, aux, rng::AbstractRNG) where {T}
    (_, (r, visited)) = aux
    visited .= false
    cayley_crossover!(z.f, x.f, y.f, rng, r, visited)
    MagnaCreature(z.f, st.model, aux)
end

function printfitness(curgen::Int, x::MagnaCreature)
    println("curgen: $(curgen) edge_score: $(x.edge_score) node_score: $(x.node_score) score: $(x.score)")
end

end # MagnaGA


text:
struct PTrie{N}
    mask::UInt
    slots::BitSet
end

function PTrie{N}() where {N}
    slots = BitSet()
    mask = sum(1 << i for i in 0:(N - 1))
    PTrie{N}(mask, slots)
end

function Base.push!(p::PTrie, collection)
    h = zero(UInt)
    @inbounds for element in collection
        h = hash(element, h)
        push!(p.slots, h & p.mask)
    end
end

function Base.in(collection, p::PTrie)
    h = zero(UInt)
    @inbounds for element in collection
        h = hash(element, h)
        if (h & p.mask) ∉ p.slots
            return false
        end
    end
    (h & p.mask) in p.slots
end

function Base.getindex(p::PTrie, collection)
    h = zero(UInt)
    for element in collection
        h = hash(element, h)
        if (h & p.mask) ∉ p.slots
            return nothing
        end
    end
    return h
end

function has_concatenation(p::PTrie, h::UInt, suffix)
    @inbounds for element in suffix
        h = hash(element, h)
        if (h & p.mask) ∉ p.slots
            return false
        end
    end
    (h & p.mask) in p.slots
end

function has_concatenation(p::PTrie, collections::Vararg{String, N}) where {N}
    h = zero(UInt)
    for collection in collections
        @inbounds for element in collection
            h = hash(element, h)
            # if !p.slots[(h & p.mask) + 1]
            if (h & p.mask) ∉ p.slots
                return false
            end
        end
    end
    (h & p.mask) in p.slots
end


text:
only_exceptions(trace::Trace) = filter(tr->tr.value isa Exception, trace)
macro stacktrace(to_trace, expr)
    esc(:($TraceCalls.only_exceptions(@trace($to_trace, $expr))))
end

macro stacktrace(expr)
    esc(:($TraceCalls.@stacktrace () $expr))
end

################################################################################
# compare_past_trace

struct IsEqual
    a
    b
end

iseql(isd::IsEqual) = iseql(isd.a, isd.b)
iseql(tr::Trace) = iseql(tr.value)
iseql(a::Nullable, b::Nullable) = isequal(a, b)
iseql(a, b) = a == b
function show_val(io::IO, mime::MIME"text/html", isd::IsEqual)
    write(io, """""")
    if iseql(isd)
        write(io, "Same: ")
        try_show_val(io, mime, isd.a)
    else
        write(io, "before: ")
        try_show_val(io, mime, isd.a)
        write(io, " vs. now: ")
        try_show_val(io, mime, isd.b)
    end
    write(io, """""")
end
function show_val(io::IO, mime::MIME"text/plain", isd::IsEqual)
    if iseql(isd)
        with_crayon(io, Crayon(foreground=:green)) do
            write(io, "Same: ")
            try_show_val(io, mime, isd.a)
        end
    else
        with_crayon(io, Crayon(foreground=:red)) do
            with_crayon(io, Crayon(underline=true)) do
                write(io, "before")
            end
            write(io, ": ")
            try_show_val(io, mime, isd.a)
            write(io, " ")
            with_crayon(io, Crayon(underline=true)) do
                write(io, "vs. now")
            end
            write(io, ": ")
            try_show_val(io, mime, isd.b)
        end
    end
end

""" `compare_past_trace(old_trace::Trace; filter_out_equal=true))` reruns every function
call in `old_trace`, and shows in red where the new results differ from the old.  If
`filter_out_equal==true`, only show the non-equal results. Override
`TraceCalls.iseql(a, b)` to implement custom comparisons. """
function compare_past_trace(old_trace::Trace; filter_out_equal=true)
    tr2 = map(sub_tr->IsEqual(sub_tr.value, get_error_or_value(sub_tr)),
              old_trace)
    return filter_out_equal ? filter(!iseql, tr2) : tr2
end


text:
function get_density(obj::Atmosphere, arg0::AbsoluteDate, arg1::Vector3D, arg2::Frame)
    return jcall(obj, "getDensity", jdouble, (AbsoluteDate, Vector3D, Frame), arg0, arg1, arg2)
end

function get_density(obj::Atmosphere, arg0::FieldAbsoluteDate, arg1::FieldVector3D, arg2::Frame)
    return jcall(obj, "getDensity", RealFieldElement, (FieldAbsoluteDate, FieldVector3D, Frame), arg0, arg1, arg2)
end

function get_frame(obj::Atmosphere)
    return jcall(obj, "getFrame", Frame, ())
end

function get_velocity(obj::Atmosphere, arg0::AbsoluteDate, arg1::Vector3D, arg2::Frame)
    return jcall(obj, "getVelocity", Vector3D, (AbsoluteDate, Vector3D, Frame), arg0, arg1, arg2)
end

function get_velocity(obj::Atmosphere, arg0::FieldAbsoluteDate, arg1::FieldVector3D, arg2::Frame)
    return jcall(obj, "getVelocity", FieldVector3D, (FieldAbsoluteDate, FieldVector3D, Frame), arg0, arg1, arg2)
end


text:
module TestModularityStarters
using Test
using EcologicalNetworks

    A = [
      true true true false false false; true true true false false false;
      false false false true true true; false false false true true true
      ]
    B = BipartiteNetwork(A)

    @test length(unique(last(each_species_its_module(B)))) == richness(B)

    f2 = n_random_modules(2)
    n2 = f2(B)
    @test labs = length(unique(collect(values(last(n2))))) == 2

end


text:
module Sudoku
using Distributed
#precompile on master, the worker probably all do the precompilation concurrently which has to fail
include("./Utils.jl")
@everywhere include("src/Utils.jl")

function distributed_run(states, indices, nsteps)
    min_state = states[1]
    tot_steps = 0
    while min_state.energy > 0
        futures = []
        for state in states
            temp = rand()*rand(1:4)
            push!(futures, @spawn run_mc(state, indices, temp, nsteps))
            tot_steps += nsteps
        end

        states = [fetch(f) for f in futures]
        min_state = states[argmin([s.energy for s in states])]
        if tot_steps % 10000 == 0
            println("Min energy = $(min_state.energy)")
            println("Temp = $(min_state.T)")
        end

    end

    return states[argmin([s.energy for s in states])]

end

function mc_solve(puzzle::Matrix, nsteps::Int)
    indices = get_indices(puzzle)
    states = []
    println("Using $(nworkers()) workers")

    for i in 1:nworkers()
        push!(states, initialize_board(puzzle, indices))
    end
    states = distributed_run(states, indices, nsteps)

    return states

end

end #module


text:
function SeisPatchProcess(in,out,param=Dict())
	# read data from disk, split into multidimensional overlapping patches, apply
	# processes, merge patches with tapers, and write to disk. Processing of patches
	# can be done in parallel by running the code using (for example): julia -p 2 script_name.jl
	#
	#
	# Important Notice: You must make declare global variables f and f_param on every processor. You
	# can do this in your main function by typing (for example):
	# @everywhere global f_param = ["style"=>"mxmyhxhy","Niter"=> 100,"alpha"=>1,"fmax"=>80]
	# @everywhere global f = [SeisPOCS]
	#
	# f is an array of functions that have the following syntax: d2,h2 = f(d1,h1,f_param), where
	# param is a dictionary (Dict) of parameters for the function.
	#
	# note that param should contain parameters for the patching and
	# unpatching operations.
	#
	# to execute the code type:  julia -p 4 my_code.jl where 4 can be replaced with the number of
	# processors you wish to use.
	#
	#
	patch_names = SeisPatch(in,out,param)
	a = pmap(MyProcess,patch_names)
	SeisUnPatch(patch_names,out,param)
	#for ipatch = 1 : length(patch_names)
	#	SeisRemove(patch_names[ipatch])
	#end

end

function MyProcess(filename)
	d1,h1 = SeisRead(filename)
	for ifunc = 1 : length(f)
		func = f[ifunc]
		d2,h2 = func(d1,h1,f_param)
		d1 = copy(d2)
		h1 = copy(h2)
	end
	SeisWrite(filename,d1,h1)
	return(1)
end


text:
using Catlab.Present, Catlab.Theories, Catlab.CategoricalAlgebra
using CSetAutomorphisms

@present TheoryRxn(FreeSchema) begin
  (Molecule, Atom, Bond)::Ob
  inv::Hom(Bond,Bond)
  atom::Hom(Bond, Atom)
  mol::Hom(Atom, Molecule)

  (Float, Num)::AttrType
  atomic_number::Attr(Atom, Num)
  coefficient::Attr(Molecule, Float)

  compose(inv, inv) == id(Bond)
end

@acset_type RxnGeneric(TheoryRxn)
Rxn = RxnGeneric{Float64, Int}

H2 = Rxn()
add_part!(H2, :Molecule, coefficient=2.0)
add_parts!(H2, :Atom, 2, atomic_number=[1,1], mol=[1,1])
add_parts!(H2, :Bond, 2, atom=[1,2], inv=[2,1])

O2 = deepcopy(H2)
set_subpart!(O2, :coefficient, 1.0)
set_subpart!(O2, :atomic_number, [8,8])

H2O = deepcopy(H2)
set_subpart!(H2O, :coefficient, -2.0)
add_part!(H2O, :Atom, mol=1, atomic_number=8)
add_parts!(H2O, :Bond, 4, atom=[1,3,2,3], inv=[4,3,6,5])

r1, r2 = Rxn(), Rxn()
[copy_parts!(r1, x) for x in [H2, O2, H2O]]
[copy_parts!(r2, x) for x in [H2O, H2, O2]]

println(r1==r2) # false
println(is_isomorphic(r1, r2)) # true
println(canonical_hash(r1)) # 12244109900905077714
println(canonical_hash(r2)) # 12244109900905077714