text:
#
# This is a part of Manager module. This part is related to
# organisms logic and behavior.
#
# @author DeadbraiN
#
# Dependencies
#
import Config
import Helper
import Creature
import Mutator
import Client
import Event
import World
import RpcApi
import ManagerTypes
#
# Shows organism related message
# @param man Manager data type
# @param id Unique orgainsm identifier
# @param msg Organism's message
#
function msg(man::ManagerTypes.ManagerData, id::UInt, msg::String)
  if man.cfg.modeQuiet < Config.MODE_QUIET_IMPORTANT Helper.info(string("org-", id, " ", msg)) end
end
#
# Binds handlers to organism's events
# @param man Manager data type
# @param org Organism we are working with
#
function bindEvents(man::ManagerTypes.ManagerData, org::Creature.Organism)
  Event.clear(org.observer)
  Event.on(org.observer, "getenergy", (org::Creature.Organism, pos::Helper.Point, retObj::Helper.RetObj)->_onGetEnergy(man, org, pos, retObj))
  Event.on(org.observer, "grableft",  (org::Creature.Organism, amount::Int, retObj::Helper.RetObj)->_onGrabLeft(man, org, amount, retObj))
  Event.on(org.observer, "grabright", (org::Creature.Organism, amount::Int, retObj::Helper.RetObj)->_onGrabRight(man, org, amount, retObj))
  Event.on(org.observer, "grabup",    (org::Creature.Organism, amount::Int, retObj::Helper.RetObj)->_onGrabUp(man, org, amount, retObj))
  Event.on(org.observer, "grabdown",  (org::Creature.Organism, amount::Int, retObj::Helper.RetObj)->_onGrabDown(man, org, amount, retObj))
  Event.on(org.observer, "stepleft",  (org::Creature.Organism, retObj::Helper.RetObj)->retObj.ret = _onStepLeft(man, org))
  Event.on(org.observer, "stepright", (org::Creature.Organism, retObj::Helper.RetObj)->retObj.ret = _onStepRight(man, org))
  Event.on(org.observer, "stepup",    (org::Creature.Organism, retObj::Helper.RetObj)->retObj.ret = _onStepUp(man, org))
  Event.on(org.observer, "stepdown",  (org::Creature.Organism, retObj::Helper.RetObj)->retObj.ret = _onStepDown(man, org))
  Event.on(org.observer, "propleft",  (org::Creature.Organism, retObj::Helper.RetObj)->_onPropLeft(man, org, retObj))
  Event.on(org.observer, "propright", (org::Creature.Organism, retObj::Helper.RetObj)->_onPropRight(man, org, retObj))
  Event.on(org.observer, "propup",    (org::Creature.Organism, retObj::Helper.RetObj)->_onPropUp(man, org, retObj))
  Event.on(org.observer, "propdown",  (org::Creature.Organism, retObj::Helper.RetObj)->_onPropDown(man, org, retObj))
end
#
# Updates organisms existances. We have to call this function to
# update organisms life in memory world. Decreases energy and
# provides rare mutations.
# @param man Manager data type
# @param counter Counter for mutations speed
# @param needYield We have to call yield in organisms loop, if
# this flag is turned on.
#
function _updateOrganisms(man::ManagerTypes.ManagerData, counter::Int, needYield::Bool)
  local cloneAfter::Int  = man.cfg.orgClonePeriod
  local needClone ::Bool = cloneAfter === 0 ? false : counter % cloneAfter === 0
  local tasks     ::Array{ManagerTypes.OrganismTask, 1} = man.tasks
  local len       ::Int = length(tasks)
  local curLen    ::Int = len
  local task      ::ManagerTypes.OrganismTask
  local org       ::Creature.Organism
  local probIndex ::Int
  local probs     ::Array{UInt, 1}
  local cfg       ::Config.ConfigData = man.cfg
  local i         ::Int = len
  #
  # This block runs one iteration for all available organisms.
  # By one iteration i mean that every organism from a list
  # run peace of it's script - code between two produce() calls.
  #
  while i > 0
    @inbounds task = tasks[i]
    org = task.organism
    #
    # Because this loop affects porformance, we have call yield()
    # here and not in main Manager while loop.
    #
    if needYield yield(); Event.fire(man.obs, "yield", man) end
    #
    # We have to wait while all clients are ready for streaming. This
    # is because the error in serializer. See issue for details:
    # https://github.com/JuliaLang/julia/issues/16746. See Manager
    # main loop for details.
    #
    if man.cons.streamInit::Bool return counter + 1 end
    #
    # Switches to task of current organism
    #
    if org.alive
      yieldto(task.task)
      Event.fire(man.obs, "yieldto", man)
    else
      i-=1
      continue
    end
    #
    # This is how organisms die if their age is bigger then some
    # predefined config value (orgAlivePeriod)
    #
    if cfg.orgAlivePeriod > 0 && org.age >= cfg.orgAlivePeriod && ManagerTypes.orgAmount(man) > cfg.worldMinOrgs
      _killOrganism(man, i)
      i-=1
      continue
    end
    #
    # Current organism could die during running it's code, for
    # example during giving it's energy to another organism (altruism)
    #
    if org.energy < 1 && org.alive _killOrganism(man, i); i-=1; continue end
    #
    # This is how we mutate organisms during their life.
    # Mutations occures according to organisms settings.
    # If mutationPeriod or mutationPercent set to 0, it
    # means that mutations during leaving are disabled.
    # Mutation will be automatically applied if organism
    # doesn't contain any code line. This line must be
    # last in organisms loop.
    #
    if cfg.orgRainMutationPeriod > 0 && org.mutationPeriod > 0 && counter % org.mutationPeriod === 0 _mutate(man, task, org.mutationPercent, false) end
    #
    # Updates min/max values
    #
    _updateMinMax(man, org)
    #
    # Event about one organism has processed (runned)
    #
    Event.fire(man.obs, "organism", man, org)
    #
    # Here shouldn't be a code, after mutations, because current
    # task may be updated with new one.
    #
    i -= 1
  end
  curLen = ManagerTypes.orgAmount(man)
  #
  # After all organisms die, we have to create next, new population
  #
  if curLen < 1 createOrganisms(man) end
  #
  # Cloning procedure. The meaning of this is in ability to
  # produce children as fast as much energy has an organism.
  # If organism has high energy value, then it will produce
  # more copies and these copies will produce other organisms
  # and so on and so fourth...
  # TODO: may be i have to move this code outside the loop
  # TODO: optimize this array. It should be created only once
  # TODO: outside the loop.
  #
  if needClone && curLen > 0 _updateClonning(man, tasks) end
  #
  # This block decreases energy from organisms, because they
  # spend it while leaving.
  #
  if cfg.orgEnergySpendPeriod > 0 && counter % cfg.orgEnergySpendPeriod === 0
    _updateOrganismsEnergy(man)
  end
  #
  # Resets min/max values
  #
  _resetMinMax(man)
  #
  # This counter should be infinite, but not zero!
  #
  if counter === typemax(Int) counter = 1 end

  counter + 1
end
#
# Updates minimum and maximum values for organisms (like energy, codeSize,...)
# @param man Manager data type
# @param org Organism
#
function _updateMinMax(man::ManagerTypes.ManagerData, org::Creature.Organism)
  #
  # This is how we find maximum energetic organism
  #
  if org.energy > man.maxEnergy man.maxEnergy = org.energy end
end
#
# This method should be called at the end of every iteration, because
# during next iteration max/min values may be different
# @param man Manager data type
#
function _resetMinMax(man::ManagerTypes.ManagerData)
  man.maxEnergy = 0
end
#
# Updates clonning of organisms. Chooses organism for clonning according
# to energy * diversity criterias. Energy should be more valuable in this
# process, because diversity (mutations) are very simple to obtain and
# population will die, if diversity and energy will have similar affection
# on natural selection mechanism.
# @param man Manager data type
# @param org Organism
# @return {Bool} Clonning was successful or not
#
function _updateClonning(man::ManagerTypes.ManagerData, tasks::Array{ManagerTypes.OrganismTask, 1})
  local probs::Array{UInt, 1} = UInt[]
  local probIndex::Int
  local orgAmount::Int = length(tasks)
  local i::Int
  local org::Creature.Organism
  #
  # This code will be run if total amount of organisms is less then cfg.worldMaxOrgs
  #
  @inbounds for i = 1:orgAmount
    org = tasks[i].organism
    push!(probs, org.alive ? UInt(org.energy) * UInt(org.mutationsFromStart) : 0)
  end

  probIndex = Helper.getProbIndex(probs)
  @inbounds if tasks[probIndex].organism.alive
    _onClone(man, tasks[probIndex].organism)
    #
    # Checks if random selected organism may be removed and clonning
    # will be available, because we already limit the maximum (cfg.worldMaxOrgs)
    #
    if orgAmount >= man.cfg.worldMaxOrgs
      probIndex = Helper.fastRand(orgAmount)
      if tasks[probIndex].organism.alive
        if probIndex < 1 || Helper.fastRand(man.maxEnergy) < man.maxEnergy - tasks[probIndex].organism.energy return false end
        _killOrganism(man, probIndex)
      end
    end
  end

  true
end
#
# Updates energy of all organisms. Decreases their energy according
# to config (orgEnergySpendPeriod). Removes marked as "delete"
# tasks from man.tasks map.
# @param man Manager data type
#
function _updateOrganismsEnergy(man::ManagerTypes.ManagerData)
  local tasks::Array{ManagerTypes.OrganismTask, 1} = man.tasks
  local org::Creature.Organism
  local i::Int = length(tasks)
  local len::Int = i
  local minOrgs::Int = man.cfg.worldMinOrgs
  local dontKill::Bool = (i < minOrgs)
  local codeSize::Int
  local codeSizeCoef::Int = man.cfg.codeSizeCoef
  local codeMaxSize::Int = man.cfg.codeMaxSize
  local orgGarbagePeriod::Int = man.cfg.orgGarbagePeriod
  local orgCodeSize::Int

  if dontKill return false end
  #
  # We have to go through tasks in reverse way, because we may
  # remove some elements inside while loop.
  #
  while i > 0
    @inbounds if !tasks[i].organism.alive i-=1; continue end
    #
    # if the organism is marked as "removed", we have to delete it
    #
    @inbounds org = tasks[i].organism
    #
    # Energy shouldn't be less then 1
    #
    if !dontKill
      #
      # Orgabism's garbage is not affect on amount of grabbed energy
      #
      orgCodeSize = div(org.codeSize, orgGarbagePeriod)
      if orgCodeSize < 1 orgCodeSize = 1 end
      #
      # This check is used for limiting organisms code size to codeMaxSize
      # because our CPU's are slow
      #
      if org.codeSize > codeMaxSize codeSize = orgCodeSize * codeSizeCoef
      else codeSize = orgCodeSize end
      codeSize = min(org.energy, codeSize)
      Event.fire(man.obs, "grabenergy", man, codeSize)
      if !_decreaseOrganismEnergy(man, org, codeSize)
        dontKill = ManagerTypes.orgAmount(man) <= minOrgs
      end
    end

    i -= 1
  end

  Event.fire(man.obs, "updateenergy", man)

  true
end
#
# Decreases energy from organism on "amount"
# @param man Manager data type
# @param org Organism
# @param amount Amount of energy we have to decrease
#
function _decreaseOrganismEnergy(man::ManagerTypes.ManagerData, org::Creature.Organism, amount::Int)
  org.energy -= amount
  if org.energy < 1
    _killOrganism(man, org.index)
    return false
  end

  true
end
#
# Marks one organism as "frozen". It means that it will be hidden
# and all other organisms will no ability to interact with him.
# Removing from tasks pool will be provided in _updateOrganismsEnergy()
# @param man Manager data type
# @param i Index of organism's task
#
function _freezeOrganism(man::ManagerTypes.ManagerData, i::Int)
  @inbounds local id::UInt = man.tasks[i].id
  @inbounds local org::Creature.Organism = man.tasks[i].organism
  local oldColor::UInt16 = org.color

  org.color = UInt16(Dots.INDEX_EMPTY)
  Event.clear(org.observer)
  _moveOrganism(man, org.pos, org)
  org.color = oldColor
  delete!(man.positions, Manager._getPosId(man, org.pos))
  delete!(man.organisms, id)
  @inbounds Manager.stopTask(man.tasks[i].task)
  man.cons.frozen[org.id] = org
  msg(man, id, "frozen")
end
#
# Marks one organism as "removed". Deletion will be done in
# _updateOrganismsEnergy() function.
# @param man Manager data type
# @param index Index of organism's task
#
function _killOrganism(man::ManagerTypes.ManagerData, index::Int)
  local tasks::Array{ManagerTypes.OrganismTask, 1} = man.tasks
  @inbounds local org::Creature.Organism = tasks[index].organism
  local energyAfterDeath::UInt16 = UInt16(min(typemax(UInt16), org.energy))

  org.energy = 0
  org.color  = UInt16(Dots.INDEX_EMPTY)
  if !org.alive return false end
  org.alive  = false
  push!(man.killed, index)
  Event.clear(org.observer)
  _moveOrganism(man, org.pos, org)
  delete!(man.positions, Manager._getPosId(man, org.pos))
  delete!(man.organisms, org.id)
  @inbounds Manager.stopTask(man, tasks[index].task)
  msg(man, org.id, "die")
  Event.fire(man.obs, "killorganism", man, org)

  true
end
#
# Moves organism to specified position. Updates organism's
# position and set new one into the man.positions. Removes
# organism's previous position from man.positions.
# @param man Manager data type
# @param pos New position
# @param organism Organism to move
# @return {Bool}
#
function _moveOrganism(man::ManagerTypes.ManagerData, pos::Helper.Point, organism::Creature.Organism)
  local newPos::Helper.Point = Helper.Point(pos.x, pos.y)
  local idNew::Int
  local idOld::Int = Manager._getPosId(man, organism.pos)
  local freeze::Bool = false
  local cyclicMove::Bool = false
  #
  # If cyclical mode turned on, then we have to move organisms in a
  # specific cyclic way from the borders.
  #
  if man.cfg.worldCyclical
    if newPos.x < 1
      newPos.x = man.world.width
      cyclicMove = true
    elseif newPos.x > man.world.width
      newPos.x = 1
      cyclicMove = true
    elseif newPos.y < 1
      newPos.y = man.world.height
      cyclicMove = true
    elseif newPos.y > man.world.height
      newPos.y = 1
      cyclicMove = true
    end
  #
  # Organism try step outside of current instance. If near
  # instance is ready, we may teleport him there. We also
  # have to decrease energy to prevent network overload.
  # Energy decrease should be provided on destination Manager.
  # If network is ok and we may send an organism, we have to
  # kill him in current Manager/instance.
  #
  else
    if newPos.x < 1
      if !Client.isOk(man.cons.left)  || !Client.request(man.cons.left, RpcApi.RPC_ORG_STEP_LEFT, organism) Event.fire(man.obs, "request", man); return false end
      freeze = true
    elseif newPos.x > man.world.width
      if !Client.isOk(man.cons.right) || !Client.request(man.cons.right, RpcApi.RPC_ORG_STEP_RIGHT, organism) Event.fire(man.obs, "request", man); return false end
      freeze = true
    elseif newPos.y < 1
      if !Client.isOk(man.cons.up)    || !Client.request(man.cons.up, RpcApi.RPC_ORG_STEP_UP, organism) Event.fire(man.obs, "request", man); return false end
      freeze = true
    elseif newPos.y > man.world.height
      if !Client.isOk(man.cons.down)  || !Client.request(man.cons.down, RpcApi.RPC_ORG_STEP_DOWN, organism) Event.fire(man.obs, "request", man); return false end
      freeze = true
    end
    #
    # We have to freeze the organism and throw an error to interrupt
    # his current runned code
    #
    if freeze
      # TODO: possibly slow code!
      _freezeOrganism(man, organism.index)
      error("Organism is interrupted, because of freeze")
    end
  end
  #
  # Destination position, where organism wants step to is not
  # empty. Other organism or an energy block is there.
  #
  idNew = Manager._getPosId(man, newPos)
  if idOld !== idNew && !Manager._isFree(man, newPos) return false end
  #
  # newPos - new organism position
  # organism.pos - old organism position
  #
  if idOld !== idNew
    delete!(man.positions, idOld)
    man.positions[idNew] = organism
    #
    # Using this command, we optimize amount of transferred data
    # through network and remove blinks in visualizer, because we
    # transfet only new coordinates, color and direction
    #
    if cyclicMove World.moveEnergy(man.world, organism.pos, newPos, organism, true)
    else World.moveEnergy(man.world, organism.pos, newPos, organism) end
    organism.pos = newPos
  #
  # The position didn't change, so only color should be updated
  #
  else
    World.moveEnergy(man.world, newPos, newPos, organism)
  end

  true
end
#
# Mutates an organism according to his own amount of mutations.
# @param man Instance of manager data type
# @param task Task of organism
# @param mutationPercents Percent of mutations from code size
# @param onClone true if current mutations were applied on clonning
# of organism and not as a rain mutations
#
function _mutate(man::ManagerTypes.ManagerData, task::ManagerTypes.OrganismTask, mutationPercents::Float64, onClone::Bool = true)
  local mutations::Int = Mutator.mutate(man.cfg, task.organism, mutationPercents)

  if mutations > 0
    #
    # Because we have changed current organism's code, we have to
    # update it's task. Otherwise, old, removed code will still be
    # runned, before new code will be running.
    #
    Manager._updateOrgTask(man, task)
    Event.fire(man.obs, "mutations", man, task.organism, mutations, onClone)
  end
end
#
# Makes orhanism clone and apply mutations to it (child).
# Finds free point for new organism and returns these coordinates.
# If no free space, then returns false. It checks four (4) places
# around current organism's position: up, down, left and right.
# @param man Manager data type
# @param organism Parent organism
#
function _onClone(man::ManagerTypes.ManagerData, organism::Creature.Organism)
  if organism.energy < 1 return false end
  #
  # First, we have to find free point near the organism to put
  # clone in. It's possible, that all places are filled.
  #
  pos = World.getNearFreePos(man.world, organism.pos)
  if pos === false return false end
  #s
  # Creates new organism and apply mutations to him.
  #
  crTask = Manager._createOrganism(man, organism, pos)
  if crTask === false return false end
  #
  # Clonning means additional energy waste
  #
  local minimum::Bool = ManagerTypes.orgAmount(man) <= man.cfg.worldMinOrgs
  local energy::Int = minimum ? 1 : round(Int, organism.energy * organism.cloneEnergyPercent)
  local before::Int = organism.energy

  if !minimum
    _decreaseOrganismEnergy(man, organism, energy)
    _decreaseOrganismEnergy(man, crTask.organism, crTask.organism.energy - energy)
  end
  if before < (organism.energy + crTask.organism.energy)
    println("before: ", before, " org: ", organism.energy, " cr: ", crTask.organism.energy, " e: ", energy)
  end
  if energy > 0 && crTask.organism.energy > 0
    _mutate(man, crTask, crTask.organism.mutationsOnClonePercent)
  end

  Event.fire(man.obs, "clone", man, organism.id, crTask.organism.id)

  true
end
#
# Returns an energy amount in specified point in a world.
# @param org Organism
# @param pos Position to check
# @param retObj Special object for return value
#
function _onGetEnergy(man::ManagerTypes.ManagerData, org::Creature.Organism, pos::Helper.Point, retObj::Helper.RetObj)
  local id::Int = Manager._getPosId(man, pos)
  #
  # Other organism at this position
  #
  if haskey(man.positions, id)
    retObj.ret = man.positions[id].energy
  #
  # Energy block at this position
  #
  else
    retObj.ret = World.getEnergy(man.world, pos)
  end
end
#
# Grabs energy on the left side of the organism
# @param man Manager data type
# @param org Organism
# @param amount Amount of energy we want to grab
# @param retObj Special object for return value
#
function _onGrabLeft(man::ManagerTypes.ManagerData, org::Creature.Organism, amount::Int, retObj::Helper.RetObj)
  local eated::Int = _onGrab(man, org, amount, Helper.Point(org.pos.x - 1, org.pos.y), retObj)
  Event.fire(man.obs, "eatleft", man, org, amount, eated)

  eated
end
#
# Grabs energy on the right side of the organism
# @param man Manager data type
# @param org Organism
# @param amount Amount of energy we want to grab
# @param retObj Special object for return value
#
function _onGrabRight(man::ManagerTypes.ManagerData, org::Creature.Organism, amount::Int, retObj::Helper.RetObj)
  local eated::Int = _onGrab(man, org, amount, Helper.Point(org.pos.x + 1, org.pos.y), retObj)
  Event.fire(man.obs, "eatright", man, org, amount, eated)

  eated
end
#
# Grabs energy on the up side of the organism
# @param man Manager data type
# @param org Organism
# @param amount Amount of energy we want to grab
# @param retObj Special object for return value
#
function _onGrabUp(man::ManagerTypes.ManagerData, org::Creature.Organism, amount::Int, retObj::Helper.RetObj)
  local eated::Int = _onGrab(man, org, amount, Helper.Point(org.pos.x, org.pos.y - 1), retObj)
  Event.fire(man.obs, "eatup", man, org, amount, eated)

  eated
end
#
# Grabs energy on the down side of the organism
# @param man Manager data type
# @param orgId Unique organism id
# @param amount Amount of energy we want to grab
# @param retObj Special object for return value
#
function _onGrabDown(man::ManagerTypes.ManagerData, org::Creature.Organism, amount::Int, retObj::Helper.RetObj)
  local eated::Int = _onGrab(man, org, amount, Helper.Point(org.pos.x, org.pos.y + 1), retObj)
  Event.fire(man.obs, "eatdown", man, org, amount, eated)

  eated
end
#
# Handler of "stepleft" event. Checks a possibility to step left.
# New position will be set to "retObj.pos" property.
# @param man Manager data type
# @param orgId Unique organism id
#
function _onStepLeft(man::ManagerTypes.ManagerData, org::Creature.Organism)
  local stepDone::Bool = _onStep(man, org, Helper.Point(org.pos.x - 1, org.pos.y))
  Event.fire(man.obs, "stepleft", man, org, stepDone)

  stepDone
end
#
# Handler of "stepright" event. Checks a possibility to step right.
# New position will be set to "retObj.pos" property.
# @param man Manager data type
# @param orgId Unique organism id
#
function _onStepRight(man::ManagerTypes.ManagerData, org::Creature.Organism)
  local stepDone::Bool = _onStep(man, org, Helper.Point(org.pos.x + 1, org.pos.y))
  Event.fire(man.obs, "stepright", man, org, stepDone)

  stepDone
end
#
# Handler of "stepup" event. Checks a possibility to step up.
# New position will be set to "retObj.pos" property.
# @param man Manager data type
# @param orgId Unique organism id
#
function _onStepUp(man::ManagerTypes.ManagerData, org::Creature.Organism)
  local stepDone::Bool = _onStep(man, org, Helper.Point(org.pos.x, org.pos.y - 1))
  Event.fire(man.obs, "stepup", man, org, stepDone)

  stepDone
end
#
# Handler of "stepdown" event. Checks a possibility to step down.
# @param man Manager data type
# @param orgId Unique organism id
#
function _onStepDown(man::ManagerTypes.ManagerData, org::Creature.Organism)
  local stepDone::Bool = _onStep(man, org, Helper.Point(org.pos.x, org.pos.y + 1))
  Event.fire(man.obs, "stepdown", man, org, stepDone)

  stepDone
end
#
# Handler of "propleft" event. Checks if we may obtain some property of
# near organism, on the left.
# @param man Manager data type
# @param orgId Unique organism id
# @param retObj Special object for return value
#
function _onPropLeft(man::ManagerTypes.ManagerData, org::Creature.Organism, retObj::Helper.RetObj)
  _onProp(man, org, Helper.Point(org.pos.x - 1, org.pos.y), retObj)
end
#
# Handler of "propright" event. Checks if we may obtain some property of
# near organism, on the right.
# @param man Manager data type
# @param orgId Unique organism id
# @param retObj Special object for return value
#
function _onPropRight(man::ManagerTypes.ManagerData, org::Creature.Organism, retObj::Helper.RetObj)
  _onProp(man, org, Helper.Point(org.pos.x + 1, org.pos.y), retObj)
end
#
# Handler of "propup" event. Checks if we may obtain some property of
# near organism, on the above.
# @param man Manager data type
# @param orgId Unique organism id
# @param retObj Special object for return value
#
function _onPropUp(man::ManagerTypes.ManagerData, org::Creature.Organism, retObj::Helper.RetObj)
  _onProp(man, org, Helper.Point(org.pos.x, org.pos.y - 1), retObj)
end
#
# Handler of "propdown" event. Checks if we may obtain some property of
# near organism, on the below.
# @param man Manager data type
# @param orgId Unique organism id
# @param retObj Special object for return value
#
function _onPropDown(man::ManagerTypes.ManagerData, org::Creature.Organism, retObj::Helper.RetObj)
  _onProp(man, org, Helper.Point(org.pos.x, org.pos.y + 1), retObj)
end
#
# Obtains some property of organism on the specified side. If there is no
# organism near current, will return 0.
# @param man Manager data type
# @param orgId Unique organism id
# @param pos Position of nearest organism, which id we have to get
# @param retObj Special object for return value
#
function _onProp(man::ManagerTypes.ManagerData, org::Creature.Organism, pos::Helper.Point, retObj::Helper.RetObj)
  local id::Int = Manager._getPosId(man, pos)

  if haskey(man.positions, id)
    retObj.ret = getfield(man.positions[id], retObj.ret)
  else
    retObj.ret = nothing
  end

  retObj.ret
end
#
# Grabs energy on specified point. It grabs the energy and
# checks if other organism was at that position. If so, then
# it decrease an energy of this other organism.
# @param man Manager data type
# @param organism Organism, who grabs an energy
# @param amount Amount of energy he wants to grab
# @param pos Point where we should check the energy
# @param retObj Special object for return value
#
function _onGrab(man::ManagerTypes.ManagerData, organism::Creature.Organism, amount::Int, pos::Helper.Point, retObj::Helper.RetObj)
  if haskey(man.cons.frozen, organism.id) || ManagerTypes.orgAmount(man) <= man.cfg.worldMinOrgs return retObj.ret = 0 end
  local newPos::Helper.Point = Helper.Point(pos.x, pos.y)
  local nearId::Int
  local nearOrg::Creature.Organism
  #
  # In case if cyclical mode is on, organism may grab energy
  # outside the world's borders
  #
  if man.cfg.worldCyclical
    if newPos.x < 1 newPos.x = man.world.width
    elseif newPos.x > man.world.width newPos.x = 1
    elseif newPos.y < 1 newPos.y = man.world.height
    elseif newPos.y > man.world.height newPos.y = 1
    end
  end
  nearId = Manager._getPosId(man, newPos)
  #
  # If other organism at the position of the check,
  # then grab energy from him
  #
  if haskey(man.positions, nearId)
    nearOrg = man.positions[nearId]
    #
    # Current organism wants give an energy
    #
    if amount < 0
      if organism.energy <= abs(amount)
        amount = -organism.energy
        _killOrganism(man, organism.index)
        retObj.ret  = 0
      else
        retObj.ret = amount
      end
      nearOrg.energy -= amount
    elseif nearOrg.energy > amount
      nearOrg.energy -= amount
      retObj.ret = amount
    elseif nearOrg.energy <= amount
      amount = retObj.ret = nearOrg.energy
      _killOrganism(man, nearOrg.index)
    end
    Event.fire(man.obs, "eatorganism", man, amount)
  else
    #
    # Organism wants to get an energy, but no other organisms around
    #
    retObj.ret = Int(amount > 0 ? World.grabEnergy(man.world, newPos, UInt16(amount)) : 0)
    if retObj.ret > 0 Event.fire(man.obs, "eatenergy", man, retObj.ret) end
  end

  retObj.ret
end
#
# Checks if specified position ("pos") has no energy and we may
# move the organism there. If this position has an energy, then
# the same position will be set to "retObj.pos".
# @param man Manager data type
# @param organism Organism hwo grabs
# @param pos Point where we should check the energy
#
function _onStep(man::ManagerTypes.ManagerData, organism::Creature.Organism, pos::Helper.Point)
  local stepDone::Bool = false

  if organism.alive && !haskey(man.cons.frozen, organism.id)
    stepDone = _moveOrganism(man, pos, organism)
    #
    # We have to explain this a little bit. This yieldto() switches current
    # context to man.task. It means that not all the code of current organism
    # will be run. It also solves a problem of parallel organisms runningand
    # smooth organisms moving in a visualizer.
    #
    yieldto(man.task)
  end

  stepDone
end
#
# Creates new organism and binds event handlers to him. It also
# finds free point in a world, where organism will start living.
# If add === true, we have to add it to organisms pool.
# @param man Manager data type
# @param org Organism we have to copy. Optional.
# @param pos Optional. Position of organism.
# @param add We need just add existing organism to the world
# @return {ManagerTypes.OrganismTask}
# TODO: set type for arguments
#
function _createOrganism(man::ManagerTypes.ManagerData, organism = nothing, pos::Helper.Point = Helper.Point(0,0), add::Bool = false)
  pos = organism !== nothing && Helper.empty(pos) ? World.getNearFreePos(man.world, organism.pos) : (Helper.empty(pos) ? World.getFreePos(man.world) : pos)
  if pos === false return false end
  #
  # No place for new organisms yet
  #
  if length(man.killed) < 1 return false end
  local index::Int = last(man.killed)
  local id::UInt = man.organismId
  local org::Creature.Organism = organism === nothing ? Creature.create(man.cfg, index, id, pos) : add ? organism : Creature.create(organism, man.cfg, index, id, pos)
  local oTask::ManagerTypes.OrganismTask = ManagerTypes.OrganismTask(id, man.task, org)
  Manager._updateOrgTask(man, oTask)

  org.pos = pos
  #
  # Because of deepcopy(), we have to remove copied handlers
  #
  bindEvents(man, org)
  # TODO: clonning is under question now...
  #Event.on(org.observer, "clone",     _onClone    )
  #
  # Shows organism
  #
  _moveOrganism(man, pos, org)
  #
  # Adds organism to organisms pool
  #
  man.organismId += 1
  man.totalOrganisms += 1
  man.organisms[id] = org
  man.positions[_getPosId(man, org.pos)] = org
  man.tasks[index] = oTask
  pop!(man.killed)
  msg(man, id, "born")
  Event.fire(man.obs, "bornorganism", man, org)

  oTask
end

max_stars_repo_name: tmptrash/jevo

max_issues_repo_name: tmptrash/jevo

max_forks_repo_name: tmptrash/jevo


text:
using Documenter, MyPackage

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

makedocs(;
    modules=[MyPackage],
    format=Documenter.HTML(),
    pages=[
        "Home" => "index.md",
    ],
    repo="https://github.com/zekeriyasari/MyPackage.jl.git",
    sitename="MyPackage.jl",
    authors="Zekeriya SARI",
)

deploydocs(;
    repo="github.com/zekeriyasari/MyPackage.jl.git",
    devbranch = "master",
    devurl = "dev",
    versions = ["stable" => "v^", "v#.#", "v#.#.#"]
)

ext: jl


text:
function inicia_com(palavra::AbstractString, inicio::Array{String})::Bool
	for i in inicio
		if startswith(palavra, i)
			return true
		end
	end
	return false
end

function termina_com(palavra::AbstractString, fim::Array{String})::Bool
	for i in fim
		if endswith(palavra, i)
			return true
		end
	end
	return false
end

## Function used to sort by length desc
#function sort_by_length(lista::Array{String})
#	return reverse(unique(sort(sort(lista), by=length)))
#end

const LISTA_SUFIXOS_SUBSTANTIVOS = [ # sorted by length desc
	"ência", "ância", "ático", "zinho", "mento", "douro", "cídio", "ório",
	"ício", "ície", "ério", "âneo", "ázio", "ário", "áceo", "ácea", "usco",
	"ugem", "tude", "orra", "onho", "oide", "ista", "ismo", "isco", "inho",
	"esco", "eria", "ença", "ento", "engo", "eiro", "eira", "dade", "culo",
	"cula", "cida", "aréu", "arra", "aria", "ardo", "ança", "aico", "agem",
	"acho", "ção", "vel", "ura", "ume", "ulo", "ula", "ude", "tor", "sor", "ote",
	"ose", "ola", "nte", "iço", "ivo", "ite", "ina", "ico", "ice", "eza", "eto",
	"eta", "eno", "ela", "ejo", "edo", "dão", "dor", "aço", "aça", "ato", "ado",
	"ada", "ão", "ol", "io", "im", "il", "ia", "ez", "al"
]

const LISTA_SUFIXOS_ADJETIVOS = [ # sorted by length desc
	"íssimo", "érrimo", "ático", "zinho", "douro", "cídio", "ório", "ício",
	"âneo", "ário", "áceo", "ácea", "usco", "ugem", "onho", "oide", "ista",
	"isco", "inho", "esco", "ento", "ense", "engo", "eiro", "eira", "culo",
	"cula", "cida", "ardo", "ando", "aico", "acho", "íno", "vel", "ulo",
	"ula", "udo", "tor", "sor", "ote", "ose", "ola", "nte", "iço", "ivo",
	"ite", "ino", "ina", "imo", "ico", "eto", "eta", "eso", "esa", "eno",
	"ela", "ejo", "dor", "ato", "ano", "ado", "ês", "ão", "ol", "im", "il",
	"ia", "eu", "eo", "ar", "al"
]

const LISTA_SUFIXOS_VERBOS = [ # sorted by length desc
	"iscar", "inhar", "ilhar", "ficar", "entar", "izar", "itar",
	"icar", "ejar", "ecer", "açar", "ear", "ir", "er", "ar"
]

const LISTA_SUFIXOS_VERBOS_CONJUGADOS = [ # sorted by length desc
	# TODO
]

const LISTA_ADVERBIOS = [
	"abaixo", "acaso", "acima", "adiante", "agora", "aí",
	"ainda", "além", "ali", "amanhã", "anteontem", "antes",
	"aquém", "aqui", "assaz", "assim", "atrás", "através",
	"bastante", "bem", "breve", "cá", "cedo", "certamente",
	"como", "debalde", "defronte", "demais", "dentro", "depois",
	"depressa", "detrás", "devagar", "efetivamente", "então",
	"fora", "hoje", "já", "jamais", "junto", "lá", "logo",
	"longe", "mais", "mal", "melhor", "menos", "muito", "não",
	"nunca", "onde", "ontem", "outrora", "perto", "pior",
	"porventura", "possivelmente", "pouco", "provavelmente",
	"quando", "quanto", "quão", "quase", "quiçá", "realmente",
	"sempre", "sim", "talvez", "tampouco", "tanto", "tão", "tarde"
]

const LISTA_PREPOSICOES = [
	"a", "ante", "após", "até", "com", "contra", "de", "desde", "em",
	"entre","para", "per", "perante", "por", "sem", "sob", "sobre", "trás"
]

const LISTA_ARTIGOS = [
	"a", "as", "o", "os", "um", "uns", "uma", "umas"
]

const LISTA_ARTIGOS_CONTRAIDOS = [
	"à", "às", "da", "das",
	"na", "nas", "pela", "pelas",
	"ao", "aos", "do", "dos",
	"no", "nos", "pelo", "pelos",
	"dum", "duns", "duma", "dumas",
	"num", "nuns", "numa", "numas",
	"pra", "pras", "pro", "pros"
]

const LISTA_NUMERAIS = [
	"zero", "um", "uma", "dois", "duas", "três", "quatro", "cinco", "seis",
	"sete", "oito", "nove", "dez", "onze", "doze", "treze", "quatorze",
	"quinze", "dezesseis", "dezessete", "dezoiteo", "dezenove", "vinte",
	"trinta", "quarenta", "cinquenta", "sessenta", "setenta", "oitenta",
	"noventa", "cem", "duzentos", "duzentas", "trezentos", "trezentas",
	"quatrocentos", "quatrocentas", "quinhentos", "quinhentas",
	"seiscentos", "seiscentas", "setecentos", "setecentas", "oitocentos",
	"oitocentas", "novecentos", "novecentas", "mil", "milhão", "bilhão",
	"primeiro", "primeira", "primeiros", "primeiras", "segundo", "segunda",
	"segundos", "segundas", "terceiro", "terceira", "terceiros", "terceiras",
	"quarto", "quarta", "quartos", "quartas", "quinto", "quinta", "quntos",
	"quintas", "sexto", "sexta", "sextos", "sextas", "sétimo", "sétima",
	"sétimos", "sétimas", "oitavo", "oitava", "oitavos", "oitavas", "nono",
	"nona", "nonos", "nonas", "décimo", "décima", "décimos", "décimas",
	"undécimo", "undécima", "undécimos", "undécimas", "duodécimo",
	"doudécima", "duodécimos", "duodécimas", "vigésimo", "vigésima",
	"vigésimos", "vigésimas", "trigésimo", "trigésima", "trigésimos",
	"trigésimas", "quadragésimo", "quadragésima", "quadragésimos",
	"quadragésimas", "quinquagésimo", "quinquagésima", "quinquagésimos",
	"quinquagésimas", "sexagésimo", "sexagésima", "sexagésimos", "sexagésimas",
	"septuagésimo", "septuagésima", "septuagésimos", "septuagésimas",
	"octogésimo", "octogésima", "octogésimos", "octogésimas", "nonagésimo",
	"nonagésima", "nonagésimos", "nonagésimas", "centésimo", "centésima",
	"centésimos", "centésimas", "duocentésimo", "duocentésima", "duocentésimos",
	"duocentésimas", "trecentésimo", "trecentésima", "trecentésimos",
	"trecentésimas", "tricentésimo", "tricentésima", "tricentésimos",
	"tricentésimas", "quadringentésimo", "quadringentésima", "quadringentésimos",
	"quadringentésimas", "quingentésimo", "quingentésima", "quingentésimos",
	"quingentésimas", "seiscentésimo", "seiscentésima", "seiscentésimos",
	"seiscentésimas", "sexcentésimo", "sexcentésima", "sexcentésimos",
	"sexcentésimas", "septingentésimo", "septingentésima", "septingentésimos",
	"septingentésimas", "octingentésimo", "octingentésima", "octingentésimos",
	"octingentésimas", "nongentésimo", "nongentésima", "nongentésimos",
	"nongentésimas", "noningentésimo", "noningentésima", "noningentésimos",
	"noningentésimas", "milésimo", "milésima", "milésimos", "milésimas",
	"milionésimo", "milionésima", "milionésimos", "milionésimas", "bilionésimo",
	"bilionésima", "bilionésimos", "bilionésimas", "duplo", "dupla", "duplos",
	"duplas", "dobro", "dobra", "dobros", "dobras", "dúplice", "dúplices", "triplo",
	"tripla", "triplos", "triplas", "tríplice", "tríplices", "quádruplo", "quádrupla",
	"quádruplos", "quádruplas", "quíntuplo", "quíntupla", "quíntuplos", "quíntuplas",
	"sêxtuplo", "sêxtupla", "sêxtuplos", "sêxtuplas", "séptuplo", "séptupla",
	"séptuplos", "séptuplas", "octuplo", "octupla", "octuplos", "octuplas", "nônuplo",
	"nônupla", "nônuplos", "nônuplas", "décuplo", "décupla", "décuplos", "décuplas",
	"undécuplo", "undécupla", "undécuplos", "undécuplas", "duodécuplo", "doudécupla",
	"duodécuplos", "doudécuplas", "cêntuplo", "cêntupla", "cêntuplos", "cêntuplas",
	"meio", "meia", "meios", "meias", "metade", "metades", "terço", "terça", "terços",
	"terpas", "quarto", "quarta", "quartos", "quartas", "quinto", "quinta", "quintos",
	"quintas", "sexto", "sexta", "sextos", "sextas", "sétimo", "sétima", "sétimos",
	"sétimas", "oitavo", "oitava", "oitavos", "oitavas", "nono", "nona", "nonos",
	"nonas", "décimo", "décima", "décimos", "décimas", "undécimo", "undécima",
	"undécimos", "undécimas", "centésimo", "centésima", "centésimos", "centésimas",
	"milésimo", "milésima", "milésimos", "milésimas", "milionésimo", "milionésima",
	"milionésimos", "milionésimas", "bilionésimo", "bilionésima", "bilionésimos",
	"bilionésimas", "par", "novena", "dezena", "década", "dúzia", "centena", "cento",
	"lustro", "milhar", "milheiro", "I", "II", "III", "IV", "V", "VI", "VII", "VIII",
	"IX", "X", "XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX",
	"XXI", "XXII", "XXIII", "XXIV", "XXV", "XXVI", "XXVII", "XXVIII", "XXIX", "XXX",
	"XXXI", "XXXII", "XXXIII", "XXXIV", "XXXV", "XXXVI", "XXXVII", "XXXVIII", "XXXIX",
	"XL", "XLI", "XLII", "XLIII", "XLIV", "XLV", "XLVI", "XLVII", "XLVIII", "XLIX", "L"
]

const LISTA_LOCUCOES_ADVERBIAIS = [
	"com certeza", "por certo", "sem dúvida", "de muito", "de pouco",
	"de todo", "à direita", "à esquerda", "à distância", "ao lado",
	"de dentro", "de cima", "de longe", "de perto", "em cima",
	"para dentro", "para onde", "por ali", "por aqui", "por dentro",
	"por fora", "por onde", "por perto", "à toa", "à vontade",
	"ao contrário", "ao léu", "às avessas", "às claras", "às direitas",
	"às pressas", "com gosto", "com amor", "de cor", "de regra",
	"em geral", "em silêncio", "em vão", "por acaso", "à noite", "à tarde",
	"à tardinha", "de dia", "de manhã", "de noite", "em breve", "pela manhã"
]

function eh_substantivo(palavra::AbstractString)::Bool
	return termina_com(palavra, LISTA_SUFIXOS_SUBSTANTIVOS)
end

function eh_adjetivo(palavra::AbstractString)::Bool
	return termina_com(palavra, LISTA_SUFIXOS_ADJETIVOS)
end

function eh_verbo(palavra::AbstractString)::Bool
	return termina_com(palavra, LISTA_SUFIXOS_VERBO) || termina_com(palavra, LISTA_SUFIXOS_VERBOS_CONJUGADOS)
end

function eh_adverbio(palavra::AbstractString)::Bool
	return in(palavra, LISTA_ADVERBIOS) || termina_com(palavra, "mente")
end

function eh_preposicao(palavra::AbstractString)::Bool
	return in(palavra, LISTA_PREPOSICOES)
end

function eh_artigo(palavra::AbstractString)::Bool
	return in(palavra, LISTA_ARTIGOS)
end

function eh_artigo_contraido(palavra::AbstractString)::Bool
	return in(palavra, LISTA_ARTIGOS_CONTRAIDOS)
end

function eh_numeral(palavra::AbstractString)::Bool
	return in(palavra, LISTA_NUMERAIS)
end

function eh_nome(palavra::AbstractString)::Bool
	return eh_substantivo(palavra) || eh_adjetivo(palavra)
end

function eh_locucao_adverbial(frase::Array{String})::Bool
	return in(palavra, split(LISTA_LOCUCOES_ADVERBIAIS)) || (eh_preposicao(frase[1]) && eh_adverbio(frase[2]))
end

function eh_sintagma_nominal(frase::Array{String})::Bool
	return false # TODO
end

function eh_sintagma_verbal(frase::Array{String})::Bool
	return false # TODO
end

function eh_sintagma_preposicionado(frase::Array{String})::Bool
	return false # TODO
end

max_stars_repo_name: fabiolimace/lincom

max_issues_repo_name: fabiolimace/lincom

max_forks_repo_name: fabiolimace/lincom


text:
"""
    $SIGNATURES

Determine the variable ordering used to construct both the Bayes Net and Bayes/Junction/Elimination tree.

Notes
- Heuristic method -- equivalent to QR or Cholesky.
- Are using Blas `QR` function to extract variable ordering.
- **NOT USING SUITE SPARSE** -- which would requires commercial license.
- For now `A::Array{<:Number,2}` as a dense matrix.
- Columns of `A` are system variables, rows are factors (without differentiating between partial or full factor).
- default is to use `solvable=1` and ignore factors and variables that might be used for dead reckoning or similar.

Future
- TODO: `A` should be sparse data structure (when we exceed 10'000 var dims)
- TODO: Incidence matrix is rectagular and adjacency is the square.
"""
function getEliminationOrder( dfg::G;
                              ordering::Symbol=:qr,
                              solvable::Int=1,
                              constraints::Vector{Symbol}=Symbol[]) where G <: AbstractDFG
  #
  @assert 0 == length(constraints) || ordering == :ccolamd "Must use ordering=:ccolamd when trying to use constraints"
  # Get the sparse adjacency matrix, variable, and factor labels
  adjMat, permuteds, permutedsf = DFG.getBiadjacencyMatrix(dfg, solvable=solvable)
  # adjMat, permuteds, permutedsf = DFG.getAdjacencyMatrixSparse(dfg, solvable=solvable)

  # Create dense adjacency matrix

  p = Int[]
  if ordering==:chol
    # hack for dense matrix....
    A = adjMat
    p = cholesky(Matrix(A'A),Val(true)).piv
    @warn "check that cholesky ordering is not reversed -- basically how much fill in (separator size) are you seeing???  Long skinny chains in tree is bad."
  elseif ordering==:qr
    # hack for dense matrix....
    A = Array(adjMat)
    # this is the default
    q,r,p = qr(A, Val(true))
    p .= p |> reverse
  elseif ordering==:ccolamd
    cons = zeros(SuiteSparse_long, length(adjMat.colptr) - 1)
    cons[findall(x->x in constraints, permuteds)] .= 1
    p = Ccolamd.ccolamd(adjMat, cons)
    @warn "Ccolamd is experimental in IIF at this point in time."
  else
    @error("getEliminationOrder -- cannot do the requested ordering $(ordering)")
  end

  # Return the variable ordering that we should use for the Bayes map
  # reverse order checked in #475 and #499
  return permuteds[p]
end

# lets create all the vertices first and then deal with the elimination variables thereafter
function addBayesNetVerts!( dfg::AbstractDFG,
                            elimOrder::Array{Symbol,1} )
  #
  for pId in elimOrder
    vert = DFG.getVariable(dfg, pId)
    if getSolverData(vert).BayesNetVertID == nothing || getSolverData(vert).BayesNetVertID == :_null # Special serialization case of nothing
      @debug "[AddBayesNetVerts] Assigning $pId.data.BayesNetVertID = $pId"
      getSolverData(vert).BayesNetVertID = pId
    else
      @warn "addBayesNetVerts -- Something is wrong, variable '$pId' should not have an existing Bayes net reference to '$(getSolverData(vert).BayesNetVertID)'"
    end
  end
end

function addConditional!( dfg::AbstractDFG,
                          vertId::Symbol,
                          Si::Vector{Symbol} )
  #
  bnv = DFG.getVariable(dfg, vertId)
  bnvd = getSolverData(bnv)
  bnvd.separator = Si
  for s in Si
    push!(bnvd.BayesNetOutVertIDs, s)
  end
  return nothing
end

function addChainRuleMarginal!( dfg::AbstractDFG,
                                Si::Vector{Symbol} )
  #

  lbls = String[]
  genmarg = GenericMarginal()
  Xi = map(v -> DFG.getVariable(dfg, v), Si)
  # @info "adding marginal to"
  # for x in Xi
  #   @info "x.index=",x.index
  # end
  addFactor!( dfg, Xi, genmarg, graphinit=false, suppressChecks=true )
  nothing
end

function rmVarFromMarg( dfg::AbstractDFG,
                        fromvert::DFGVariable,
                        gm::Vector{DFGFactor}  )
  #

  @debug " - Removing $(fromvert.label)"
  for m in gm
    @debug "Looking at $(m.label)"
    for n in DFG.getNeighbors(dfg, m) #x1, x2
      if n == fromvert.label # n.label ==? x1
        @debug "   - Breaking link $(m.label)->$(fromvert.label)..."
        @debug "     - Original links: $(DFG.ls(dfg, m))"
        remvars = setdiff(DFG.ls(dfg, m), [fromvert.label])
        @debug "     - New links: $remvars"

        DFG.deleteFactor!(dfg, m) # Remove it
        if length(remvars) > 0
          @debug "$(m.label) still has links to other variables, readding it back..."
          addFactor!(dfg, remvars, _getCCW(m).usrfnc!, graphinit=false, suppressChecks=true )
        else
          @debug "$(m.label) doesn't have any other links, not adding it back..."
        end
      end
    end
    # Added back in chain rule.
    if DFG.exists(dfg, m) && length(DFG.getNeighbors(dfg, m)) <= 1
      @warn "removing vertex id=$(m.label)"
      DFG.deleteFactor!(dfg, m)
    end
  end
  return nothing
end

function buildBayesNet!(dfg::AbstractDFG,
                        elimorder::Vector{Symbol};
                        solvable::Int=1 )
  #
  # addBayesNetVerts!(dfg, elimorder)
  for v in elimorder
    @debug """
                Eliminating $(v)
                ===============
          """
    # which variable are we eliminating

    # all factors adjacent to this variable
    fi = Symbol[]
    Si = Symbol[]
    gm = DFGFactor[]

    vert = DFG.getVariable(dfg, v)
    for fctId in DFG.getNeighbors(dfg, vert, solvable=solvable)
      fct = DFG.getFactor(dfg, fctId)
      if (getSolverData(fct).eliminated != true)
        push!(fi, fctId)
        for sepNode in DFG.getNeighbors(dfg, fct, solvable=solvable)
          # TODO -- validate !(sepNode.index in Si) vs. older !(sepNode in Si)
          if sepNode != v && !(sepNode in Si) # Symbol comparison!
            push!(Si,sepNode)
          end
        end
        getSolverData(fct).eliminated = true
      end

      if typeof(_getCCW(fct)) == CommonConvWrapper{GenericMarginal}
        push!(gm, fct)
      end
    end

    if v != elimorder[end]
      addConditional!(dfg, v, Si)
      # not yet inserting the new prior p(Si) back into the factor graph
    end

    # mark variable
    getSolverData(vert).eliminated = true

    # TODO -- remove links from current vertex to any marginals
    rmVarFromMarg(dfg, vert, gm)

    #add marginal on remaining variables... ? f(xyz) = f(x | yz) f(yz)
    # new function between all Si (round the outside, right the outside)
    length(Si) > 0 && addChainRuleMarginal!(dfg, Si)

  end
  return nothing
end


text:
function get_tag_info(tag::GitHub.Tag)
    str = sprint() do io
        Downloads.download(tag.object["url"], io)
    end
    dict = JSON.parse(str)
    parts = splitpath(tag.url.path) # why is this not straight-forward?
    repo = GitHub.Repo(parts[3] * "/" * parts[4])
    return (
        commit = dict["object"]["sha"],
        name = dict["tag"],
        repo = repo,
        message = dict["message"],
    )
end

function commits_between(tag1, tag2, auth; repo="JuliaPlots/Makie.jl")
    t1 = GitHub.tag(repo, "v0.16.5")
    t2 = GitHub.tag(repo, "v0.15.3")
    t1info = get_tag_info(t1)
    t2info = get_tag_info(t2)
    params = Dict("per_page" => 100)
    commits, _ = GitHub.commits(repo; auth=auth, params)

    idx1 = findfirst(x-> x.sha == t1info.commit, commits)
    idx2 = findfirst(x-> x.sha == t2info.commit, commits)

    return commits[min(idx1, idx2):max(idx1, idx2)]
end

function JSServe.jsrender(owner::GitHub.Owner)
    name = DOM.span(string(owner.login), style="margin: 2px; color: 'gray")
    img = DOM.img(src=owner.avatar_url, style="border-radius: 50%", width=22)
    img_name = DOM.div(img, name; style="display: flex; align-items: center")
    return DOM.span(
        DOM.a(img_name, href=owner.html_url; style="color: gray; text-decoration: none");
        style="padding: 2px")
end

max_stars_repo_name: MakieOrg/Blog

max_issues_repo_name: MakieOrg/Blog

max_forks_repo_name: MakieOrg/Blog


text:
# Example of Bayesian estimation
# sampling from exponential(theta) distribution
# lognormal prior

# Shows how likelihood, joint, marginal likelihood,
# and posterior are formed, and how posterior can be
# integrated to get posterior mean

# explore different sample sizes, different true thetas
using Distributions, Plots

function main()
    n = 50   # sample size
    theta = 3 # true theta
    y = rand(Exponential(theta), n) # sample from exponential(theta)
    # make plots
    thetas = range(0.01,stop=10,length=1000)
    delta = thetas[2]-thetas[1]
    p, priormean = prior(thetas)
    post, postmean = posterior(y, thetas)
    plot(thetas, [p post], label = ["prior" "posterior"])
    plot!([priormean, priormean], [0.0, 1.0], label = "prior mean")
    plot!([postmean, postmean], [0.0, 1.0], label = "posterior mean")

end

# the prior is lognormal(1,1)
function prior(theta)
    d = LogNormal(1.0,1.0)
    p = pdf.(Ref(d), theta)
    pmean = exp(1.5) # mean of lognormal is exp(mu+sig/2)
    return p, pmean
end

# the likelihood function
function likelihood(y, theta)
    dens = zeros(size(theta))
    for i = 1:size(theta,1)
        d = Exponential(theta[i])
        dens[i] = prod(pdf.(Ref(d), y))
    end
    return dens
end

# joint is prior X likelihood
function joint(y, theta)
    l = likelihood(y, theta)
    p, junk = prior(theta)
    dens = l.*p
end

# compute marginal likelihood of Y by integrating out theta (crude, only illustrative)
function marginal(y)
    dens = 0.0
    theta = 0.0
    delta = 0.01
    # evaluate joint over grid
    for r = 1:1000
        theta += delta
        dens += joint(y, theta)
    end
    # marginalize by integrating the joint (sum up height X width)
    dens = dens*delta
end

# the posterior, by Bayes' Law
function posterior(y, theta)
    m = marginal(y)
    j = joint(y, theta)
    dens = j ./ m
    thetas = range(0.01,stop=10,length=1000)
    pmean = sum(dens.*thetas.*0.01)
    return dens, pmean
end

main()

max_stars_repo_name: nilshg/Econometrics

max_issues_repo_name: nilshg/Econometrics

max_forks_repo_name: nilshg/Econometrics


text:
fast_scalar_indexing(::Type{<:CUDA.CuArray}) = false
@inline allowed_getindex(x::CUDA.CuArray, i...) = CUDA.@allowscalar(x[i...])
@inline allowed_setindex!(x::CUDA.CuArray, v, i...) = (CUDA.@allowscalar(x[i...] = v))

function Base.setindex(x::CUDA.CuArray, v, i::Int)
    _x = copy(x)
    allowed_setindex!(_x, v, i)
    return _x
end

function restructure(x::CUDA.CuArray, y)
    return reshape(Adapt.adapt(parameterless_type(x), y), Base.size(x)...)
end

device(::Type{<:CUDA.CuArray}) = GPU()


text:
using Matroschka
using Test

@testset "Matroschka.jl" begin
    # Write your own tests here.
end


text:
module HLPeriodicOrbits_VIII_IX

    import JLD2: load

    using RadiiPolynomial
include("proof.jl")
    export prove_periodic_orbit

    import OrdinaryDiffEq: ODEProblem, solve, Tsit5
include("stability.jl")
    export approximate_Floquet_multipliers

end


text:
using Libxc
include("../xc/xc_evaluate.jl")

"""
Exchange-correlation term, defined by a list of functionals and usually evaluated through libxc.
"""
struct Xc
    functionals::Vector{Symbol}  # Symbols of the functionals (Libxc.jl / libxc convention)
    scaling_factor::Real         # Scales by an arbitrary factor (useful for exploration)

    # Density cutoff for XC computation: Below this value a gridpoint counts as zero
    # `nothing` implies that libxc defaults are used (for each functional a different
    # small positive value like 1e-24)
    density_threshold::Union{Nothing,Float64}
end
Xc(symbols::Symbol...; kwargs...) = Xc([symbols...]; kwargs...)
function Xc(symbols::Vector; scaling_factor=1, density_threshold=nothing)
    Xc(convert.(Symbol, symbols), scaling_factor, density_threshold)
end
function Base.show(io::IO, xc::Xc)
    fac = isone(xc.scaling_factor) ? "" : ", scaling_factor=$scaling_factor"
    fun = length(xc.functionals) == 1 ? ":$(xc.functionals[1])" : "$(xc.functionals)"
    print(io, "Xc($fun$fac)")
end

function (xc::Xc)(basis::PlaneWaveBasis{T}) where {T}
    isempty(xc.functionals) && return TermNoop()
    functionals = Functional.(xc.functionals; n_spin=basis.model.n_spin_components)
    if !isnothing(xc.density_threshold)
        for func in functionals
            func.density_threshold = xc.density_threshold
        end
    end
    TermXc(functionals, T(xc.scaling_factor))
end

struct TermXc <: TermNonlinear
    functionals::Vector{Functional}
    scaling_factor::Real
end

@views @timing "ene_ops: xc" function ene_ops(term::TermXc, basis::PlaneWaveBasis{T},
                                              ψ, occ; ρ, kwargs...) where {T}
    @assert !isempty(term.functionals)

    model  = basis.model
    n_spin = model.n_spin_components
    @assert all(xc.family in (:lda, :gga) for xc in term.functionals)
    @assert all(xc.n_spin == n_spin for xc in term.functionals)

    # Take derivatives of the density if needed.
    max_ρ_derivs = maximum(max_required_derivative, term.functionals)
    density = LibxcDensity(basis, max_ρ_derivs, ρ)

    potential = zero(ρ)
    terms = evaluate(term.functionals, density)

    # Energy contribution (zk == energy per unit particle)
    E = sum(terms.zk .* ρ) * basis.dvol

    # Map from the tuple of spin indices for the contracted density gradient
    # (s, t) to the index convention used in libxc (i.e. packed symmetry-adapted
    # storage), see details on "Spin-polarised calculations" below.
    tσ = libxc_spinindex_σ

    # Potential contributions Vρ -2 ∇⋅(Vσ ∇ρ)
    @views for s in 1:n_spin
        potential[:, :, :, s] .+= terms.vrho[s, :, :, :]

        if haskey(terms, :vsigma)  # Need gradient correction
            # TODO Drop do-block syntax here?
            potential[:, :, :, s] .+= -2divergence_real(density.basis) do α
                # Extra factor (1/2) for s != t is needed because libxc only keeps σ_{αβ}
                # in the energy expression. See comment block below on spin-polarised XC.
                sum((s == t ? one(T) : one(T)/2)
                    .* terms.vsigma[tσ(s, t), :, :, :] .* density.∇ρ_real[t, :, :, :, α]
                    for t in 1:n_spin)
            end
        end
    end

    if term.scaling_factor != 1
        E *= term.scaling_factor
        potential .*= term.scaling_factor
    end
    ops = [RealSpaceMultiplication(basis, kpt, potential[:, :, :, kpt.spin])
           for kpt in basis.kpoints]
    (E=E, ops=ops)
end

#=  GGA energy and potential

The total energy is
Etot = ∫ ρ E(ρ,σ), where σ = |∇ρ|^2 and E(ρ,σ) is the energy per unit particle.
libxc provides the scalars
    Vρ = ∂(ρ E)/∂ρ
    Vσ = ∂(ρ E)/∂σ

Consider a variation δϕi of an orbital (considered real for
simplicity), and let δEtot be the corresponding variation of the
energy. Then the potential Vxc is defined by
    δEtot = 2 ∫ Vxc ϕi δϕi

    δρ = 2 ϕi δϕi
    δσ = 2 ∇ρ ⋅ ∇δρ = 4 ∇ρ ⋅ ∇(ϕi δϕi)
    δEtot = ∫ Vρ δρ + Vσ δσ
          = 2 ∫ Vρ ϕi δϕi + 4 ∫ Vσ ∇ρ ⋅ ∇(ϕi δϕi)
          = 2 ∫ Vρ ϕi δϕi - 4 ∫ div(Vσ ∇ρ) ϕi δϕi
where we performed an integration by parts in the last equation
(boundary terms drop by periodicity). Therefore,
    Vxc = Vρ - 2 div(Vσ ∇ρ)
See eg Richard Martin, Electronic stucture, p. 158
=#

#=  Spin-polarised calculations

These expressions can be generalised for spin-polarised calculations.
In this case for example the energy per unit particle becomes
E(ρ_α, ρ_β, σ_αα, σ_αβ, σ_βα, σ_ββ), where σ_ij = ∇ρ_i ⋅ ∇ρ_j
and the XC potential is analogously
    Vxc_s = Vρ_s - 2 ∑_t div(Vσ_{st} ∇ρ_t)
where s, t ∈ {α, β} are the spin components and we understand
    Vρ_s     = ∂(ρ E)/∂(ρ_s)
    Vσ_{s,t} = ∂(ρ E)/∂(σ_{s,t})

Now, in contrast to this libxc explicitly uses the symmetry σ_αβ = σ_βα and sets σ
to be a vector of the three independent components only
    σ = [σ_αα, σ_x, σ_ββ]  where     σ_x = (σ_αβ + σ_βα)/2
Accordingly Vσ has the components
    [∂(ρ E)/∂σ_αα, ∂(ρ E)/∂σ_x, ∂(ρ E)/∂σ_ββ]
where in particular ∂(ρ E)/∂σ_x = (1/2) ∂(ρ E)/∂σ_αβ = (1/2) ∂(ρ E)/∂σ_βα.
This explains the extra factor (1/2) needed in the GGA term of the XC potential
and which pops up in the GGA kernel whenever derivatives wrt. σ are considered.
=#

#=  Packed representation of spin-adapted libxc quantities.

When storing the spin components of the contracted density gradient as well
as the various derivatives of the energy wrt. ρ or σ, libxc uses a packed
representation exploiting spin symmetry. The following helper functions
allow to write more readable loops by taking care of the packing of a Cartesian
spin index to the libxc format.
=#

# Leaving aside the details with the identification of the second spin
# component of σ with (σ_αβ + σ_βα)/2 detailed above, the contracted density
# gradient σ seems to be storing the spin components [αα αβ ββ]. In DFTK we
# identify α with 1 and β with 2, leading to the spin mapping. The caller has
# to make sure to include a factor (1/2) in the contraction whenever s == t.
function libxc_spinindex_σ(s, t)
    s == 1 && t == 1 && return 1
    s == 2 && t == 2 && return 3
    return 2
end

# For terms.v2rho2 the spins are arranged as [(α, α), (α, β), (β, β)]
function libxc_spinindex_ρρ(s, t)
    s == 1 && t == 1 && return 1
    s == 2 && t == 2 && return 3
    return 2
end

# For e.g. terms.v2rhosigma the spins are arranged in row-major order as
# [(α, αα) (α, αβ) (α, ββ) (β, αα) (β, αβ) (β, ββ)]
# where the second entry in the tuple refers to the spin component of
# the σ derivative.
libxc_spinindex_ρσ(s, t) = @inbounds LinearIndices((3, 2))[t, s]

# For e.g. terms.v2sigma2 the spins are arranged as
# [(αα, αα) (αα, αβ) (αα, ββ) (αβ, αβ) (αβ, ββ) (ββ, ββ)]
function libxc_spinindex_σσ(s, t)
    s ≤ t || return libxc_spinindex_σσ(t, s)
    Dict((1, 1) => 1, (1, 2) => 2, (1, 3) => 3,
                      (2, 2) => 4, (2, 3) => 5,
                                   (3, 3) => 6
    )[(s, t)]
end

# TODO Hide some of the index and spin-factor details by wrapping around the terms tuple
#      returned from Libxc.evaluate ?

function max_required_derivative(functional)
    functional.family == :lda && return 0
    functional.family == :gga && return 1
    error("Functional family $(functional.family) not known.")
end

# stores the input to libxc in a format it likes
struct LibxcDensity
    basis
    max_derivative::Int
    ρ_real    # density ρ[iσ, ix, iy, iz]
    ∇ρ_real   # for GGA, density gradient ∇ρ[iσ, ix, iy, iz, iα]
    σ_real    # for GGA, contracted density gradient σ[iσ, ix, iy, iz]
end

"""
Compute density in real space and its derivatives starting from ρ
"""
function LibxcDensity(basis, max_derivative::Integer, ρ)
    model = basis.model
    @assert max_derivative in (0, 1)

    n_spin    = model.n_spin_components
    σ_real    = nothing
    ∇ρ_real   = nothing

    # compute ρ_real and possibly ρ_fourier
    ρ_real = permutedims(ρ, (4, 1, 2, 3))  # ρ[x, y, z, σ] -> ρ_real[σ, x, y, z]
    if max_derivative > 0
        ρf = r_to_G(basis, ρ)
        ρ_fourier = permutedims(ρf, (4, 1, 2, 3))  # ρ_fourier[σ, x, y, z]
    end

    # compute ∇ρ and σ
    if max_derivative > 0
        n_spin_σ = div((n_spin + 1) * n_spin, 2)
        ∇ρ_real = similar(ρ_real,   n_spin, basis.fft_size..., 3)
        σ_real  = similar(ρ_real, n_spin_σ, basis.fft_size...)

        for α = 1:3
            iGα = [im * G[α] for G in G_vectors_cart(basis)]
            for σ = 1:n_spin
                ∇ρ_real[σ, :, :, :, α] .= G_to_r(basis, iGα .* @view ρ_fourier[σ, :, :, :])
            end
        end

        tσ = libxc_spinindex_σ  # Spin index transformation (s, t) => st as expected by Libxc
        σ_real .= 0
        @views for α in 1:3
            σ_real[tσ(1, 1), :, :, :] .+= ∇ρ_real[1, :, :, :, α] .* ∇ρ_real[1, :, :, :, α]
            if n_spin > 1
                σ_real[tσ(1, 2), :, :, :] .+= ∇ρ_real[1, :, :, :, α] .* ∇ρ_real[2, :, :, :, α]
                σ_real[tσ(2, 2), :, :, :] .+= ∇ρ_real[2, :, :, :, α] .* ∇ρ_real[2, :, :, :, α]
            end
        end
    end

    LibxcDensity(basis, max_derivative, ρ_real, ∇ρ_real, σ_real)
end

function compute_kernel(term::TermXc, basis::PlaneWaveBasis; ρ, kwargs...)
    density = LibxcDensity(basis, 0, ρ)
    n_spin  = basis.model.n_spin_components
    @assert 1 ≤ n_spin ≤ 2
    if !all(xc.family == :lda for xc in term.functionals)
        error("compute_kernel only implemented for LDA")
    end
    @assert all(xc.n_spin == n_spin for xc in term.functionals)

    kernel = evaluate(term.functionals, density; derivatives=2:2).v2rho2
    fac = term.scaling_factor
    if n_spin == 1
        Diagonal(vec(fac .* kernel))
    else
        # Blocks in the kernel matrix mapping (ρα, ρβ) ↦ (Vα, Vβ)
        Kαα = @view kernel[1, :, :, :]
        Kαβ = @view kernel[2, :, :, :]
        Kβα = Kαβ
        Kββ = @view kernel[3, :, :, :]

        fac .* [Diagonal(vec(Kαα)) Diagonal(vec(Kαβ));
                Diagonal(vec(Kβα)) Diagonal(vec(Kββ))]
    end
end

function apply_kernel(term::TermXc, basis::PlaneWaveBasis{T}, δρ; ρ, kwargs...) where {T}
    n_spin = basis.model.n_spin_components
    isempty(term.functionals) && return nothing
    @assert all(xc.family in (:lda, :gga) for xc in term.functionals)
    @assert all(xc.n_spin == n_spin for xc in term.functionals)

    # Take derivatives of the density and the perturbation if needed.
    max_ρ_derivs = maximum(max_required_derivative, term.functionals)
    density      = LibxcDensity(basis, max_ρ_derivs, ρ)
    perturbation = LibxcDensity(basis, max_ρ_derivs, δρ)

    ∇ρ  = density.∇ρ_real
    δρ  = perturbation.ρ_real
    ∇δρ = perturbation.∇ρ_real

    # Compute required density / perturbation cross-derivatives
    cross_derivatives = Dict{Symbol, Any}()
    if max_ρ_derivs > 0
        cross_derivatives[:δσ] = [
            @views 2sum(∇ρ[I[1], :, :, :, α] .* ∇δρ[I[2], :, :, :, α] for α in 1:3)
            for I in CartesianIndices((n_spin, n_spin))
        ]
    end

    # TODO LDA actually only needs the 2nd derivatives for this ... could be optimised
    terms  = evaluate(term.functionals, density, derivatives=1:2)
    δV = zero(ρ)  # [iσ, ix, iy, iz]

    tρρ = libxc_spinindex_ρρ
    @views for s in 1:n_spin, t in 1:n_spin  # LDA term
        δV[:, :, :, s] .+= terms.v2rho2[tρρ(s, t), :, :, :] .* δρ[t, :, :, :]
    end
    if haskey(terms, :v2rhosigma)  # GGA term
        add_kernel_gradient_correction!(δV, terms, density, perturbation, cross_derivatives)
    end

    term.scaling_factor * δV
end

function add_kernel_gradient_correction!(δV, terms, density, perturbation, cross_derivatives)
    # Follows DOI 10.1103/PhysRevLett.107.216402
    #
    # For GGA V = Vρ - 2 ∇⋅(Vσ ∇ρ) = (∂ε/∂ρ) - 2 ∇⋅((∂ε/∂σ) ∇ρ)
    #
    # δV(r) = f(r,r') δρ(r') = (∂V/∂ρ) δρ + (∂V/∂σ) δσ
    #
    # therefore
    # δV(r) = (∂^2ε/∂ρ^2) δρ - 2 ∇⋅[(∂^2ε/∂σ∂ρ) ∇ρ + (∂ε/∂σ) (∂∇ρ/∂ρ)] δρ
    #       + (∂^2ε/∂ρ∂σ) δσ - 2 ∇⋅[(∂^ε/∂σ^2) ∇ρ  + (∂ε/∂σ) (∂∇ρ/∂σ)] δσ
    #
    # Note δσ = 2∇ρ⋅δ∇ρ = 2∇ρ⋅∇δρ, therefore
    #      - 2 ∇⋅((∂ε/∂σ) (∂∇ρ/∂σ)) δσ
    #    = - 2 ∇(∂ε/∂σ)⋅(∂∇ρ/∂σ) δσ - 2 (∂ε/∂σ) ∇⋅(∂∇ρ/∂σ) δσ
    #    = - 2 ∇(∂ε/∂σ)⋅δ∇ρ - 2 (∂ε/∂σ) ∇⋅δ∇ρ
    #    = - 2 ∇⋅((∂ε/∂σ) ∇δρ)
    # and (because assumed independent variables): (∂∇ρ/∂ρ) = 0.
    #
    # Note that below the LDA term (∂^2ε/∂ρ^2) δρ is not done here (dealt with by caller)

    basis  = density.basis
    n_spin = basis.model.n_spin_components
    ρ   = density.ρ_real
    ∇ρ  = density.∇ρ_real
    δρ  = perturbation.ρ_real
    ∇δρ = perturbation.∇ρ_real
    δσ  = cross_derivatives[:δσ]
    Vρσ = terms.v2rhosigma
    Vσσ = terms.v2sigma2
    Vσ  = terms.vsigma

    T   = eltype(ρ)
    tσ  = libxc_spinindex_σ
    tρσ = libxc_spinindex_ρσ
    tσσ = libxc_spinindex_σσ

    # Note: δV[iσ, ix, iy, iz] unlike the other quantities ...
    @views for s in 1:n_spin
        for t in 1:n_spin, u in 1:n_spin
            spinfac_tu = (t == u ? one(T) : one(T)/2)
            stu = tρσ(s, tσ(t, u))
            @. δV[:, :, :, s] += spinfac_tu * Vρσ[stu, :, :, :] * δσ[t, u][:, :, :]
        end

        # TODO Potential for some optimisation ... some contractions in this body are
        #      independent of α and could be precomputed.
        δV[:, :, :, s] .+= divergence_real(density.basis) do α
            ret_α = similar(density.ρ_real, basis.fft_size...)
            ret_α .= 0
            for t in 1:n_spin
                spinfac_st = (t == s ? one(T) : one(T)/2)
                ret_α .+= -2spinfac_st .* Vσ[tσ(s, t), :, :, :] .* ∇δρ[t, :, :, :, α]

                for u in 1:n_spin
                    spinfac_su = (s == u ? one(T) : one(T)/2)
                    tsu = tρσ(t, tσ(s, u))
                    ret_α .+= -2spinfac_su .* Vρσ[tsu, :, :, :] .* ∇ρ[u, :, :, :, α] .* δρ[t, :, :, :]

                    for v in 1:n_spin
                        spinfac_uv = (u == v ? one(T) : one(T)/2)
                        stuv = tσσ(tσ(s, t), tσ(u, v))
                        ret_α .+= (-2spinfac_uv .* spinfac_st .* Vσσ[stuv, :, :, :]
                                   .* ∇ρ[t, :, :, :, α] .* δσ[u, v][:, :, :])
                    end  # v
                end  # u
            end  # t
            ret_α
        end  # α
    end

    δV
end

function Libxc.evaluate(xc::Functional, density::LibxcDensity; kwargs...)
    if xc.family == :lda
        evaluate(xc; rho=density.ρ_real, kwargs...)
    elseif xc.family == :gga
        evaluate(xc; rho=density.ρ_real, sigma=density.σ_real, kwargs...)
    else
        error("Not implemented for functional familiy $(xc.family)")
    end
end
function Libxc.evaluate(xcs::Vector{Functional}, density::LibxcDensity; kwargs...)
    isempty(xcs) && return NamedTuple()
    @assert all(xc.family == xcs[1].family for xc in xcs)

    result = evaluate(xcs[1], density; kwargs...)
    for i in 2:length(xcs)
        other = evaluate(xcs[i], density; kwargs...)
        for (k, v) in pairs(other)
            result[k] .+= other[k]
        end
    end
    result
end

"""
Compute divergence of an operand function, which returns the cartesian x,y,z
components in real space when called with the arguments 1 to 3.
The divergence is also returned as a real-space array.
"""
function divergence_real(operand, basis)
    gradsum = sum(1:3) do α
        operand_α = r_to_G(basis, operand(α))
        del_α = im * [G[α] for G in G_vectors_cart(basis)]
        del_α .* operand_α
    end
    G_to_r(basis, gradsum)
end


text:
using BinDeps

using Compat

include("versions.jl")

@BinDeps.setup

icu_aliases = ["libicuuc"]
i18n_aliases = ["libicui18n"]
@osx_only begin
    icu_aliases = ["libicucore"]
    i18n_aliases = ["libicucore"]
end
@windows_only begin
    icu_aliases = ["icuuc$v" for v in versions]
    i18n_aliases = [["icui18n$v" for v in versions];
                    ["icuin$v" for v in versions]]
end
icu = library_dependency("icu", aliases=icu_aliases)
icui18n = library_dependency("icui18n", aliases=i18n_aliases)

@windows_only begin
    using WinRPM
    provides(WinRPM.RPM, "icu", [icu,icui18n], os=:Windows)
end
provides(AptGet, @compat Dict(["libicu$v" => [icu,icui18n] for v in apt_versions]))
provides(Yum, "icu", [icu, icui18n])

@BinDeps.install @compat Dict(:icu => :iculib, :icui18n => :iculibi18n)


text:
# This file was generated by the Julia Swagger Code Generator
# Do not modify this file directly. Modify the swagger specification instead.

mutable struct StorageAccountProperties <: SwaggerModel
    provisioningState::Any # spec type: Union{ Nothing, String } # spec name: provisioningState
    primaryEndpoints::Any # spec type: Union{ Nothing, Endpoints } # spec name: primaryEndpoints
    primaryLocation::Any # spec type: Union{ Nothing, String } # spec name: primaryLocation
    statusOfPrimary::Any # spec type: Union{ Nothing, String } # spec name: statusOfPrimary
    lastGeoFailoverTime::Any # spec type: Union{ Nothing, DateTime } # spec name: lastGeoFailoverTime
    secondaryLocation::Any # spec type: Union{ Nothing, String } # spec name: secondaryLocation
    statusOfSecondary::Any # spec type: Union{ Nothing, String } # spec name: statusOfSecondary
    creationTime::Any # spec type: Union{ Nothing, DateTime } # spec name: creationTime
    customDomain::Any # spec type: Union{ Nothing, CustomDomain } # spec name: customDomain
    secondaryEndpoints::Any # spec type: Union{ Nothing, Endpoints } # spec name: secondaryEndpoints
    encryption::Any # spec type: Union{ Nothing, Encryption } # spec name: encryption
    accessTier::Any # spec type: Union{ Nothing, String } # spec name: accessTier
    azureFilesIdentityBasedAuthentication::Any # spec type: Union{ Nothing, AzureFilesIdentityBasedAuthentication } # spec name: azureFilesIdentityBasedAuthentication
    supportsHttpsTrafficOnly::Any # spec type: Union{ Nothing, Bool } # spec name: supportsHttpsTrafficOnly
    networkAcls::Any # spec type: Union{ Nothing, NetworkRuleSet } # spec name: networkAcls
    isHnsEnabled::Any # spec type: Union{ Nothing, Bool } # spec name: isHnsEnabled
    geoReplicationStats::Any # spec type: Union{ Nothing, GeoReplicationStats } # spec name: geoReplicationStats
    failoverInProgress::Any # spec type: Union{ Nothing, Bool } # spec name: failoverInProgress
    largeFileSharesState::Any # spec type: Union{ Nothing, String } # spec name: largeFileSharesState
    privateEndpointConnections::Any # spec type: Union{ Nothing, Vector{PrivateEndpointConnection} } # spec name: privateEndpointConnections
    routingPreference::Any # spec type: Union{ Nothing, RoutingPreference } # spec name: routingPreference
    blobRestoreStatus::Any # spec type: Union{ Nothing, BlobRestoreStatus } # spec name: blobRestoreStatus
    allowBlobPublicAccess::Any # spec type: Union{ Nothing, Bool } # spec name: allowBlobPublicAccess
    minimumTlsVersion::Any # spec type: Union{ Nothing, String } # spec name: minimumTlsVersion

    function StorageAccountProperties(;provisioningState=nothing, primaryEndpoints=nothing, primaryLocation=nothing, statusOfPrimary=nothing, lastGeoFailoverTime=nothing, secondaryLocation=nothing, statusOfSecondary=nothing, creationTime=nothing, customDomain=nothing, secondaryEndpoints=nothing, encryption=nothing, accessTier=nothing, azureFilesIdentityBasedAuthentication=nothing, supportsHttpsTrafficOnly=nothing, networkAcls=nothing, isHnsEnabled=nothing, geoReplicationStats=nothing, failoverInProgress=nothing, largeFileSharesState=nothing, privateEndpointConnections=nothing, routingPreference=nothing, blobRestoreStatus=nothing, allowBlobPublicAccess=nothing, minimumTlsVersion=nothing)
        o = new()
        validate_property(StorageAccountProperties, Symbol("provisioningState"), provisioningState)
        setfield!(o, Symbol("provisioningState"), provisioningState)
        validate_property(StorageAccountProperties, Symbol("primaryEndpoints"), primaryEndpoints)
        setfield!(o, Symbol("primaryEndpoints"), primaryEndpoints)
        validate_property(StorageAccountProperties, Symbol("primaryLocation"), primaryLocation)
        setfield!(o, Symbol("primaryLocation"), primaryLocation)
        validate_property(StorageAccountProperties, Symbol("statusOfPrimary"), statusOfPrimary)
        setfield!(o, Symbol("statusOfPrimary"), statusOfPrimary)
        validate_property(StorageAccountProperties, Symbol("lastGeoFailoverTime"), lastGeoFailoverTime)
        setfield!(o, Symbol("lastGeoFailoverTime"), lastGeoFailoverTime)
        validate_property(StorageAccountProperties, Symbol("secondaryLocation"), secondaryLocation)
        setfield!(o, Symbol("secondaryLocation"), secondaryLocation)
        validate_property(StorageAccountProperties, Symbol("statusOfSecondary"), statusOfSecondary)
        setfield!(o, Symbol("statusOfSecondary"), statusOfSecondary)
        validate_property(StorageAccountProperties, Symbol("creationTime"), creationTime)
        setfield!(o, Symbol("creationTime"), creationTime)
        validate_property(StorageAccountProperties, Symbol("customDomain"), customDomain)
        setfield!(o, Symbol("customDomain"), customDomain)
        validate_property(StorageAccountProperties, Symbol("secondaryEndpoints"), secondaryEndpoints)
        setfield!(o, Symbol("secondaryEndpoints"), secondaryEndpoints)
        validate_property(StorageAccountProperties, Symbol("encryption"), encryption)
        setfield!(o, Symbol("encryption"), encryption)
        validate_property(StorageAccountProperties, Symbol("accessTier"), accessTier)
        setfield!(o, Symbol("accessTier"), accessTier)
        validate_property(StorageAccountProperties, Symbol("azureFilesIdentityBasedAuthentication"), azureFilesIdentityBasedAuthentication)
        setfield!(o, Symbol("azureFilesIdentityBasedAuthentication"), azureFilesIdentityBasedAuthentication)
        validate_property(StorageAccountProperties, Symbol("supportsHttpsTrafficOnly"), supportsHttpsTrafficOnly)
        setfield!(o, Symbol("supportsHttpsTrafficOnly"), supportsHttpsTrafficOnly)
        validate_property(StorageAccountProperties, Symbol("networkAcls"), networkAcls)
        setfield!(o, Symbol("networkAcls"), networkAcls)
        validate_property(StorageAccountProperties, Symbol("isHnsEnabled"), isHnsEnabled)
        setfield!(o, Symbol("isHnsEnabled"), isHnsEnabled)
        validate_property(StorageAccountProperties, Symbol("geoReplicationStats"), geoReplicationStats)
        setfield!(o, Symbol("geoReplicationStats"), geoReplicationStats)
        validate_property(StorageAccountProperties, Symbol("failoverInProgress"), failoverInProgress)
        setfield!(o, Symbol("failoverInProgress"), failoverInProgress)
        validate_property(StorageAccountProperties, Symbol("largeFileSharesState"), largeFileSharesState)
        setfield!(o, Symbol("largeFileSharesState"), largeFileSharesState)
        validate_property(StorageAccountProperties, Symbol("privateEndpointConnections"), privateEndpointConnections)
        setfield!(o, Symbol("privateEndpointConnections"), privateEndpointConnections)
        validate_property(StorageAccountProperties, Symbol("routingPreference"), routingPreference)
        setfield!(o, Symbol("routingPreference"), routingPreference)
        validate_property(StorageAccountProperties, Symbol("blobRestoreStatus"), blobRestoreStatus)
        setfield!(o, Symbol("blobRestoreStatus"), blobRestoreStatus)
        validate_property(StorageAccountProperties, Symbol("allowBlobPublicAccess"), allowBlobPublicAccess)
        setfield!(o, Symbol("allowBlobPublicAccess"), allowBlobPublicAccess)
        validate_property(StorageAccountProperties, Symbol("minimumTlsVersion"), minimumTlsVersion)
        setfield!(o, Symbol("minimumTlsVersion"), minimumTlsVersion)
        o
    end
end # type StorageAccountProperties

const _property_map_StorageAccountProperties = Dict{Symbol,Symbol}(Symbol("provisioningState")=>Symbol("provisioningState"), Symbol("primaryEndpoints")=>Symbol("primaryEndpoints"), Symbol("primaryLocation")=>Symbol("primaryLocation"), Symbol("statusOfPrimary")=>Symbol("statusOfPrimary"), Symbol("lastGeoFailoverTime")=>Symbol("lastGeoFailoverTime"), Symbol("secondaryLocation")=>Symbol("secondaryLocation"), Symbol("statusOfSecondary")=>Symbol("statusOfSecondary"), Symbol("creationTime")=>Symbol("creationTime"), Symbol("customDomain")=>Symbol("customDomain"), Symbol("secondaryEndpoints")=>Symbol("secondaryEndpoints"), Symbol("encryption")=>Symbol("encryption"), Symbol("accessTier")=>Symbol("accessTier"), Symbol("azureFilesIdentityBasedAuthentication")=>Symbol("azureFilesIdentityBasedAuthentication"), Symbol("supportsHttpsTrafficOnly")=>Symbol("supportsHttpsTrafficOnly"), Symbol("networkAcls")=>Symbol("networkAcls"), Symbol("isHnsEnabled")=>Symbol("isHnsEnabled"), Symbol("geoReplicationStats")=>Symbol("geoReplicationStats"), Symbol("failoverInProgress")=>Symbol("failoverInProgress"), Symbol("largeFileSharesState")=>Symbol("largeFileSharesState"), Symbol("privateEndpointConnections")=>Symbol("privateEndpointConnections"), Symbol("routingPreference")=>Symbol("routingPreference"), Symbol("blobRestoreStatus")=>Symbol("blobRestoreStatus"), Symbol("allowBlobPublicAccess")=>Symbol("allowBlobPublicAccess"), Symbol("minimumTlsVersion")=>Symbol("minimumTlsVersion"))
const _property_types_StorageAccountProperties = Dict{Symbol,String}(Symbol("provisioningState")=>"String", Symbol("primaryEndpoints")=>"Endpoints", Symbol("primaryLocation")=>"String", Symbol("statusOfPrimary")=>"String", Symbol("lastGeoFailoverTime")=>"DateTime", Symbol("secondaryLocation")=>"String", Symbol("statusOfSecondary")=>"String", Symbol("creationTime")=>"DateTime", Symbol("customDomain")=>"CustomDomain", Symbol("secondaryEndpoints")=>"Endpoints", Symbol("encryption")=>"Encryption", Symbol("accessTier")=>"String", Symbol("azureFilesIdentityBasedAuthentication")=>"AzureFilesIdentityBasedAuthentication", Symbol("supportsHttpsTrafficOnly")=>"Bool", Symbol("networkAcls")=>"NetworkRuleSet", Symbol("isHnsEnabled")=>"Bool", Symbol("geoReplicationStats")=>"GeoReplicationStats", Symbol("failoverInProgress")=>"Bool", Symbol("largeFileSharesState")=>"String", Symbol("privateEndpointConnections")=>"Vector{PrivateEndpointConnection}", Symbol("routingPreference")=>"RoutingPreference", Symbol("blobRestoreStatus")=>"BlobRestoreStatus", Symbol("allowBlobPublicAccess")=>"Bool", Symbol("minimumTlsVersion")=>"String")
Base.propertynames(::Type{ StorageAccountProperties }) = collect(keys(_property_map_StorageAccountProperties))
Swagger.property_type(::Type{ StorageAccountProperties }, name::Symbol) = Union{Nothing,eval(Base.Meta.parse(_property_types_StorageAccountProperties[name]))}
Swagger.field_name(::Type{ StorageAccountProperties }, property_name::Symbol) =  _property_map_StorageAccountProperties[property_name]

const _allowed_StorageAccountProperties_provisioningState = ["Creating", "ResolvingDNS", "Succeeded"]

const _allowed_StorageAccountProperties_statusOfPrimary = ["available", "unavailable"]

const _allowed_StorageAccountProperties_statusOfSecondary = ["available", "unavailable"]

const _allowed_StorageAccountProperties_accessTier = ["Hot", "Cool"]

const _allowed_StorageAccountProperties_largeFileSharesState = ["Disabled", "Enabled"]

const _allowed_StorageAccountProperties_minimumTlsVersion = ["TLS1_0", "TLS1_1", "TLS1_2"]

function check_required(o::StorageAccountProperties)
    true
end

function validate_property(::Type{ StorageAccountProperties }, name::Symbol, val)
    if name === Symbol("provisioningState")
        Swagger.validate_param(name, "StorageAccountProperties", :enum, val, _allowed_StorageAccountProperties_provisioningState)
    end
    if name === Symbol("statusOfPrimary")
        Swagger.validate_param(name, "StorageAccountProperties", :enum, val, _allowed_StorageAccountProperties_statusOfPrimary)
    end
    if name === Symbol("statusOfSecondary")
        Swagger.validate_param(name, "StorageAccountProperties", :enum, val, _allowed_StorageAccountProperties_statusOfSecondary)
    end
    if name === Symbol("accessTier")
        Swagger.validate_param(name, "StorageAccountProperties", :enum, val, _allowed_StorageAccountProperties_accessTier)
    end
    if name === Symbol("largeFileSharesState")
        Swagger.validate_param(name, "StorageAccountProperties", :enum, val, _allowed_StorageAccountProperties_largeFileSharesState)
    end
    if name === Symbol("minimumTlsVersion")
        Swagger.validate_param(name, "StorageAccountProperties", :enum, val, _allowed_StorageAccountProperties_minimumTlsVersion)
    end
end


text:
"""
    eval_interp(m::Module, ex)

evaluate the interpolation operator in `ex` inside given module `m`.
"""
function eval_interp(m::Module, ex)
    ex isa Expr || return ex
    if ex.head === :$
        x = ex.args[1]
        if x isa Symbol && isdefined(m, x)
            return Base.eval(m, x)
        else
            return ex
        end
    end
    return Expr(ex.head, map(x->eval_interp(m, x), ex.args)...)
end

"""
    eval_literal(m::Module, ex)

Evaluate the literal values and insert them back to the expression.
The literal value can be checked via [`is_literal`](@ref).
"""
function eval_literal(m::Module, ex)
    ex isa Expr || return ex
    if ex.head === :call && all(is_literal, ex.args[2:end])
        return Base.eval(m, ex)
    end
    return Expr(ex.head, map(x->eval_literal(m, x), ex.args)...)
end

replace_symbol(x::Symbol, name::Symbol, value) = x === name ? value : x
replace_symbol(x, ::Symbol, value) = x # other expressions

function replace_symbol(ex::Expr, name::Symbol, value)
    Expr(ex.head, map(x->replace_symbol(x, name, value), ex.args)...)
end

"""
    subtitute(ex::Expr, old=>new)

Subtitute the old symbol `old` with `new`.
"""
function subtitute(ex::Expr, replace::Pair)
    name, value = replace
    return replace_symbol(ex, name, value)
end

"""
    name_only(ex)

Remove everything else leaving just names, currently supports
function calls, type with type variables, subtype operator `<:`
and type annotation `::`.

# Example

```julia
julia> using Expronicon

julia> name_only(:(sin(2)))
:sin

julia> name_only(:(Foo{Int}))
:Foo

julia> name_only(:(Foo{Int} <: Real))
:Foo

julia> name_only(:(x::Int))
:x
```
"""
function name_only(@nospecialize(ex))
    ex isa Symbol && return ex
    ex isa QuoteNode && return ex.value
    ex isa Expr || error("unsupported expression $ex")
    ex.head in [:call, :curly, :(<:), :(::), :where, :function, :kw, :(=), :(->)] && return name_only(ex.args[1])
    ex.head === :. && return name_only(ex.args[2])
    ex.head === :module && return name_only(ex.args[2])
    error("unsupported expression $ex")
end

"""
    rm_lineinfo(ex)

Remove `LineNumberNode` in a given expression.

!!! tips

    the `LineNumberNode` inside macro calls won't be removed since
    the `macrocall` expression requires a `LineNumberNode`. See also
    [issues/#9](https://github.com/Roger-luo/Expronicon.jl/issues/9).
"""
function rm_lineinfo(ex)
    @match ex begin
        Expr(:macrocall, name, line, args...) => Expr(:macrocall, name, line, map(rm_lineinfo, args)...)
        Expr(head, args...) => Expr(head, map(rm_lineinfo, filter(x->!(x isa LineNumberNode), args))...)
        _ => ex
    end
end

Base.@kwdef struct PrettifyOptions
    rm_lineinfo::Bool = true
    flatten_blocks::Bool = true
    rm_nothing::Bool = true
    rm_single_block::Bool = true
    alias_gensym::Bool = true
end

"""
    prettify(ex; kw...)

Prettify given expression, remove all `LineNumberNode` and
extra code blocks.

# Options (Kwargs)

All the options are `true` by default.

- `rm_lineinfo`: remove `LineNumberNode`.
- `flatten_blocks`: flatten `begin ... end` code blocks.
- `rm_nothing`: remove `nothing` in the `begin ... end`.
- `rm_single_block`: remove single `begin ... end`.
- `alias_gensym`: replace `##<name>#<num>` with `<name>_<id>`.

!!! tips

    the `LineNumberNode` inside macro calls won't be removed since
    the `macrocall` expression requires a `LineNumberNode`. See also
    [issues/#9](https://github.com/Roger-luo/Expronicon.jl/issues/9).
"""
function prettify(ex; kw...)
    prettify(ex, PrettifyOptions(;kw...))
end

function prettify(ex, options::PrettifyOptions)
    ex isa Expr || return ex
    ex = options.alias_gensym ? alias_gensym(ex) : ex
    for _ in 1:10
        curr = prettify_pass(ex, options)
        ex == curr && break
        ex = curr
    end
    return ex
end

function prettify_pass(ex, options::PrettifyOptions)
    ex = options.rm_lineinfo ? rm_lineinfo(ex) : ex
    ex = options.flatten_blocks ? flatten_blocks(ex) : ex
    ex = options.rm_nothing ? rm_nothing(ex) : ex
    ex = options.rm_single_block ? rm_single_block(ex) : ex
    return ex
end

"""
    flatten_blocks(ex)

Remove hierachical expression blocks.
"""
function flatten_blocks(ex)
    ex isa Expr || return ex
    ex.head === :block || return Expr(ex.head, map(_flatten_blocks, ex.args)...)
    has_block = any(ex.args) do x
        x isa Expr && x.head === :block
    end

    if has_block
        return flatten_blocks(_flatten_blocks(ex))
    end
    return Expr(ex.head, map(flatten_blocks, ex.args)...)
end

function _flatten_blocks(ex)
    ex isa Expr || return ex
    ex.head === :block || return Expr(ex.head, map(flatten_blocks, ex.args)...)

    args = []
    for stmt in ex.args
        if stmt isa Expr && stmt.head === :block
            for each in stmt.args
                push!(args, flatten_blocks(each))
            end
        else
            push!(args, flatten_blocks(stmt))
        end
    end
    return Expr(:block, args...)
end

"""
    rm_nothing(ex)

Remove the constant value `nothing` in given expression `ex`.
"""
function rm_nothing(ex)
    @match ex begin
        Expr(:block, args...) => Expr(:block, filter(x->x!==nothing, args)...)
        Expr(head, args...) => Expr(head, map(rm_nothing, args)...)
        _ => ex
    end
end

function rm_single_block(ex)
    @match ex begin
        Expr(:(=), _...) ||
            Expr(:(->), _...) ||
            Expr(:quote, xs...) ||
            Expr(:block, Expr(:quote, xs...)) => ex
        Expr(:try, Expr(:block, try_stmts...), false, false, Expr(:block, finally_stmts...)) => Expr(:try,
                Expr(:block, rm_single_block.(try_stmts)...),
                false, false,
                Expr(:block, rm_single_block.(finally_stmts)...)
            )
        Expr(:try, Expr(:block, try_stmts...), catch_var, Expr(:block, catch_stmts...)) => Expr(:try,
                Expr(:block, rm_single_block.(try_stmts)...),
                catch_var,
                Expr(:block, rm_single_block.(catch_stmts)...)
            )
        Expr(:try, Expr(:block, try_stmts...), catch_var,
            Expr(:block, catch_stmts...), Expr(:block, finally_stmts...)) => Expr(:try,
                Expr(:block, rm_single_block.(try_stmts)...),
                catch_var,
                Expr(:block, rm_single_block.(catch_stmts)...),
                Expr(:block, rm_single_block.(finally_stmts)...)
            )
        Expr(:block, stmt) => stmt
        Expr(head, args...) => Expr(head, map(rm_single_block, args)...)
        _ => ex
    end
end

"""
    rm_annotations(x)

Remove type annotation of given expression.
"""
function rm_annotations(x)
    x isa Expr || return x
    if x.head == :(::)
        if length(x.args) == 1 # anonymous
            return gensym("::$(x.args[1])")
        else
            return x.args[1]
        end
    elseif x.head in [:(=), :kw] # default values
        return rm_annotations(x.args[1])
    else
        return Expr(x.head, map(rm_annotations, x.args)...)
    end
end

"""
    alias_gensym(ex)

Replace gensym with `<name>_<id>`.

!!! note
    Borrowed from [MacroTools](https://github.com/FluxML/MacroTools.jl).
"""
alias_gensym(ex) = alias_gensym!(Dict{Symbol, Symbol}(), Dict{Symbol, Int}(), ex)

function alias_gensym!(d::Dict{Symbol, Symbol}, count::Dict{Symbol, Int}, ex)
    if is_gensym(ex)
        haskey(d, ex) && return d[ex]
        name = Symbol(gensym_name(ex))
        id = get(count, name, 0) + 1
        d[ex] = Symbol(name, :_, id)
        count[name] = id
        return d[ex]
    end

    ex isa Expr || return ex
    args = map(ex.args) do x
        alias_gensym!(d, count, x)
    end

    return Expr(ex.head, args...)
end


text:
using Turing
using Test
using Random
using Distributions

Random.seed!(128)

alg1 = HMCDA(3000, 1000, 0.65, 0.015)
# alg2 = Gibbs(3000, HMCDA(1, 200, 0.65, 0.35, :m), HMC(1, 0.25, 3, :s))
alg3 = Gibbs(1500, PG(30, 10, :s), HMCDA(1, 500, 0.65, 0.005, :m))
# alg3 = Gibbs(2000, HMC(1, 0.25, 3, :m), PG(30, 3, :s))
# alg3 = PG(50, 2000)

@model gdemo(x) = begin
  s ~ InverseGamma(2,3)
  m ~ Normal(0,sqrt.(s))
  x[1] ~ Normal(m, sqrt.(s))
  x[2] ~ Normal(m, sqrt.(s))
  return s, m
end

res1 = sample(gdemo([1.5, 2.0]), alg1)

check_numerical(res1, [:s, :m], [49/24, 7/6])

# res2 = sample(gdemo([1.5, 2.0]), alg2)
#
# @test mean(res2[:s]) ≈ 49/24 atol=0.2
# @test mean(res2[:m]) ≈ 7/6 atol=0.2

res3 = sample(gdemo([1.5, 2.0]), alg3)

check_numerical(res3, [:s, :m], [49/24, 7/6])

# res1 = sample(gdemo([1.5, 2.0]), HMC(3000, 0.2, 4))
# println("HMC")
# println("E[s] = $(mean(res1[:s]))")
# println("E[m] = $(mean(res1[:m]))")


text:
@testset "Decoder" begin

  # Bool
  v = Jib.Reader.Decoder.Field.(["0", "1", "false", "true", ""])
  @test collect(Bool, v[1:4]) == [false, true, false, true]

  @test_throws ErrorException convert(Bool, v[5])

  # Int
  v = Jib.Reader.Decoder.Field.(["", "1", "2147483647", "9223372036854775807", "a"])
  @test collect(Union{Int,Nothing}, v[1:4]) == [nothing, 1, nothing, nothing]

  @test_throws ArgumentError convert(Int, v[5])

  # Float64
  v = Jib.Reader.Decoder.Field.(["", "1", "1.7976931348623157E308", "a"])
  @test collect(Union{Float64,Nothing}, v[1:3]) == [nothing, 1, nothing]

  @test_throws ArgumentError convert(Float64, v[4])

  # Enum
  v = Jib.Reader.Decoder.Field.(["1", "2", "a"])
  @test convert(Jib.ConditionType, v[1]) == Jib.PRICE

  @test_throws ArgumentError convert(Jib.ConditionType, v[2])
  @test_throws ArgumentError convert(Jib.ConditionType, v[3])

  # String
  @test collect(String, v) == ["1", "2", "a"]

  # slurp
  v =  Jib.Reader.Decoder.Field.(["1", "0", "action", "", "0", "0", "", "-1", ""])
  it = Iterators.Stateful(v)

  @test Jib.Reader.Decoder.slurp((Int, Float64, String), it) == [1, 0., "action"]

  @test isnothing(Jib.Reader.Decoder.slurp(Int, it))

  it = Iterators.Stateful(v)
  @test Jib.Reader.Decoder.slurp(Jib.ComboLeg, it) == Jib.ComboLeg(conId=1, action="action")

  it = Iterators.Stateful(v)
  c = Jib.Contract()
  Jib.Reader.Decoder.slurp!(c, (:conId, :secType, :symbol), it)
  @test c.symbol == Jib.Contract(symbol="action").symbol == "action"

  # unmask
  @test Jib.Reader.Decoder.unmask(NamedTuple{(:a, :b),NTuple{2,Bool}}, 2) == (a=false, b=true)
  @test_logs (:error, "unmask(): wrong attribs") Jib.Reader.Decoder.unmask(NamedTuple{(:a, :b),NTuple{2,Bool}}, 4)

  # tagvalue2nt()
  v =  Jib.Reader.Decoder.Field.(["a", "1", "b", "2"])
  it = Iterators.Stateful(v)
  @test Jib.Reader.Decoder.tagvalue2nt(Iterators.take(it, 4)) == (a="1", b="2")

  # fill_df
  it = Iterators.Stateful(v)
  @test Jib.Reader.Decoder.fill_df([String, Int], [:a, :b], 2, it) == DataFrame(:a => ["a", "b"], :b => [1, 2])

end


text:
module BazykinKhibnik81

using DiffEqBase: ODEProblem
using Parameters: @with_kw, @unpack
using StaticArrays: SVector
using Setfield: @lens
import Setfield

using ...Bifurcations: BifurcationProblem
using ...Codim2: DiffEqCodim2Problem

@with_kw struct BazykinKhibnik81Param{N, M, G}
    n::N = 0.5
    m::M = 0.5
    γ::G = 1
end

function f(u::SVector, p::BazykinKhibnik81Param, t)
    @unpack n, m, γ = p
    x, y = u
    return SVector(
        x * x * (1 - x) / (n + x) - x * y,
        - γ * y * (m - x),
    )
end

function f(du, u, p, t)
    du .= f(SVector{2}(u), p, t)
    nothing
end

make_prob(
        p = BazykinKhibnik81Param();
        u0 = SVector(1.0, 0.0),
        tspan = (0.0, 30.0),
        ode = ODEProblem{!(u0 isa SVector)}(f, u0, tspan, p),
        param_axis = (@lens _.m),
        t_domain = (-1e-3, 2.0),
        kwargs...) =
    BifurcationProblem(ode, param_axis, t_domain;
                       kwargs...)

prob = make_prob()
ode = prob.p.de_prob
u0 = ode.u0
param_axis = prob.p.param_axis
t_domain = prob.t_domain

function make_codim2_prob(
        p = BazykinKhibnik81Param();
        u0 = SVector(1.0, 0.0),
        tspan = (0.0, 30.0),
        ode = ODEProblem{!(u0 isa SVector)}(f, u0, tspan, p),
        param_axis1 = (@lens _.m),
        param_axis2 = (@lens _.n),
        t_domain = ([-1e-3, -1e-3], [2.0, 2.0]),
        kwargs...)
    return DiffEqCodim2Problem(
        ode,
        param_axis1,
        param_axis2,
        t_domain;
        kwargs...)
end

end  # module


text:
using Test
using LogicCircuits
using ProbabilisticCircuits

function conditional_entropy_test()
    N = 10
    D = 5

    b = rand(Bool, N, D)
    dis_cache, hy_given_x = conditional_entropy(b, nothing; α=0)
    p = dis_cache.pairwise
    m = dis_cache.marginal

    for x in 1 : D, y in 1 : D
        h_y_x = p[x, y, 1] * log(p[x, y, 1] / m[x, 1]) +
                    p[x, y, 2] * log(p[x, y, 2] / m[x, 1]) +
                    p[x, y, 3] * log(p[x, y, 3] / m[x, 2]) +
                    p[x, y, 4] * log(p[x, y, 4] / m[x, 2])
        if x == y
            @test hy_given_x[x, y] == 0.0
        elseif !isnan(h_y_x)
            @test hy_given_x[x, y] ≈ - h_y_x atol=1e-12
        end
    end
end

@testset "Information Theory Test" begin
    conditional_entropy_test()
end


text:
using PyCall
@pyimport igraph

"""
This function computes a graph layout of a sparse matrix
by calling igraph via the python interface, so you must
have PyCall installed in Julia and
python-igraph installed as well. There are a bunch
of pip modules called igraph, only one of which
is the right one, so use
    pip install python-igraph
if you aren't sure!

@param A - the input sparse matrix, the values are ignored, it is treated as a directed graph
@param layoutname - an igraph layout, e.g.

    bipartite: bipartite layout
    circle, circular: circular layout
    drl: DrL layout for large graphs
    drl_3d: 3D DrL layout for large graphs
    fr, fruchterman_reingold: Fruchterman-Reingold layout
    fr_3d, fr3d, fruchterman_reingold_3d: 3D Fruchterman-Reingold layout
    grid: regular grid layout in 2D
    grid_3d: regular grid layout in 3D
    graphopt: the graphopt algorithm
    gfr, grid_fr, grid_fruchterman_reingold: grid-based Fruchterman-Reingold layout
    kk, kamada_kawai: Kamada-Kawai layout
    kk_3d, kk3d, kamada_kawai_3d: 3D Kamada-Kawai layout
    lgl, large, large_graph: Large Graph Layout
    mds: multidimensional scaling layout
    random: random layout
    random_3d: random 3D layout
    rt, tree, reingold_tilford:
    rt_circular, reingold_tilford_circular: circular Reingold-Tilford tree layout
    sphere, spherical, circle_3d, circular_3d: spherical layout
    star: star layout
    sugiyama: Sugiyama layout

(copied from igraph documentation)
"""
function igraph_layout{T}(A::SparseMatrixCSC{T}, layoutname::AbstractString="auto")
    (ei,ej) = findnz(A)
    edgelist = [(ei[i]-1,ej[i]-1) for i = 1:length(ei)]
    nverts = size(A)
    G = igraph.Graph(nverts, edges=edgelist, directed=true)
    xy = G[:layout](layoutname)
    xy = [ Float64(xy[i][j]) for i in 1:length(xy),  j in 1:length(xy[1])]
end

export igraph_layout


text:
int main() {
  int x, y;

  x = (y = 3);
  printInt(x);
  printInt(y);

  x = (x = x + 1) + x;
  printInt(x);

  boolean b = true;
  while ((b = false) == true) {
    printString("nope");
  }

  if (b = !b) {
    printString("yay!");
  }
  return 0;
}

max_stars_repo_name: jwilk/jtc

max_issues_repo_name: jwilk/jtc

max_forks_repo_name: jwilk/jtc