text:
# Abstract base type - all containers that want to use these features must inherit from it
abstract type AbstractContainer end

# Generic functions for which concrete containers must add implementations
function invalidate! end
function raw_copy! end
function move_connectivity! end
function delete_connectivity! end
function reset_data_structures! end

# Auxiliary copy function to copy data between containers
function copy_data!(target::AbstractArray, source::AbstractArray,
                    first::Int, last::Int, destination::Int, block_size::Int=1)
  count = last - first + 1
  if destination <= first || destination > last
    # In this case it is safe to copy forward (left-to-right) without overwriting data
    for i in 0:(count-1), j in 1:block_size
      target[block_size*(destination+i-1) + j] = source[block_size*(first+i-1) + j]
    end
  else
    # In this case we need to copy backward (right-to-left) to prevent overwriting data
    for i in (count-1):-1:0, j in 1:block_size
      target[block_size*(destination+i-1) + j] = source[block_size*(first+i-1) + j]
    end
  end

  return target
end

# Inquire about capacity and size
capacity(c::AbstractContainer) = c.capacity
Base.length(c::AbstractContainer) = c.length
Base.size(c::AbstractContainer) = (length(c),)

"""
    resize!(c::AbstractContainer, new_length) -> AbstractContainer

Resize `c` to contain `new_length` elements. If `new_length` is smaller than the current container
length, the first `new_length` elements will be retained. If `new_length` is
larger, the new elements are invalidated.
"""
function Base.resize!(c::AbstractContainer, new_length)
  @assert new_length >= zero(new_length) "New length must be >= 0"
  @assert new_length <= capacity(c) "New length would exceed capacity"

  # If new length is greater than current length, append to container.
  # If new length is less than current length, shrink container.
  # If new length is equal to current length, do nothing.
  if new_length > length(c)
    # First, invalidate range (to be sure that no sensible values are accidentally left there)
    invalidate!(c, length(c) + 1, new_length)

    # Then, set new container length
    c.length = new_length
  elseif new_length < length(c)
    # Rely on remove&shift to do The Right Thing (`remove_shift!` also updates the length)
    remove_shift!(c, new_length + 1, length(c))
  end

  return c
end

# Copy data range from source to target container.
#
# Calls `raw_copy` internally, which must be implemented for each concrete type
# inheriting from AbstractContainer.
# TODO: Shall we extend Base.copyto! ?
function Trixi.copy!(target::AbstractContainer, source::AbstractContainer,
               first::Int, last::Int, destination::Int)
  @assert 1 <= first <= length(source) "First cell out of range"
  @assert 1 <= last <= length(source) "Last cell out of range"
  @assert 1 <= destination <= length(target) "Destination out of range"
  @assert destination + (last - first) <= length(target) "Target range out of bounds"

  # Return if copy would be a no-op
  if last < first || (source === target && first == destination)
    return target
  end

  raw_copy!(target, source, first, last, destination)

  return target
end

# Convenience method to copy a single element
function Trixi.copy!(target::AbstractContainer, source::AbstractContainer, from::Int, destination::Int)
  Trixi.copy!(target, source, from, from, destination)
end

# Convenience method for copies within a single container
function Trixi.copy!(c::AbstractContainer, first::Int, last::Int, destination::Int)
  Trixi.copy!(c, c, first, last, destination)
end

# Convenience method for copying a single element within a single container
function Trixi.copy!(c::AbstractContainer, from::Int, destination::Int)
  Trixi.copy!(c, c, from, from, destination)
end

# Move elements in a way that preserves connectivity.
function move!(c::AbstractContainer, first::Int, last::Int, destination::Int)
  @assert 1 <= first <= length(c) "First cell $first out of range"
  @assert 1 <= last <= length(c) "Last cell $last out of range"
  @assert 1 <= destination <= length(c) "Destination $destination out of range"
  @assert destination + (last - first) <= length(c) "Target range out of bounds"

  # Return if move would be a no-op
  if last < first || first == destination
    return c
  end

  # Copy cells to new location
  raw_copy!(c, first, last, destination)

  # Move connectivity
  move_connectivity!(c, first, last, destination)

  # Invalidate original cell locations (unless they already contain new data due to overlap)
  # 1) If end of desination range is within original range, shift first_invalid to the right
  count = last - first + 1
  first_invalid = (first <= destination + count - 1 <= last) ? destination + count : first
  # 2) If beginning of destination range is within original range, shift last_invalid to the left
  last_invalid = (first <= destination <= last) ? destination - 1 : last
  # 3) Invalidate range
  invalidate!(c, first_invalid, last_invalid)

  return c
end
move!(c::AbstractContainer, from::Int, destination::Int) = move!(c, from, from, destination)

# Default implementation for moving a single element
function move_connectivity!(c::AbstractContainer, from::Int, destination::Int)
  return move_connectivity!(c, from, from, destination)
end

# Default implementation for invalidating a single element
function invalidate!(c::AbstractContainer, id::Int)
  return invalidate!(c, id, id)
end

# Swap two elements in a container while preserving element connectivity.
function swap!(c::AbstractContainer, a::Int, b::Int)
  @assert 1 <= a <= length(c) "a out of range"
  @assert 1 <= b <= length(c) "b out of range"

  # Return if swap would be a no-op
  if a == b
    return c
  end

  # Move a to dummy location
  raw_copy!(c, a, c.dummy)
  move_connectivity!(c, a, c.dummy)

  # Move b to a
  raw_copy!(c, b, a)
  move_connectivity!(c, b, a)

  # Move from dummy location to b
  raw_copy!(c, c.dummy, b)
  move_connectivity!(c, c.dummy, b)

  # Invalidate dummy to be sure
  invalidate!(c, c.dummy)

  return c
end

# Insert blank elements in container, shifting the following elements back.
#
# After a call to insert!, the range `position:position + count - 1` will be available for use.
# TODO: Shall we extend Base.insert! ?
function insert!(c::AbstractContainer, position::Int, count::Int)
  @assert 1 <= position <= length(c) + 1 "Insert position out of range"
  @assert count >= 0 "Count must be non-negative"
  @assert count + length(c) <= capacity(c) "New length would exceed capacity"

  # Return if insertation would be a no-op
  if count == 0
    return c
  end

  # Append and return if insertion is beyond last current element
  if position == length(c) + 1
    resize!(c, length(c) + count)
    return c
  end

  # Increase length
  c.length += count

  # Move original cells that currently occupy the insertion region, unless
  # insert position is one beyond previous length
  if position <= length(c) - count
    move!(c, position, length(c) - count, position + count)
  end

  return c
end

# Erase elements from container, deleting their connectivity and then invalidating their data.
# TODO: Shall we extend Base.deleteat! or Base.delete! ?
function erase!(c::AbstractContainer, first::Int, last::Int)
  @assert 1 <= first <= length(c) "First cell out of range"
  @assert 1 <= last <= length(c) "Last cell out of range"

  # Return if eraseure would be a no-op
  if last < first
    return c
  end

  # Delete connectivity and invalidate cells
  delete_connectivity!(c, first, last)
  invalidate!(c, first, last)

  return c
end
erase!(c::AbstractContainer, id::Int) = erase!(c, id, id)

# Remove cells and shift existing cells forward to close the gap
function remove_shift!(c::AbstractContainer, first::Int, last::Int)
  @assert 1 <= first <= length(c) "First cell out of range"
  @assert 1 <= last <= length(c) "Last cell out of range"

  # Return if removal would be a no-op
  if last < first
    return c
  end

  # Delete connectivity of cells to be removed
  delete_connectivity!(c, first, last)

  if last == length(c)
    # If everything up to the last cell is removed, no shifting is required
    invalidate!(c, first, last)
  else
    # Otherwise, the corresponding cells are moved forward
    move!(c, last + 1, length(c), first)
  end

  # Reduce length
  count = last - first + 1
  c.length -= count

  return c
end
remove_shift!(c::AbstractContainer, id::Int) = remove_shift!(c, id, id)

# Remove cells and fill gap with cells from the end of the container (to reduce copy operations)
function remove_fill!(c::AbstractContainer, first::Int, last::Int)
  @assert 1 <= first <= length(c) "First cell out of range"
  @assert 1 <= last <= length(c) "Last cell out of range"

  # Return if removal would be a no-op
  if last < first
    return c
  end

  # Delete connectivity of cells to be removed and then invalidate them
  delete_connectivity!(c, first, last)
  invalidate!(c, first, last)

  # Copy cells from end (unless last is already the last cell)
  count = last - first + 1
  if last < length(c)
    move!(c, max(length(c) - count + 1, last + 1), length(c), first)
  end

  # Reduce length
  c.length -= count

  return c
end

# Reset container to zero-length and with a new capacity
function reset!(c::AbstractContainer, capacity::Int)
  @assert capacity >=0

  c.capacity = capacity
  c.length = 0
  c.dummy = capacity + 1
  reset_data_structures!(c)

  return c
end

# Invalidate all elements and set length to zero.
function clear!(c::AbstractContainer)
  invalidate!(c)
  c.length = 0

  return c
end

# Helpful overloads for `raw_copy`
function raw_copy!(c::AbstractContainer, first::Int, last::Int, destination::Int)
  raw_copy!(c, c, first, last, destination)
end
function raw_copy!(target::AbstractContainer, source::AbstractContainer, from::Int, destination::Int)
  raw_copy!(target, source, from, from, destination)
end
function raw_copy!(c::AbstractContainer, from::Int, destination::Int)
  raw_copy!(c, c, from, from, destination)
end


text:
@testset "minimal.powRev1_test" begin
    # powRev1 [empty] [empty] [empty] = [empty]
    # powRev1 [empty] [entire] [empty] = [empty]
    # powRev1 [entire] [empty] [empty] = [empty]
    # powRev1 [entire] [entire] [empty] = [empty]
    # powRev1 [empty] [empty] [entire] = [empty]
    # powRev1 [empty] [entire] [entire] = [empty]
    # powRev1 [entire] [empty] [entire] = [empty]
    # powRev1 [entire] [entire] [entire] = [0.0, infinity]
    # powRev1 [entire] [entire] [-infinity,-1.0] = [empty]
    # powRev1 [-infinity,-1.0] [entire] [-infinity,0.0] = [empty]
    # powRev1 [-infinity,0.0] [entire] [-infinity,0.0] = [empty]
    # powRev1 [-infinity,0.0] [-infinity,0.0] [entire] = [empty]
    # powRev1 [-infinity,0.0] [-infinity,0.9] [0.0,1.0] = [empty]
    # powRev1 [-infinity,0.0] [1.1,infinity] [1.0,infinity] = [empty]
    # powRev1 [0.0,infinity] [1.1,infinity] [0.0,1.0] = [empty]
    # powRev1 [0.0,infinity] [-infinity,0.9] [1.0,infinity] = [empty]
    # powRev1 [0.0,0.0] [1.0,1.0] [-infinity,0.0] = [empty]
    # powRev1 [entire] [0.0,0.0] [entire] = [0.0,0.0]
    # powRev1 [entire] [-infinity,0.0] [entire] = [0.0,0.0]
    # powRev1 [0.0,infinity] [-infinity,0.0] [entire] = [0.0,0.0]
    # powRev1 [0.0,infinity] [0.0,0.0] [entire] = [0.0,0.0]
    # powRev1 [1.0,2.0] [0.0,0.0] [entire] = [0.0,0.0]
    # powRev1 [1.0,1.0] [0.0,0.0] [0.0,0.0] = [0.0,0.0]
    # powRev1 [entire] [1.0,1.0] [1.0,1.0] = [1.0,1.0]
    # powRev1 [0.0,0.0] [1.0,1.0] [entire] = [0.0,infinity]
    # powRev1 [0.0,0.0] [1.0,1.0] [2.0,3.0] = [2.0,3.0]
    # powRev1 [entire] [1.0,1.0] [entire] = [0.0,infinity]
    # powRev1 [entire] [1.0,1.0] [20.0,30.0] = [20.0,30.0]
    # powRev1 [0.0,0.0] [1.0,1.0] [1.0,1.0] = [1.0,1.0]
    # powRev1 [-4.0,-2.0] [0.0,0.5] [entire] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [-infinity,-2.0] [0.0,0.5] [entire] = [1.0, infinity]
    # powRev1 [-4.0,-2.0] [-infinity,0.5] [entire] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [-infinity,-2.0] [-infinity,0.5] [entire] = [1.0, infinity]
    # powRev1 [-4.0,-2.0] [0.25,0.5] [entire] = [0x1.306FE0A31B715p0, 2.0]
    # powRev1 [-infinity,-2.0] [0.25,0.5] [entire] = [1.0, 2.0]
    # powRev1 [-4.0,-2.0] [0.25,1.0] [entire] = [1.0, 2.0]
    # powRev1 [-infinity,-2.0] [0.25,1.0] [entire] = [1.0, 2.0]
    # powRev1 [-4.0,-2.0] [1.0,1.0] [entire] = [1.0, 1.0]
    # powRev1 [-infinity,-2.0] [1.0,1.0] [entire] = [1.0, 1.0]
    # powRev1 [-4.0,-2.0] [0.0,1.0] [entire] = [1.0, infinity]
    # powRev1 [-infinity,-2.0] [0.0,1.0] [entire] = [1.0, infinity]
    # powRev1 [-4.0,-2.0] [0.0,2.0] [entire] = [0x1.6A09E667F3BCCp-1, infinity]
    # powRev1 [-infinity,-2.0] [0.0,2.0] [entire] = [0x1.6A09E667F3BCCp-1, infinity]
    # powRev1 [-4.0,-2.0] [0.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [-infinity,-2.0] [0.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [-4.0,-2.0] [-infinity,2.0] [entire] = [0x1.6A09E667F3BCCp-1, infinity]
    # powRev1 [-infinity,-2.0] [-infinity,2.0] [entire] = [0x1.6A09E667F3BCCp-1, infinity]
    # powRev1 [-4.0,-2.0] [-infinity,infinity] [entire] = [0.0, infinity]
    # powRev1 [-infinity,-2.0] [-infinity,infinity] [entire] = [0.0, infinity]
    # powRev1 [-4.0,-2.0] [0.5,2.0] [entire] = [0x1.6A09E667F3BCCp-1, 0x1.6A09E667F3BCDp0]
    # powRev1 [-infinity,-2.0] [0.5,2.0] [entire] = [0x1.6A09E667F3BCCp-1, 0x1.6A09E667F3BCDp0]
    # powRev1 [-4.0,-2.0] [0.5,infinity] [entire] = [0.0, 0x1.6A09E667F3BCDp0]
    # powRev1 [-infinity,-2.0] [0.5,infinity] [entire] = [0.0, 0x1.6A09E667F3BCDp0]
    # powRev1 [-4.0,-2.0] [1.0,2.0] [entire] = [0x1.6A09E667F3BCCp-1, 1.0]
    # powRev1 [-infinity,-2.0] [1.0,2.0] [entire] = [0x1.6A09E667F3BCCp-1, 1.0]
    # powRev1 [-4.0,-2.0] [1.0,infinity] [entire] = [0.0, 1.0]
    # powRev1 [-infinity,-2.0] [1.0,infinity] [entire] = [0.0, 1.0]
    # powRev1 [-4.0,-2.0] [2.0,4.0] [entire] = [0.5, 0x1.AE89F995AD3AEp-1]
    # powRev1 [-infinity,-2.0] [2.0,4.0] [entire] = [0.5, 1.0]
    # powRev1 [-4.0,-2.0] [2.0,infinity] [entire] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [-infinity,-2.0] [2.0,infinity] [entire] = [0.0, 1.0]
    # powRev1 [0.0,0.0] [0.0,0.5] [entire] = [empty]
    # powRev1 [0.0,0.0] [-infinity,0.5] [entire] = [empty]
    # powRev1 [0.0,0.0] [0.25,0.5] [entire] = [empty]
    # powRev1 [0.0,0.0] [0.25,1.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,0.0] [1.0,1.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,0.0] [0.0,1.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,0.0] [0.0,2.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,0.0] [0.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [0.0,0.0] [-infinity,2.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,0.0] [-infinity,infinity] [entire] = [0.0, infinity]
    # powRev1 [0.0,0.0] [0.5,2.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,0.0] [0.5,infinity] [entire] = [0.0, infinity]
    # powRev1 [0.0,0.0] [1.0,2.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,0.0] [1.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [0.0,0.0] [2.0,4.0] [entire] = [empty]
    # powRev1 [0.0,0.0] [2.0,infinity] [entire] = [empty]
    # powRev1 [-4.0,0.0] [0.0,0.5] [entire] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [-infinity,0.0] [0.0,0.5] [entire] = [1.0, infinity]
    # powRev1 [-4.0,0.0] [-infinity,0.5] [entire] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [-infinity,0.0] [-infinity,0.5] [entire] = [1.0, infinity]
    # powRev1 [-4.0,0.0] [0.25,0.5] [entire] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [-infinity,0.0] [0.25,0.5] [entire] = [1.0, infinity]
    # powRev1 [-4.0,0.0] [0.25,1.0] [entire] = [0.0, infinity]
    # powRev1 [-infinity,0.0] [0.25,1.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,0.0] [1.0,1.0] [entire] = [0.0, infinity]
    # powRev1 [-infinity,0.0] [1.0,1.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,0.0] [0.0,1.0] [entire] = [0.0, infinity]
    # powRev1 [-infinity,0.0] [0.0,1.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,0.0] [0.0,2.0] [entire] = [0.0, infinity]
    # powRev1 [-infinity,0.0] [0.0,2.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,0.0] [0.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [-infinity,0.0] [0.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [-4.0,0.0] [-infinity,2.0] [entire] = [0.0, infinity]
    # powRev1 [-infinity,0.0] [-infinity,2.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,0.0] [-infinity,infinity] [entire] = [0.0, infinity]
    # powRev1 [-infinity,0.0] [-infinity,infinity] [entire] = [0.0, infinity]
    # powRev1 [-4.0,0.0] [0.5,2.0] [entire] = [0.0, infinity]
    # powRev1 [-infinity,0.0] [0.5,2.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,0.0] [0.5,infinity] [entire] = [0.0, infinity]
    # powRev1 [-infinity,0.0] [0.5,infinity] [entire] = [0.0, infinity]
    # powRev1 [-4.0,0.0] [1.0,2.0] [entire] = [0.0, infinity]
    # powRev1 [-infinity,0.0] [1.0,2.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,0.0] [1.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [-infinity,0.0] [1.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [-4.0,0.0] [2.0,4.0] [entire] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [-infinity,0.0] [2.0,4.0] [entire] = [0.0, 1.0]
    # powRev1 [-4.0,0.0] [2.0,infinity] [entire] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [-infinity,0.0] [2.0,infinity] [entire] = [0.0, 1.0]
    # powRev1 [-4.0,4.0] [0.0,0.5] [entire] = [0.0, infinity]
    # powRev1 [-infinity,4.0] [0.0,0.5] [entire] = [0.0, infinity]
    # powRev1 [-4.0,4.0] [-infinity,0.5] [entire] = [0.0, infinity]
    # powRev1 [-infinity,4.0] [-infinity,0.5] [entire] = [0.0, infinity]
    # powRev1 [-4.0,infinity] [0.0,0.5] [entire] = [0.0, infinity]
    # powRev1 [entire] [0.0,0.5] [entire] = [0.0, infinity]
    # powRev1 [-4.0,infinity] [-infinity,0.5] [entire] = [0.0, infinity]
    # powRev1 [entire] [-infinity,0.5] [entire] = [0.0, infinity]
    # powRev1 [-4.0,4.0] [0.0,0.5] [0.0, 1.0] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [-infinity,4.0] [0.0,0.5] [0.0, 1.0] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [-4.0,4.0] [-infinity,0.5] [0.0, 1.0] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [-infinity,4.0] [-infinity,0.5] [0.0, 1.0] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [-4.0,infinity] [0.0,0.5] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [entire] [0.0,0.5] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-4.0,infinity] [-infinity,0.5] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [entire] [-infinity,0.5] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-4.0,4.0] [0.0,0.5] [1.0, infinity] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [-infinity,4.0] [0.0,0.5] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,4.0] [-infinity,0.5] [1.0, infinity] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [-infinity,4.0] [-infinity,0.5] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,infinity] [0.0,0.5] [1.0, infinity] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [entire] [0.0,0.5] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,infinity] [-infinity,0.5] [1.0, infinity] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [entire] [-infinity,0.5] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,4.0] [0.25,0.5] [entire] = [0.0, infinity]
    # powRev1 [-infinity,4.0] [0.25,0.5] [entire] = [0.0, infinity]
    # powRev1 [-4.0,infinity] [0.25,0.5] [entire] = [0.0, infinity]
    # powRev1 [entire] [0.25,0.5] [entire] = [0.0, infinity]
    # powRev1 [-4.0,4.0] [0.25,0.5] [0.0, 1.0] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [-infinity,4.0] [0.25,0.5] [0.0, 1.0] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [-4.0,infinity] [0.25,0.5] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [entire] [0.25,0.5] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-4.0,4.0] [0.25,0.5] [1.0, infinity] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [-infinity,4.0] [0.25,0.5] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,infinity] [0.25,0.5] [1.0, infinity] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [entire] [0.25,0.5] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,4.0] [0.25,1.0] [entire] = [0.0, infinity]
    # powRev1 [-infinity,4.0] [0.25,1.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,4.0] [1.0,1.0] [entire] = [0.0, infinity]
    # powRev1 [-infinity,4.0] [1.0,1.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,infinity] [0.25,1.0] [entire] = [0.0, infinity]
    # powRev1 [entire] [0.25,1.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,infinity] [1.0,1.0] [entire] = [0.0, infinity]
    # powRev1 [entire] [1.0,1.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,4.0] [0.25,1.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-infinity,4.0] [0.25,1.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-4.0,4.0] [1.0,1.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-infinity,4.0] [1.0,1.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-4.0,infinity] [0.25,1.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [entire] [0.25,1.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-4.0,infinity] [1.0,1.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [entire] [1.0,1.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-4.0,4.0] [0.25,1.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-infinity,4.0] [0.25,1.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,4.0] [1.0,1.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-infinity,4.0] [1.0,1.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,infinity] [0.25,1.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [entire] [0.25,1.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,infinity] [1.0,1.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [entire] [1.0,1.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,4.0] [0.0,1.0] [entire] = [0.0, infinity]
    # powRev1 [-infinity,4.0] [0.0,1.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,infinity] [0.0,1.0] [entire] = [0.0, infinity]
    # powRev1 [entire] [0.0,1.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,4.0] [0.0,1.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-infinity,4.0] [0.0,1.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-4.0,infinity] [0.0,1.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [entire] [0.0,1.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-4.0,4.0] [0.0,1.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-infinity,4.0] [0.0,1.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,infinity] [0.0,1.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [entire] [0.0,1.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,4.0] [0.0,2.0] [entire] = [0.0, infinity]
    # powRev1 [-infinity,4.0] [0.0,2.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,4.0] [0.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [-infinity,4.0] [0.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [-4.0,4.0] [-infinity,2.0] [entire] = [0.0, infinity]
    # powRev1 [-infinity,4.0] [-infinity,2.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,4.0] [-infinity,infinity] [entire] = [0.0, infinity]
    # powRev1 [-infinity,4.0] [-infinity,infinity] [entire] = [0.0, infinity]
    # powRev1 [-4.0,infinity] [0.0,2.0] [entire] = [0.0, infinity]
    # powRev1 [entire] [0.0,2.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,infinity] [0.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [entire] [0.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [-4.0,infinity] [-infinity,2.0] [entire] = [0.0, infinity]
    # powRev1 [entire] [-infinity,2.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,infinity] [-infinity,infinity] [entire] = [0.0, infinity]
    # powRev1 [entire] [-infinity,infinity] [entire] = [0.0, infinity]
    # powRev1 [-4.0,4.0] [0.0,2.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-infinity,4.0] [0.0,2.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-4.0,4.0] [0.0,infinity] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-infinity,4.0] [0.0,infinity] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-4.0,4.0] [-infinity,2.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-infinity,4.0] [-infinity,2.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-4.0,4.0] [-infinity,infinity] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-infinity,4.0] [-infinity,infinity] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-4.0,infinity] [0.0,2.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [entire] [0.0,2.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-4.0,infinity] [0.0,infinity] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [entire] [0.0,infinity] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-4.0,infinity] [-infinity,2.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [entire] [-infinity,2.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-4.0,infinity] [-infinity,infinity] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [entire] [-infinity,infinity] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [-4.0,4.0] [0.0,2.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-infinity,4.0] [0.0,2.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,4.0] [0.0,infinity] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-infinity,4.0] [0.0,infinity] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,4.0] [-infinity,2.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-infinity,4.0] [-infinity,2.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,4.0] [-infinity,infinity] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-infinity,4.0] [-infinity,infinity] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,infinity] [0.0,2.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [entire] [0.0,2.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,infinity] [0.0,infinity] [1.0, infinity] = [1.0, infinity]
    # powRev1 [entire] [0.0,infinity] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,infinity] [-infinity,2.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [entire] [-infinity,2.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,infinity] [-infinity,infinity] [1.0, infinity] = [1.0, infinity]
    # powRev1 [entire] [-infinity,infinity] [1.0, infinity] = [1.0, infinity]
    # powRev1 [-4.0,4.0] [0.5,2.0] [entire] = [0.0, infinity]
    # powRev1 [-infinity,4.0] [0.5,2.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,4.0] [0.5,infinity] [entire] = [0.0, infinity]
    # powRev1 [-infinity,4.0] [0.5,infinity] [entire] = [0.0, infinity]
    # powRev1 [-4.0,infinity] [0.5,2.0] [entire] = [0.0, infinity]
    # powRev1 [entire] [0.5,2.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,infinity] [0.5,infinity] [entire] = [0.0, infinity]
    # powRev1 [entire] [0.5,infinity] [entire] = [0.0, infinity]
    # powRev1 [-4.0,4.0] [0.5,2.0] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [-infinity,4.0] [0.5,2.0] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [-4.0,4.0] [0.5,infinity] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [-infinity,4.0] [0.5,infinity] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [-4.0,infinity] [0.5,2.0] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [entire] [0.5,2.0] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [-4.0,infinity] [0.5,infinity] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [entire] [0.5,infinity] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [-4.0,4.0] [0.5,2.0] [1.0,infinity] = [1.0, infinity]
    # powRev1 [-infinity,4.0] [0.5,2.0] [1.0,infinity] = [1.0, infinity]
    # powRev1 [-4.0,4.0] [0.5,infinity] [1.0,infinity] = [1.0, infinity]
    # powRev1 [-infinity,4.0] [0.5,infinity] [1.0,infinity] = [1.0, infinity]
    # powRev1 [-4.0,infinity] [0.5,2.0] [1.0,infinity] = [1.0, infinity]
    # powRev1 [entire] [0.5,2.0] [1.0,infinity] = [1.0, infinity]
    # powRev1 [-4.0,infinity] [0.5,infinity] [1.0,infinity] = [1.0, infinity]
    # powRev1 [entire] [0.5,infinity] [1.0,infinity] = [1.0, infinity]
    # powRev1 [-4.0,4.0] [1.0,2.0] [entire] = [0.0, infinity]
    # powRev1 [-infinity,4.0] [1.0,2.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,4.0] [1.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [-infinity,4.0] [1.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [-4.0,infinity] [1.0,2.0] [entire] = [0.0, infinity]
    # powRev1 [entire] [1.0,2.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,infinity] [1.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [entire] [1.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [-4.0,4.0] [1.0,2.0] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [-infinity,4.0] [1.0,2.0] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [-4.0,4.0] [1.0,infinity] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [-infinity,4.0] [1.0,infinity] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [-4.0,infinity] [1.0,2.0] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [entire] [1.0,2.0] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [-4.0,infinity] [1.0,infinity] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [entire] [1.0,infinity] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [-4.0,4.0] [1.0,2.0] [1.0,infinity] = [1.0, infinity]
    # powRev1 [-infinity,4.0] [1.0,2.0] [1.0,infinity] = [1.0, infinity]
    # powRev1 [-4.0,4.0] [1.0,infinity] [1.0,infinity] = [1.0, infinity]
    # powRev1 [-infinity,4.0] [1.0,infinity] [1.0,infinity] = [1.0, infinity]
    # powRev1 [-4.0,infinity] [1.0,2.0] [1.0,infinity] = [1.0, infinity]
    # powRev1 [entire] [1.0,2.0] [1.0,infinity] = [1.0, infinity]
    # powRev1 [-4.0,infinity] [1.0,infinity] [1.0,infinity] = [1.0, infinity]
    # powRev1 [entire] [1.0,infinity] [1.0,infinity] = [1.0, infinity]
    # powRev1 [-4.0,4.0] [2.0,4.0] [entire] = [0.0, infinity]
    # powRev1 [-infinity,4.0] [2.0,4.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,4.0] [2.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [-infinity,4.0] [2.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [-4.0,infinity] [2.0,4.0] [entire] = [0.0, infinity]
    # powRev1 [entire] [2.0,4.0] [entire] = [0.0, infinity]
    # powRev1 [-4.0,infinity] [2.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [entire] [2.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [-4.0,4.0] [2.0,4.0] [0.0,1.0] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [-infinity,4.0] [2.0,4.0] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [-4.0,4.0] [2.0,infinity] [0.0,1.0] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [-infinity,4.0] [2.0,infinity] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [-4.0,infinity] [2.0,4.0] [0.0,1.0] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [entire] [2.0,4.0] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [-4.0,infinity] [2.0,infinity] [0.0,1.0] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [entire] [2.0,infinity] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [-4.0,4.0] [2.0,4.0] [1.0,infinity] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [-infinity,4.0] [2.0,4.0] [1.0,infinity] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [-4.0,4.0] [2.0,infinity] [1.0,infinity] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [-infinity,4.0] [2.0,infinity] [1.0,infinity] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [-4.0,infinity] [2.0,4.0] [1.0,infinity] = [1.0, infinity]
    # powRev1 [entire] [2.0,4.0] [1.0,infinity] = [1.0, infinity]
    # powRev1 [-4.0,infinity] [2.0,infinity] [1.0,infinity] = [1.0, infinity]
    # powRev1 [entire] [2.0,infinity] [1.0,infinity] = [1.0, infinity]
    # powRev1 [0.0,4.0] [0.0,0.5] [entire] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [0.0,4.0] [-infinity,0.5] [entire] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [0.0,infinity] [0.0,0.5] [entire] = [0.0, 1.0]
    # powRev1 [0.0,infinity] [-infinity,0.5] [entire] = [0.0, 1.0]
    # powRev1 [0.0,4.0] [0.0,0.5] [0.0, 1.0] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [0.0,4.0] [-infinity,0.5] [0.0, 1.0] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [0.0,infinity] [0.0,0.5] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [0.0,infinity] [-infinity,0.5] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [0.0,4.0] [0.0,0.5] [1.0, infinity] = [empty]
    # powRev1 [0.0,4.0] [-infinity,0.5] [1.0, infinity] = [empty]
    # powRev1 [0.0,infinity] [0.0,0.5] [1.0, infinity] = [empty]
    # powRev1 [0.0,infinity] [-infinity,0.5] [1.0, infinity] = [empty]
    # powRev1 [0.0,4.0] [0.25,0.5] [entire] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [0.0,infinity] [0.25,0.5] [entire] = [0.0, 1.0]
    # powRev1 [0.0,4.0] [0.25,0.5] [0.0, 1.0] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [0.0,infinity] [0.25,0.5] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [0.0,4.0] [0.25,0.5] [1.0, infinity] = [empty]
    # powRev1 [0.0,infinity] [0.25,0.5] [1.0, infinity] = [empty]
    # powRev1 [0.0,4.0] [0.25,1.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,4.0] [1.0,1.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,infinity] [0.25,1.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,infinity] [1.0,1.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,4.0] [0.25,1.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [0.0,4.0] [1.0,1.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [0.0,infinity] [0.25,1.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [0.0,infinity] [1.0,1.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [0.0,4.0] [0.25,1.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [0.0,4.0] [1.0,1.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [0.0,infinity] [0.25,1.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [0.0,infinity] [1.0,1.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [0.0,4.0] [0.0,1.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,infinity] [0.0,1.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,4.0] [0.0,1.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [0.0,infinity] [0.0,1.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [0.0,4.0] [0.0,1.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [0.0,infinity] [0.0,1.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [0.0,4.0] [0.0,2.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,4.0] [0.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [0.0,4.0] [-infinity,2.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,4.0] [-infinity,infinity] [entire] = [0.0, infinity]
    # powRev1 [0.0,infinity] [0.0,2.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,infinity] [0.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [0.0,infinity] [-infinity,2.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,infinity] [-infinity,infinity] [entire] = [0.0, infinity]
    # powRev1 [0.0,4.0] [0.0,2.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [0.0,4.0] [0.0,infinity] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [0.0,4.0] [-infinity,2.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [0.0,4.0] [-infinity,infinity] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [0.0,infinity] [0.0,2.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [0.0,infinity] [0.0,infinity] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [0.0,infinity] [-infinity,2.0] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [0.0,infinity] [-infinity,infinity] [0.0, 1.0] = [0.0, 1.0]
    # powRev1 [0.0,4.0] [0.0,2.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [0.0,4.0] [0.0,infinity] [1.0, infinity] = [1.0, infinity]
    # powRev1 [0.0,4.0] [-infinity,2.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [0.0,4.0] [-infinity,infinity] [1.0, infinity] = [1.0, infinity]
    # powRev1 [0.0,infinity] [0.0,2.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [0.0,infinity] [0.0,infinity] [1.0, infinity] = [1.0, infinity]
    # powRev1 [0.0,infinity] [-infinity,2.0] [1.0, infinity] = [1.0, infinity]
    # powRev1 [0.0,infinity] [-infinity,infinity] [1.0, infinity] = [1.0, infinity]
    # powRev1 [0.0,4.0] [0.5,2.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,4.0] [0.5,infinity] [entire] = [0.0, infinity]
    # powRev1 [0.0,infinity] [0.5,2.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,infinity] [0.5,infinity] [entire] = [0.0, infinity]
    # powRev1 [0.0,4.0] [0.5,2.0] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [0.0,4.0] [0.5,infinity] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [0.0,infinity] [0.5,2.0] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [0.0,infinity] [0.5,infinity] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [0.0,4.0] [0.5,2.0] [1.0,infinity] = [1.0, infinity]
    # powRev1 [0.0,4.0] [0.5,infinity] [1.0,infinity] = [1.0, infinity]
    # powRev1 [0.0,infinity] [0.5,2.0] [1.0,infinity] = [1.0, infinity]
    # powRev1 [0.0,infinity] [0.5,infinity] [1.0,infinity] = [1.0, infinity]
    # powRev1 [0.0,4.0] [1.0,2.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,4.0] [1.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [0.0,infinity] [1.0,2.0] [entire] = [0.0, infinity]
    # powRev1 [0.0,infinity] [1.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [0.0,4.0] [1.0,2.0] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [0.0,4.0] [1.0,infinity] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [0.0,infinity] [1.0,2.0] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [0.0,infinity] [1.0,infinity] [0.0,1.0] = [0.0, 1.0]
    # powRev1 [0.0,4.0] [1.0,2.0] [1.0,infinity] = [1.0, infinity]
    # powRev1 [0.0,4.0] [1.0,infinity] [1.0,infinity] = [1.0, infinity]
    # powRev1 [0.0,infinity] [1.0,2.0] [1.0,infinity] = [1.0, infinity]
    # powRev1 [0.0,infinity] [1.0,infinity] [1.0,infinity] = [1.0, infinity]
    # powRev1 [0.0,4.0] [2.0,4.0] [entire] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [0.0,4.0] [2.0,infinity] [entire] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [0.0,infinity] [2.0,4.0] [entire] = [1.0, infinity]
    # powRev1 [0.0,infinity] [2.0,infinity] [entire] = [1.0, infinity]
    # powRev1 [0.0,4.0] [2.0,4.0] [0.0,1.0] = [empty]
    # powRev1 [0.0,4.0] [2.0,infinity] [0.0,1.0] = [empty]
    # powRev1 [0.0,infinity] [2.0,4.0] [0.0,1.0] = [empty]
    # powRev1 [0.0,infinity] [2.0,infinity] [0.0,1.0] = [empty]
    # powRev1 [0.0,4.0] [2.0,4.0] [1.0,infinity] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [0.0,4.0] [2.0,infinity] [1.0,infinity] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [0.0,infinity] [2.0,4.0] [1.0,infinity] = [1.0, infinity]
    # powRev1 [0.0,infinity] [2.0,infinity] [1.0,infinity] = [1.0, infinity]
    # powRev1 [2.0,4.0] [0.0,0.5] [entire] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [2.0,4.0] [-infinity,0.5] [entire] = [0.0, 0x1.AE89F995AD3AEp-1]
    # powRev1 [2.0,infinity] [0.0,0.5] [entire] = [0.0, 1.0]
    # powRev1 [2.0,infinity] [-infinity,0.5] [entire] = [0.0, 1.0]
    # powRev1 [2.0,4.0] [0.25,0.5] [entire] = [0.5, 0x1.AE89F995AD3AEp-1]
    # powRev1 [2.0,infinity] [0.25,0.5] [entire] = [0.5, 1.0]
    # powRev1 [2.0,4.0] [0.25,1.0] [entire] = [0.5, 1.0]
    # powRev1 [2.0,4.0] [1.0,1.0] [entire] = [1.0, 1.0]
    # powRev1 [2.0,infinity] [0.25,1.0] [entire] = [0.5, 1.0]
    # powRev1 [2.0,infinity] [1.0,1.0] [entire] = [1.0, 1.0]
    # powRev1 [2.0,4.0] [0.0,1.0] [entire] = [0.0, 1.0]
    # powRev1 [2.0,infinity] [0.0,1.0] [entire] = [0.0, 1.0]
    # powRev1 [2.0,4.0] [0.0,2.0] [entire] = [0.0, 0x1.6A09E667F3BCDp0]
    # powRev1 [2.0,4.0] [0.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [2.0,4.0] [-infinity,2.0] [entire] = [0.0, 0x1.6A09E667F3BCDp0]
    # powRev1 [2.0,4.0] [-infinity,infinity] [entire] = [0.0, infinity]
    # powRev1 [2.0,infinity] [0.0,2.0] [entire] = [0.0, 0x1.6A09E667F3BCDp0]
    # powRev1 [2.0,infinity] [0.0,infinity] [entire] = [0.0, infinity]
    # powRev1 [2.0,infinity] [-infinity,2.0] [entire] = [0.0, 0x1.6A09E667F3BCDp0]
    # powRev1 [2.0,infinity] [-infinity,infinity] [entire] = [0.0, infinity]
    # powRev1 [2.0,4.0] [0.5,2.0] [entire] = [0x1.6A09E667F3BCCp-1, 0x1.6A09E667F3BCDp0]
    # powRev1 [2.0,4.0] [0.5,infinity] [entire] = [0x1.6A09E667F3BCCp-1, infinity]
    # powRev1 [2.0,infinity] [0.5,2.0] [entire] = [0x1.6A09E667F3BCCp-1, 0x1.6A09E667F3BCDp0]
    # powRev1 [2.0,infinity] [0.5,infinity] [entire] = [0x1.6A09E667F3BCCp-1, infinity]
    # powRev1 [2.0,4.0] [1.0,2.0] [entire] = [1.0, 0x1.6A09E667F3BCDp0]
    # powRev1 [2.0,4.0] [1.0,infinity] [entire] = [1.0, infinity]
    # powRev1 [2.0,infinity] [1.0,2.0] [entire] = [1.0, 0x1.6A09E667F3BCDp0]
    # powRev1 [2.0,infinity] [1.0,infinity] [entire] = [1.0, infinity]
    # powRev1 [2.0,4.0] [2.0,4.0] [entire] = [0x1.306FE0A31B715p0, 2.0]
    # powRev1 [2.0,4.0] [2.0,infinity] [entire] = [0x1.306FE0A31B715p0, infinity]
    # powRev1 [2.0,infinity] [2.0,4.0] [entire] = [1.0, 2.0]
    # powRev1 [2.0,infinity] [2.0,infinity] [entire] = [1.0, infinity]
end

@testset "minimal.powRev2_test" begin
    # powRev2 [empty] [empty] [empty] = [empty]
    # powRev2 [empty] [entire] [empty] = [empty]
    # powRev2 [entire] [empty] [empty] = [empty]
    # powRev2 [entire] [entire] [empty] = [empty]
    # powRev2 [empty] [empty] [entire] = [empty]
    # powRev2 [empty] [entire] [entire] = [empty]
    # powRev2 [entire] [empty] [entire] = [empty]
    # powRev2 [entire] [entire] [entire] = [entire]
    # powRev2 [0.0, 0.0] [-infinity, -0.1] [entire] = [empty]
    # powRev2 [0.0, 0.0] [0.1, infinity] [entire] = [empty]
    # powRev2 [0.0, 0.0] [0.0, 0.0] [-infinity, 0.0] = [empty]
    # powRev2 [-infinity, 0.9] [0.0, 0.9] [-infinity, 0.0] = [empty]
    # powRev2 [1.1, infinity] [1.1, infinity] [-infinity, 0.0] = [empty]
    # powRev2 [-infinity, 0.9] [1.1, infinity] [0.0, infinity] = [empty]
    # powRev2 [1.1, infinity] [0.0, 0.9] [0.0, infinity] = [empty]
    # powRev2 [0.0, 0.0] [0.0, 0.0] [entire] = [0.0, infinity]
    # powRev2 [-infinity, 0.0] [-infinity, 0.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [-infinity, 0.0] [-infinity, 0.0] [1.0, 2.0] = [1.0, 2.0]
    # powRev2 [entire] [0.0, 0.0] [entire] = [0.0, infinity]
    # powRev2 [entire] [-infinity, 0.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [entire] [-infinity, 0.0] [1.0, 2.0] = [1.0, 2.0]
    # powRev2 [0.0, 0.0] [entire] [entire] = [0.0, infinity]
    # powRev2 [-infinity, 0.0] [entire] [0.0, infinity] = [0.0, infinity]
    # powRev2 [-infinity, 0.0] [entire] [1.0, 2.0] = [1.0, 2.0]
    # powRev2 [1.0, 1.0] [entire] [entire] = [entire]
    # powRev2 [1.0, 1.0] [1.0, 1.0] [entire] = [entire]
    # powRev2 [1.0, 1.0] [1.0, 1.0] [2.0, 3.0] = [2.0, 3.0]
    # powRev2 [entire] [1.0, 1.0] [entire] = [entire]
    # powRev2 [entire] [1.0, 1.0] [2.0, 3.0] = [2.0, 3.0]
    # powRev2 [2.0, 3.0] [1.0, 1.0] [entire] = [0.0, 0.0]
    # powRev2 [2.0, 3.0] [1.0, 1.0] [2.0, 3.0] = [empty]
    # powRev2 [0.0, 0.5] [0.0, 0.5] [entire] = [0.0, infinity]
    # powRev2 [0.0, 0.5] [0.0, 0.5] [-infinity, 0.0] = [empty]
    # powRev2 [0.0, 0.5] [0.25, 0.5] [entire] = [0.0, 2.0]
    # powRev2 [0.0, 0.25] [0.5, 1.0] [entire] = [0.0, 0.5]
    # powRev2 [0.0, 0.25] [1.0, 1.0] [entire] = [0.0, 0.0]
    # powRev2 [0.0, 0.25] [0.0, 1.0] [entire] = [0.0, infinity]
    # powRev2 [0.0, 0.25] [0.0, 1.0] [-infinity, 0.0] = [0.0, 0.0]
    # powRev2 [0.0, 0.25] [0.0, 2.0] [entire] = [-0.5, infinity]
    # powRev2 [0.0, 0.25] [0.0, infinity] [entire] = [entire]
    # powRev2 [0.0, 0.25] [0.5, 2.0] [entire] = [-0.5, 0.5]
    # powRev2 [0.0, 0.25] [0.5, infinity] [entire] = [-infinity, 0.5]
    # powRev2 [0.0, 0.25] [1.0, 2.0] [entire] = [-0.5, 0.0]
    # powRev2 [0.0, 0.25] [1.0, 2.0] [0.0, infinity] = [0.0, 0.0]
    # powRev2 [0.0, 0.25] [1.0, infinity] [entire] = [-infinity, 0.0]
    # powRev2 [0.0, 0.25] [1.0, infinity] [0.0, infinity] = [0.0, 0.0]
    # powRev2 [0.0, 0.25] [2.0, 4.0] [entire] = [-1.0, 0.0]
    # powRev2 [0.0, 0.25] [2.0, 4.0] [0.0, infinity] = [empty]
    # powRev2 [0.0, 0.25] [2.0, infinity] [entire] = [-infinity, 0.0]
    # powRev2 [0.0, 0.25] [2.0, infinity] [0.0, infinity] = [empty]
    # powRev2 [0.25, 0.5] [0.0, 0.5] [entire] = [0.5, infinity]
    # powRev2 [0.25, 0.5] [0.25, 0.5] [entire] = [0.5, 2.0]
    # powRev2 [0.25, 0.5] [0.5, 1.0] [entire] = [0.0, 1.0]
    # powRev2 [0.25, 0.5] [1.0, 1.0] [entire] = [0.0, 0.0]
    # powRev2 [0.25, 0.5] [0.0, 1.0] [entire] = [0.0, infinity]
    # powRev2 [0.25, 0.5] [0.0, 1.0] [-infinity, 0.0] = [0.0, 0.0]
    # powRev2 [0.25, 0.5] [0.0, 2.0] [entire] = [-1.0, infinity]
    # powRev2 [0.25, 0.5] [0.0, infinity] [entire] = [entire]
    # powRev2 [0.25, 0.5] [0.5, 2.0] [entire] = [-1.0, 1.0]
    # powRev2 [0.25, 0.5] [0.5, infinity] [entire] = [-infinity, 1.0]
    # powRev2 [0.25, 0.5] [1.0, 2.0] [entire] = [-1.0, 0.0]
    # powRev2 [0.25, 0.5] [1.0, infinity] [entire] = [-infinity, 0.0]
    # powRev2 [0.25, 0.5] [2.0, 4.0] [entire] = [-2.0, -0.5]
    # powRev2 [0.25, 0.5] [2.0, infinity] [entire] = [entire]
    # powRev2 [0.25, 1.0] [0.0, 0.5] [entire] = [0.5, infinity]
    # powRev2 [1.0, 1.0] [0.0, 0.5] [entire] = [empty]
    # powRev2 [0.25, 1.0] [0.25, 0.5] [entire] = [0.5, infinity]
    # powRev2 [1.0, 1.0] [0.25, 0.5] [entire] = [empty]
    # powRev2 [0.25, 1.0] [0.5, 1.0] [entire] = [entire]
    # powRev2 [0.25, 1.0] [1.0, 1.0] [entire] = [entire]
    # powRev2 [1.0, 1.0] [0.5, 1.0] [entire] = [entire]
    # powRev2 [1.0, 1.0] [1.0, 1.0] [entire] = [entire]
    # powRev2 [0.25, 1.0] [0.0, 1.0] [entire] = [entire]
    # powRev2 [1.0, 1.0] [0.0, 1.0] [entire] = [entire]
    # powRev2 [0.25, 1.0] [0.0, 2.0] [entire] = [entire]
    # powRev2 [1.0, 1.0] [0.0, 2.0] [entire] = [entire]
    # powRev2 [0.25, 1.0] [0.0, infinity] [entire] = [entire]
    # powRev2 [1.0, 1.0] [0.0, infinity] [entire] = [entire]
    # powRev2 [0.25, 1.0] [0.5, 2.0] [entire] = [entire]
    # powRev2 [1.0, 1.0] [0.5, 2.0] [entire] = [entire]
    # powRev2 [0.25, 1.0] [0.5, infinity] [entire] = [entire]
    # powRev2 [1.0, 1.0] [0.5, infinity] [entire] = [entire]
    # powRev2 [0.25, 1.0] [1.0, 2.0] [entire] = [entire]
    # powRev2 [1.0, 1.0] [1.0, 2.0] [entire] = [entire]
    # powRev2 [0.25, 1.0] [1.0, infinity] [entire] = [entire]
    # powRev2 [1.0, 1.0] [1.0, infinity] [entire] = [entire]
    # powRev2 [0.25, 1.0] [2.0, 4.0] [entire] = [-infinity, -0.5]
    # powRev2 [1.0, 1.0] [2.0, 4.0] [entire] = [empty]
    # powRev2 [0.25, 1.0] [2.0, infinity] [entire] = [-infinity, 0.0]
    # powRev2 [1.0, 1.0] [2.0, infinity] [entire] = [empty]
    # powRev2 [0.0, 1.0] [0.0, 0.5] [entire] = [0.0, infinity]
    # powRev2 [0.0, 1.0] [0.0, 0.5] [-infinity, 0.0] = [empty]
    # powRev2 [0.0, 1.0] [0.0, 0.5] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 1.0] [0.25, 0.5] [entire] = [0.0, infinity]
    # powRev2 [0.0, 1.0] [0.25, 0.5] [-infinity, 0.0] = [empty]
    # powRev2 [0.0, 1.0] [0.25, 0.5] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 1.0] [0.5, 1.0] [entire] = [entire]
    # powRev2 [0.0, 1.0] [1.0, 1.0] [entire] = [entire]
    # powRev2 [0.0, 1.0] [0.5, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 1.0] [1.0, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 1.0] [0.5, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 1.0] [1.0, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 1.0] [0.0, 1.0] [entire] = [entire]
    # powRev2 [0.0, 1.0] [0.0, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 1.0] [0.0, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 1.0] [0.0, 2.0] [entire] = [entire]
    # powRev2 [0.0, 1.0] [0.0, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 1.0] [0.0, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 1.0] [0.0, infinity] [entire] = [entire]
    # powRev2 [0.0, 1.0] [0.0, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 1.0] [0.0, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 1.0] [0.5, 2.0] [entire] = [entire]
    # powRev2 [0.0, 1.0] [0.5, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 1.0] [0.5, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 1.0] [0.5, infinity] [entire] = [entire]
    # powRev2 [0.0, 1.0] [0.5, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 1.0] [0.5, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 1.0] [1.0, 2.0] [entire] = [entire]
    # powRev2 [0.0, 1.0] [1.0, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 1.0] [1.0, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 1.0] [1.0, infinity] [entire] = [entire]
    # powRev2 [0.0, 1.0] [1.0, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 1.0] [1.0, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 1.0] [2.0, 4.0] [entire] = [-infinity, 0.0]
    # powRev2 [0.0, 1.0] [2.0, 4.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 1.0] [2.0, 4.0] [0.0, infinity] = [empty]
    # powRev2 [0.0, 1.0] [2.0, infinity] [entire] = [-infinity, 0.0]
    # powRev2 [0.0, 1.0] [2.0, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 1.0] [2.0, infinity] [0.0, infinity] = [empty]
    # powRev2 [0.0, 2.0] [0.0, 0.5] [entire] = [entire]
    # powRev2 [0.0, 2.0] [0.0, 0.5] [-infinity, 0.0] = [-infinity, -1.0]
    # powRev2 [0.0, 2.0] [0.0, 0.5] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, infinity] [0.0, 0.5] [entire] = [entire]
    # powRev2 [0.0, infinity] [0.0, 0.5] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, infinity] [0.0, 0.5] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 2.0] [0.25, 0.5] [entire] = [entire]
    # powRev2 [0.0, 2.0] [0.25, 0.5] [-infinity, 0.0] = [-infinity, -1.0]
    # powRev2 [0.0, 2.0] [0.25, 0.5] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, infinity] [0.25, 0.5] [entire] = [entire]
    # powRev2 [0.0, infinity] [0.25, 0.5] [-infinity, 0.0] = [-infinity, -0.0]
    # powRev2 [0.0, infinity] [0.25, 0.5] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 2.0] [0.5, 1.0] [entire] = [entire]
    # powRev2 [0.0, 2.0] [1.0, 1.0] [entire] = [entire]
    # powRev2 [0.0, 2.0] [0.5, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 2.0] [1.0, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 2.0] [0.5, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 2.0] [1.0, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, infinity] [0.5, 1.0] [entire] = [entire]
    # powRev2 [0.0, infinity] [1.0, 1.0] [entire] = [entire]
    # powRev2 [0.0, infinity] [0.5, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, infinity] [1.0, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, infinity] [0.5, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, infinity] [1.0, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 2.0] [0.0, 1.0] [entire] = [entire]
    # powRev2 [0.0, 2.0] [0.0, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 2.0] [0.0, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, infinity] [0.0, 1.0] [entire] = [entire]
    # powRev2 [0.0, infinity] [0.0, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, infinity] [0.0, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 2.0] [0.0, 2.0] [entire] = [entire]
    # powRev2 [0.0, 2.0] [0.0, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 2.0] [0.0, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, infinity] [0.0, 2.0] [entire] = [entire]
    # powRev2 [0.0, infinity] [0.0, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, infinity] [0.0, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 2.0] [0.0, infinity] [entire] = [entire]
    # powRev2 [0.0, 2.0] [0.0, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 2.0] [0.0, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, infinity] [0.0, infinity] [entire] = [entire]
    # powRev2 [0.0, infinity] [0.0, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, infinity] [0.0, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 2.0] [0.5, 2.0] [entire] = [entire]
    # powRev2 [0.0, 2.0] [0.5, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 2.0] [0.5, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, infinity] [0.5, 2.0] [entire] = [entire]
    # powRev2 [0.0, infinity] [0.5, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, infinity] [0.5, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 2.0] [0.5, infinity] [entire] = [entire]
    # powRev2 [0.0, 2.0] [0.5, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 2.0] [0.5, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, infinity] [0.5, infinity] [entire] = [entire]
    # powRev2 [0.0, infinity] [0.5, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, infinity] [0.5, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 2.0] [1.0, 2.0] [entire] = [entire]
    # powRev2 [0.0, 2.0] [1.0, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 2.0] [1.0, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, infinity] [1.0, 2.0] [entire] = [entire]
    # powRev2 [0.0, infinity] [1.0, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, infinity] [1.0, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 2.0] [1.0, infinity] [entire] = [entire]
    # powRev2 [0.0, 2.0] [1.0, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 2.0] [1.0, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, infinity] [1.0, infinity] [entire] = [entire]
    # powRev2 [0.0, infinity] [1.0, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, infinity] [1.0, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 2.0] [2.0, 4.0] [entire] = [entire]
    # powRev2 [0.0, 2.0] [2.0, 4.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 2.0] [2.0, 4.0] [0.0, infinity] = [1.0, infinity]
    # powRev2 [0.0, infinity] [2.0, 4.0] [entire] = [entire]
    # powRev2 [0.0, infinity] [2.0, 4.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, infinity] [2.0, 4.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.0, 2.0] [2.0, infinity] [entire] = [entire]
    # powRev2 [0.0, 2.0] [2.0, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, 2.0] [2.0, infinity] [0.0, infinity] = [1.0, infinity]
    # powRev2 [0.0, infinity] [2.0, infinity] [entire] = [entire]
    # powRev2 [0.0, infinity] [2.0, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.0, infinity] [2.0, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, 2.0] [0.0, 0.5] [entire] = [entire]
    # powRev2 [0.5, 2.0] [0.0, 0.5] [-infinity, 0.0] = [-infinity, -1.0]
    # powRev2 [0.5, 2.0] [0.0, 0.5] [0.0, infinity] = [1.0, infinity]
    # powRev2 [0.5, infinity] [0.0, 0.5] [entire] = [entire]
    # powRev2 [0.5, infinity] [0.0, 0.5] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, infinity] [0.0, 0.5] [0.0, infinity] = [1.0, infinity]
    # powRev2 [0.5, 2.0] [0.25, 0.5] [entire] = [entire]
    # powRev2 [0.5, 2.0] [0.25, 0.5] [-infinity, 0.0] = [-infinity, -1.0]
    # powRev2 [0.5, 2.0] [0.25, 0.5] [0.0, infinity] = [1.0, infinity]
    # powRev2 [0.5, infinity] [0.25, 0.5] [entire] = [entire]
    # powRev2 [0.5, infinity] [0.25, 0.5] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, infinity] [0.25, 0.5] [0.0, infinity] = [1.0, infinity]
    # powRev2 [0.5, 2.0] [0.5, 1.0] [entire] = [entire]
    # powRev2 [0.5, 2.0] [1.0, 1.0] [entire] = [entire]
    # powRev2 [0.5, 2.0] [0.5, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, 2.0] [1.0, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, 2.0] [0.5, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, 2.0] [1.0, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, infinity] [0.5, 1.0] [entire] = [entire]
    # powRev2 [0.5, infinity] [1.0, 1.0] [entire] = [entire]
    # powRev2 [0.5, infinity] [0.5, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, infinity] [1.0, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, infinity] [0.5, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, infinity] [1.0, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, 2.0] [0.0, 1.0] [entire] = [entire]
    # powRev2 [0.5, 2.0] [0.0, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, 2.0] [0.0, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, infinity] [0.0, 1.0] [entire] = [entire]
    # powRev2 [0.5, infinity] [0.0, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, infinity] [0.0, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, 2.0] [0.0, 2.0] [entire] = [entire]
    # powRev2 [0.5, 2.0] [0.0, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, 2.0] [0.0, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, infinity] [0.0, 2.0] [entire] = [entire]
    # powRev2 [0.5, infinity] [0.0, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, infinity] [0.0, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, 2.0] [0.0, infinity] [entire] = [entire]
    # powRev2 [0.5, 2.0] [0.0, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, 2.0] [0.0, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, infinity] [0.0, infinity] [entire] = [entire]
    # powRev2 [0.5, infinity] [0.0, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, infinity] [0.0, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, 2.0] [0.5, 2.0] [entire] = [entire]
    # powRev2 [0.5, 2.0] [0.5, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, 2.0] [0.5, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, infinity] [0.5, 2.0] [entire] = [entire]
    # powRev2 [0.5, infinity] [0.5, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, infinity] [0.5, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, 2.0] [0.5, infinity] [entire] = [entire]
    # powRev2 [0.5, 2.0] [0.5, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, 2.0] [0.5, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, infinity] [0.5, infinity] [entire] = [entire]
    # powRev2 [0.5, infinity] [0.5, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, infinity] [0.5, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, 2.0] [1.0, 2.0] [entire] = [entire]
    # powRev2 [0.5, 2.0] [1.0, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, 2.0] [1.0, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, infinity] [1.0, 2.0] [entire] = [entire]
    # powRev2 [0.5, infinity] [1.0, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, infinity] [1.0, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, 2.0] [1.0, infinity] [entire] = [entire]
    # powRev2 [0.5, 2.0] [1.0, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, 2.0] [1.0, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, infinity] [1.0, infinity] [entire] = [entire]
    # powRev2 [0.5, infinity] [1.0, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [0.5, infinity] [1.0, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [0.5, 2.0] [2.0, 4.0] [entire] = [entire]
    # powRev2 [0.5, 2.0] [2.0, 4.0] [-infinity, 0.0] = [-infinity, -1.0]
    # powRev2 [0.5, 2.0] [2.0, 4.0] [0.0, infinity] = [1.0, infinity]
    # powRev2 [0.5, infinity] [2.0, 4.0] [entire] = [entire]
    # powRev2 [0.5, infinity] [2.0, 4.0] [-infinity, 0.0] = [-infinity, -1.0]
    # powRev2 [0.5, infinity] [2.0, 4.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [1.0, 2.0] [0.0, 0.5] [entire] = [-infinity, -1.0]
    # powRev2 [1.0, 2.0] [0.0, 0.5] [-infinity, 0.0] = [-infinity, -1.0]
    # powRev2 [1.0, 2.0] [0.0, 0.5] [0.0, infinity] = [empty]
    # powRev2 [1.0, infinity] [0.0, 0.5] [entire] = [-infinity, 0.0]
    # powRev2 [1.0, infinity] [0.0, 0.5] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [1.0, infinity] [0.0, 0.5] [0.0, infinity] = [empty]
    # powRev2 [1.0, 2.0] [0.25, 0.5] [entire] = [-infinity, -1.0]
    # powRev2 [1.0, 2.0] [0.25, 0.5] [-infinity, 0.0] = [-infinity, -1.0]
    # powRev2 [1.0, 2.0] [0.25, 0.5] [0.0, infinity] = [empty]
    # powRev2 [1.0, infinity] [0.25, 0.5] [entire] = [-infinity, 0.0]
    # powRev2 [1.0, infinity] [0.25, 0.5] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [1.0, infinity] [0.25, 0.5] [0.0, infinity] = [empty]
    # powRev2 [1.0, 2.0] [0.5, 1.0] [entire] = [entire]
    # powRev2 [1.0, 2.0] [1.0, 1.0] [entire] = [entire]
    # powRev2 [1.0, 2.0] [0.5, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [1.0, 2.0] [1.0, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [1.0, 2.0] [0.5, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [1.0, 2.0] [1.0, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [1.0, infinity] [0.5, 1.0] [entire] = [entire]
    # powRev2 [1.0, infinity] [1.0, 1.0] [entire] = [entire]
    # powRev2 [1.0, infinity] [0.5, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [1.0, infinity] [1.0, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [1.0, infinity] [0.5, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [1.0, infinity] [1.0, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [1.0, 2.0] [0.0, 1.0] [entire] = [entire]
    # powRev2 [1.0, 2.0] [0.0, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [1.0, 2.0] [0.0, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [1.0, infinity] [0.0, 1.0] [entire] = [entire]
    # powRev2 [1.0, infinity] [0.0, 1.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [1.0, infinity] [0.0, 1.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [1.0, 2.0] [0.0, 2.0] [entire] = [entire]
    # powRev2 [1.0, 2.0] [0.0, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [1.0, 2.0] [0.0, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [1.0, infinity] [0.0, 2.0] [entire] = [entire]
    # powRev2 [1.0, infinity] [0.0, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [1.0, infinity] [0.0, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [1.0, 2.0] [0.0, infinity] [entire] = [entire]
    # powRev2 [1.0, 2.0] [0.0, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [1.0, 2.0] [0.0, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [1.0, infinity] [0.0, infinity] [entire] = [entire]
    # powRev2 [1.0, infinity] [0.0, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [1.0, infinity] [0.0, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [1.0, 2.0] [0.5, 2.0] [entire] = [entire]
    # powRev2 [1.0, 2.0] [0.5, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [1.0, 2.0] [0.5, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [1.0, infinity] [0.5, 2.0] [entire] = [entire]
    # powRev2 [1.0, infinity] [0.5, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [1.0, infinity] [0.5, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [1.0, 2.0] [0.5, infinity] [entire] = [entire]
    # powRev2 [1.0, 2.0] [0.5, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [1.0, 2.0] [0.5, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [1.0, infinity] [0.5, infinity] [entire] = [entire]
    # powRev2 [1.0, infinity] [0.5, infinity] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [1.0, infinity] [0.5, infinity] [0.0, infinity] = [0.0, infinity]
    # powRev2 [1.0, 2.0] [1.0, 2.0] [entire] = [entire]
    # powRev2 [1.0, 2.0] [1.0, infinity] [entire] = [entire]
    # powRev2 [1.0, infinity] [1.0, infinity] [entire] = [entire]
    # powRev2 [1.0, infinity] [1.0, 2.0] [entire] = [entire]
    # powRev2 [1.0, 2.0] [1.0, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [1.0, infinity] [1.0, 2.0] [-infinity, 0.0] = [-infinity, 0.0]
    # powRev2 [1.0, 2.0] [1.0, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [1.0, infinity] [1.0, 2.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [1.0, 2.0] [2.0, 4.0] [entire] = [1.0, infinity]
    # powRev2 [1.0, infinity] [2.0, 4.0] [entire] = [0.0, infinity]
    # powRev2 [1.0, 2.0] [2.0, 4.0] [-infinity, 0.0] = [empty]
    # powRev2 [1.0, infinity] [2.0, 4.0] [-infinity, 0.0] = [empty]
    # powRev2 [1.0, 2.0] [2.0, 4.0] [0.0, infinity] = [1.0, infinity]
    # powRev2 [1.0, infinity] [2.0, 4.0] [0.0, infinity] = [0.0, infinity]
    # powRev2 [2.0, 4.0] [0.0, 0.5] [entire] = [-infinity, -0.5]
    # powRev2 [2.0, infinity] [0.0, 0.5] [entire] = [-infinity, 0.0]
    # powRev2 [2.0, infinity] [0.0, 0.5] [0.0, infinity] = [empty]
    # powRev2 [2.0, 4.0] [0.25, 0.5] [entire] = [-2.0, -0.5]
    # powRev2 [2.0, infinity] [0.25, 0.5] [entire] = [-2.0, 0.0]
    # powRev2 [2.0, infinity] [0.25, 0.5] [0.0, infinity] = [empty]
    # powRev2 [2.0, 4.0] [0.5, 1.0] [entire] = [-1.0, 0.0]
    # powRev2 [2.0, infinity] [0.5, 1.0] [entire] = [-1.0, 0.0]
    # powRev2 [2.0, 4.0] [1.0, 1.0] [entire] = [0.0, 0.0]
    # powRev2 [2.0, infinity] [1.0, 1.0] [entire] = [0.0, 0.0]
    # powRev2 [2.0, 4.0] [0.0, 1.0] [entire] = [-infinity, 0.0]
    # powRev2 [2.0, infinity] [0.0, 1.0] [entire] = [-infinity, 0.0]
    # powRev2 [2.0, 4.0] [0.0, 1.0] [0.0, infinity] = [0.0, 0.0]
    # powRev2 [2.0, infinity] [0.0, 1.0] [0.0, infinity] = [0.0, 0.0]
    # powRev2 [2.0, 4.0] [0.0, 2.0] [entire] = [-infinity, 1.0]
    # powRev2 [2.0, infinity] [0.0, 2.0] [entire] = [-infinity, 1.0]
    # powRev2 [2.0, 4.0] [0.5, 2.0] [entire] = [-1.0, 1.0]
    # powRev2 [2.0, infinity] [0.5, 2.0] [entire] = [-1.0, 1.0]
    # powRev2 [2.0, 4.0] [1.0, 2.0] [entire] = [0.0, 1.0]
    # powRev2 [2.0, infinity] [1.0, 2.0] [entire] = [0.0, 1.0]
    # powRev2 [2.0, 4.0] [1.0, 2.0] [-infinity, 0.0] = [0.0, 0.0]
    # powRev2 [2.0, infinity] [1.0, 2.0] [-infinity, 0.0] = [0.0, 0.0]
    # powRev2 [2.0, 4.0] [2.0, 4.0] [entire] = [0.5, 2.0]
    # powRev2 [2.0, infinity] [2.0, 4.0] [entire] = [0.0, 2.0]
    # powRev2 [2.0, infinity] [2.0, 4.0] [-infinity, 0.0] = [empty]
    # powRev2 [2.0, 4.0] [2.0, infinity] [entire] = [0.5, infinity]
    # powRev2 [2.0, infinity] [2.0, infinity] [entire] = [0.0, infinity]
    # powRev2 [2.0, infinity] [2.0, infinity] [-infinity, 0.0] = [empty]
end

ext: jl


text:
abstract type AbstractNexus{T} end
abstract type AbstractArc{T} end
abstract type AbstractArcIter{T} end

@traitdef IsDirected{G<:AbstractNexus}
@traitimpl IsDirected{G} <- is_directed(G)

function show(io::IO, g::AbstractNexus{T}) where {T}
    dir = is_directed(g) ? "directed" : "undirected"
    print(io, "{$(nn(g)), $(na(g))} $dir $T graph.")
end

function show(io::IO, a::AbstractArc{T}) where {T}
    print(io, "Arc $T $(src(a)) -> $(tgt(a)) key $(key(a))")
end

function show(io::IO, ait::AbstractArcIter{T}) where {T}
    print(io, "ArcIter $T $(length(ait.list))")
end

eltype(::AbstractNexus{T}) where {T} = T

nn(g::AbstractNexus) = g.nn
na(g::AbstractNexus) = g.na
fadj(g::AbstractNexus) = g.fadj
nodes(g::AbstractNexus) = g.fadj |> keys

has_node(g::AbstractNexus{T}, n::T) where {T} = n in nodes(g)
function has_arc(g::AbstractNexus{T}, u::T, v::T, key::Int) where {T}
    haskey(g.fadj, u) && haskey(g.fadj[u],v) && haskey(g.fadj[u][v], key) && return true
    return false
end
# not dependent on directedness? NO.
# why? karena klo yg dicek fadj-nya, u--v dan v--u ada dua2nya

src(a::AbstractArc) = a.src
tgt(a::AbstractArc) = a.tgt
key(a::AbstractArc) = a.key


text:
using Test
using TestSetExtensions

include("tests.jl")

@testset ExtendedTestSet "Changepoint" begin
    Tests.changepoint_test()
end

max_stars_repo_name: realseanla/ntl-stick-breaking-julia

max_issues_repo_name: realseanla/ntl-stick-breaking-julia

max_forks_repo_name: realseanla/ntl-stick-breaking-julia


text:
using BoundingSphere
using NearestNeighbors
using Plots
using DynamicsPlots
using Random

struct AbstractSimplicialComplex
    Simplex::Set{Int64}
end
const ASC = AbstractSimplicialComplex

include("../utilities/tDATAsets.jl")
Random.seed!(0)
M2n = rand(Sphere(2), 20)
d, n = size(M2n)
flatΔ = 1:n
ε = 0.3
maxdim = 6

# Initialization
kdtree = KDTree(M2n)
knn0 = knn(kdtree, M2n, 2)
# bit_Δ0 = first.(knn0[2]) .≥ ε
# Δ0 = [[j] for j in 1:n][bit_Δ0]
begin
cache_r = Float64[]
Δ = []
preΔ = []
# push!(preΔ, knn0[1][.!bit_Δ0] |> sort .|> sort |> unique)
push!(preΔ, [[j] for j in 1:n])
for k in 1:maxdim
    if preΔ[k] |> isempty break end
    push!(Δ, [])
    push!(preΔ, [])
    # flatΔ = reduce(∪, preΔ[k]) |> sort
    for (idx_taboo, β) in enumerate(preΔ[k])
        flag_Δ = false
        for α in preΔ[k+1]
            if β ⊆ α
                flag_Δ = true
                break
            end
        end
        if flag_Δ continue end
        for v in flatΔ[idx_taboo:end]
            if v in β
                continue
            end
            # println("candy - β: ", β, " ∪  {", v, "}")
            candy = [β; v] |> sort # `candy` is a alias of 'candidate'.
            c, r = boundingsphere([M2n[:,idx] for idx in candy])
            checked = inrange(kdtree, c, r + eps(), true)
            if r ≤ ε && (length(candy) < length(checked) || candy == checked)
                flag_Δ = true
                push!(preΔ[k+1], candy)
                push!(cache_r, r)
                continue
            end
        end
        if flag_Δ continue end
        push!(Δ[k], β)
        println(Δ[k])
    end
end
end
# Δ0
Δ
preΔ[end]
cache_r |> unique |> sort
union(reduce(∪, Δ0), reduce(∪, reduce(∪, Δ))) |> sort

candy = [5,8,11,12]
c, r = boundingsphere([M2n[:,idx] for idx in candy])
inrange(kdtree, c, r + eps(), true)

color = [:yellow, :gray, :orange, :red, :black, :purple]
x,y = eachrow(M2n); p1 = scatter(x,y, text = 1:n, size = (600,600), color = :white)
for i in 1:length(Δ)
    for j in Δ[i]
        c, r = boundingsphere([M2n[:,k] for k in j])
        circle!(c,r, color = color[i], label = :none)
    end
end
circle!((0,0), ε, color = :blue, legend= :none)

c, r = boundingsphere([M2n[:,k] for k in [4,15,20]])
circle!(c, r, color = :green, legend= :none)
circle!(c, ε, color = :blue, legend= :none)


text:
module PlutoSliderServer

using FromFile

@from "./MoreAnalysis.jl" import MoreAnalysis
@from "./FileHelpers.jl" import FileHelpers: find_notebook_files_recursive, list_files_recursive
@from "./Export.jl" using Export
@from "./Actions.jl" import Actions: add_to_session!, generate_static_export, myhash, showall
@from "./Types.jl" using Types

import Pluto
import Pluto: ServerSession, Firebasey, Token, withtoken, pluto_file_extensions, without_pluto_file_extension
using HTTP
using Base64
using SHA
using Sockets
using Configurations
using TOML

using Logging: global_logger
using GitHubActions: GitHubActionsLogger
function __init__()
    get(ENV, "GITHUB_ACTIONS", "false") == "true" && global_logger(GitHubActionsLogger())
end

function get_configuration(toml_path::Union{Nothing,String}=nothing; kwargs...)::PlutoDeploySettings
    if !isnothing(toml_path) && isfile(toml_path)
        Configurations.from_toml(PlutoDeploySettings, toml_path; kwargs...)
    else
        Configurations.from_kwargs(PlutoDeploySettings; kwargs...)
    end
end

merge_recursive(a::AbstractDict, b::AbstractDict) = mergewith(merge_recursive, a, b)
merge_recursive(a, b) = b

merge_recursive(a::PlutoDeploySettings, b::PlutoDeploySettings) =
    Configurations.from_dict(PlutoDeploySettings,
        merge_recursive(Configurations.to_dict(a), Configurations.to_dict(b)))

with_kwargs(original::PlutoDeploySettings; kwargs...) = merge_recursive(original, Configurations.from_kwargs(PlutoDeploySettings; kwargs...))

include("./HTTPRouter.jl")

export export_directory, run_directory, github_action

"""
    export_directory(start_dir::String="."; kwargs...)

Search recursively for all Pluto notebooks in the current folder, and for each notebook:
- Run the notebook and wait for all cells to finish
- Export the state object
- Create a .html file with the same name as the notebook, which has:
  - The JS and CSS assets to load the Pluto editor
  - The state object embedded
  - Extra functionality enabled, such as hidden UI, binder button, and a live bind server

# Keyword rguments
- `Export_exclude::Vector{String}=[]`: list of notebook files to skip. Provide paths relative to `start_dir`.
- `Export_disable_ui::Bool=true`: hide all buttons and toolbars to make it look like an article.
- `Export_baked_state::Bool=true`: base64-encode the state object and write it inside the .html file. If `false`, a separate `.plutostate` file is generated.
- `Export_offer_binder::Bool=true`: show a "Run on Binder" button on the notebooks.
- `Export_binder_url::Union{Nothing,String}=nothing`: e.g. `https://mybinder.org/v2/gh/mitmath/18S191/e2dec90`. Defaults to a binder repo that runs the correct version of Pluto -- https://github.com/fonsp/pluto-on-binder. TODO docs
- `Export_slider_server_url::Union{Nothing,String}=nothing`: e.g. `https://sliderserver.mycoolproject.org/` TODO docs
- `Export_cache_dir::Union{Nothing,String}=nothing`: if provided, use this directory to read and write cached notebook states. Caches will be indexed by notebook hash, but you need to take care to invalidate the cache when Pluto or this export script updates. Useful in combination with https://github.com/actions/cache.
- `Export_output_dir::String="."`: folder to write generated HTML files to (will create directories to preserve the input folder structure). Leave at the default to generate each HTML file in the same folder as the notebook file.
- `notebook_paths::Vector{String}=find_notebook_files_recursive(start_dir)`: If you do not want the recursive save behaviour, then you can set this to a vector of absolute paths. In that case, `start_dir` is ignored, and you should set `Export_output_dir`.
"""
function export_directory(args...; kwargs...)
    run_directory(args...; static_export=true, run_server=false, kwargs...)
end
export_notebook(p; kwargs...) = run_notebook(p; static_export=true, run_server=false, kwargs...)
github_action = export_directory

function run_notebook(path::String; kwargs...)
    run_directory(dirname(path); notebook_paths=[basename(path)], kwargs...)
end

"""
    run_directory(start_dir::String="."; export_options...)

Run the Pluto bind server for all Pluto notebooks in the given directory (recursive search).

# Keyword arguments
- `SliderServer_exclude::Vector{String}=[]`: list of notebook files to skip. Provide paths relative to `start_dir`. _If `static_export` is `true`, then only paths in `SliderServer_exclude ∩ Export_exclude` will be skipped, paths in `setdiff(SliderServer_exclude, Export_exclude)` will be shut down after exporting._
- `SliderServer_port::Integer=2345`: Port to run the HTTP server on.
- `SliderServer_host="127.0.0.1"`: Often set to `"0.0.0.0"` on a server.
- `static_export::Bool=false`: Also export static files?
- `notebook_paths::Vector{String}=find_notebook_files_recursive(start_dir)`: If you do not want the recursive save behaviour, then you can set this to a vector of absolute paths. In that case, `start_dir` is ignored, and you should set `Export_output_dir`.

If `static_export` is `true`, then additional `Export_` keywords can be given, see [`export_directory`](@ref).
"""
function run_directory(
        start_dir::String=".";
        notebook_paths::Vector{String}=find_notebook_files_recursive(start_dir),
        static_export::Bool=false, run_server::Bool=true,
        on_ready::Function=((args...)->()),
        config_toml_path::Union{String,Nothing}=joinpath(Base.active_project() |> dirname, "PlutoDeployment.toml"),
        kwargs...
    )

    pluto_version = Export.try_get_exact_pluto_version()
    settings = get_configuration(config_toml_path;kwargs...)
    output_dir = something(settings.Export.output_dir, start_dir)
    mkpath(output_dir)

    to_run = if static_export
        setdiff(notebook_paths, settings.SliderServer.exclude ∩ settings.Export.exclude)
    else
        s = setdiff(notebook_paths, settings.SliderServer.exclude)
        filter(s) do f
            occursin("@bind", read(joinpath(start_dir, f), String))
        end
    end

    if static_export && run_server
        # The user wants to run a slider server, with static export and static notebook serving, so they very probably want to set `slider_server_url` to "./".
        settings = with_kwargs(settings; Export_slider_server_url = "./")
    end

    @info "Settings" Text(settings)

    run_server && @warn "Make sure that you run this slider server inside a containerized environment -- it is not intended to be secure. Assume that users can execute arbitrary code inside your notebooks."

    if to_run != notebook_paths
        @info "Excluded notebooks:" showall(setdiff(notebook_paths, to_run))
    end

    @info "Pluto notebooks to run:" showall(to_run)

    settings.Pluto.server.disable_writing_notebook_files = true
    settings.Pluto.evaluation.lazy_workspace_creation = true
    server_session = Pluto.ServerSession(;options=settings.Pluto)

    notebook_sessions = NotebookSession[QueuedNotebookSession(;path, current_hash=myhash(read(joinpath(start_dir, path)))) for path in to_run]

    if run_server
        static_dir = (
            static_export && settings.SliderServer.serve_static_export_folder
        ) ? output_dir : nothing
        router = make_router(settings, server_session, notebook_sessions; static_dir )
        # This is boilerplate HTTP code, don't read it
        host = settings.SliderServer.host
        port = settings.SliderServer.port

        # This is boilerplate HTTP code, don't read it
        hostIP = parse(Sockets.IPAddr, host)
        if port === nothing
            port, serversocket = Sockets.listenany(hostIP, UInt16(1234))
        else
            serversocket = try
                Sockets.listen(hostIP, UInt16(port))
            catch e
                @error "Port with number $port is already in use. Use Pluto.run() to automatically select an available port."
                return
            end
        end

        @info "Starting server..." host Int(port)

        # This is boilerplate HTTP code, don't read it
        # We start the HTTP server before launching notebooks so that the server responds to heroku/digitalocean garbage fast enough
        http_server_task = @async HTTP.serve(hostIP, UInt16(port), stream=true, server=serversocket) do http::HTTP.Stream
            request::HTTP.Request = http.message
            request.body = read(http)
            HTTP.closeread(http)

            params = HTTP.queryparams(HTTP.URI(request.target))

            response_body = HTTP.handle(router, request)

            request.response::HTTP.Response = response_body
            request.response.request = request
            try
                HTTP.setheader(http, "Referrer-Policy" => "origin-when-cross-origin")
                HTTP.startwrite(http)
                write(http, request.response.body)
                HTTP.closewrite(http)
            catch e
                if isa(e, Base.IOError) || isa(e, ArgumentError)
                    # @warn "Attempted to write to a closed stream at $(request.target)"
                else
                    rethrow(e)
                end
            end
        end
    else
        http_server_task = @async 1+1
        serversocket = nothing
    end

    if static_export && settings.Export.create_index
        exists = any(["index.html", "index.md", ("index"*e for e in pluto_file_extensions)...]) do f
            joinpath(output_dir, f) |> isfile
        end
        if !exists
            write(joinpath(output_dir, "index.html"), default_index((
                without_pluto_file_extension(path) => without_pluto_file_extension(path) * ".html"
                for path in to_run
            )))
        end
    end

    # RUN ALL NOTEBOOKS AND KEEP THEM RUNNING
    for (i, path) in enumerate(to_run)

        @info "[$(i)/$(length(to_run))] Opening $(path)"

        local session, jl_contents, original_state
        # That's because you can't continue in a loop
        try
            session, jl_contents, original_state = add_to_session!(notebook_sessions, server_session, path, settings, run_server, start_dir)
        catch e
            rethrow(e)
            continue
        end

        if static_export
            generate_static_export(path, settings, original_state, output_dir, jl_contents)
        end

        @info "[$(i)/$(length(to_run))] Ready $(path)" session.current_hash
    end
    @info "-- ALL NOTEBOOKS READY --"

    on_ready((;
        serversocket,
        server_session,
        notebook_sessions,
    ))

    wait(http_server_task)
end

end


text:
#Contains functions to update the networks

#Simply iterate trough the dataset and update:
function do_sac_update(Pl::Any,Qf1::Any, Qf2::Any, Vf::Any,Vf_tar::Any,buffer::Traj_Data,params::Params, opt_para_pl, opt_para_qf1, opt_para_qf2, opt_para_vf)
    n_traj = buffer.n_traj
    shuffle_arr = shuffle(1:n_traj)
    τ = params.τ

    for i_true = 1:n_traj
        i_traj = shuffle_arr[i_true]
        traj = buffer.traj[i_traj]

        #Get the gradients:
        ĝ_vf, ĝ_qf1, ĝ_qf2, ĝ_pl = grad_all_networks(traj, Vf, Vf_tar, Qf1, Qf2, Pl, params)

        #Update the Networks:
        Knet.update!(Vf, ĝ_vf, opt_para_vf)
        Knet.update!(Qf1, ĝ_qf1, opt_para_qf1)
        Knet.update!(Qf2, ĝ_qf2, opt_para_qf2)
        Knet.update!(Pl, ĝ_pl, opt_para_pl)
        Vf_tar = τ .* Vf .+ (1-τ) .* Vf_tar
    end
end

#This function will update the networks in parallel:
function do_sac_update_parallel!(Pl::Any,Qf1::Any,Qf2::Any,Vf::Any,Vf_tar::Any,buffer::Traj_Data,params::Params,
     opt_para_pl, opt_para_qf1, opt_para_qf2, opt_para_vf)

    #Take all partial traj and shuffle their order!
    n_traj = buffer.n_traj
    shuffle_arr = shuffle(1:n_traj)
    τ = params.τ

    active_workers = workers()
    n_workers = length(active_workers)

    ĝ_pl  = copy(Pl)
    ĝ_qf1 = copy(Qf1)
    ĝ_qf2 = copy(Qf2)
    ĝ_vf  = copy(Vf)

    # Create Channels storing results and starting values
    input_channel  = RemoteChannel(()->Channel{Tuple}(length(workers())+1)) # will contain networks and traj
    output_channel = RemoteChannel(()->Channel{Tuple}(length(workers())+1)) # will contain networks

    # Create problem on every worker
    begin
        for p in workers()
            remote_do(distributed_sac_update, p, params, input_channel, output_channel)
        end
    end

    # Start optimizations
    n_parallel = Int(ceil(n_traj / (n_workers * 20)))
    prog = Progress(n_parallel,1)

    for i_parallel = 1 : n_parallel

        #1. Send the work tasks:
        for i_w = 1 : n_workers
            i_true = ((i_parallel-1)*n_workers + i_w) #get true order
            if i_true <= n_traj
                i_traj = shuffle_arr[i_true] #shuffle order
                traj_local = buffer.traj[i_traj]
                @async put!(input_channel, (traj_local, Pl, Qf1, Qf2, Vf, Vf_tar))
            end
        end

        # 2. Take the results
        ĝ_pl  *= 0
        ĝ_qf1 *= 0
        ĝ_qf2 *= 0
        ĝ_vf  *= 0

        for i_w = 1: n_workers
            i_true = ((i_parallel-1)*n_workers + i_w)
            if i_true <= n_traj
                #Take from Channel
                gradients = take!(output_channel)
                #Reorder
                ĝ_vf  += gradients[1]
                ĝ_qf1 += gradients[2]
                ĝ_qf2 += gradients[3]
                ĝ_pl  += gradients[4]
            end
        end

        #Update the Networks
        Knet.update!(Vf,  ĝ_vf,  opt_para_vf)
        Knet.update!(Qf1, ĝ_qf1, opt_para_qf1)
        Knet.update!(Qf2, ĝ_qf2, opt_para_qf2)
        Knet.update!(Pl,  ĝ_pl,  opt_para_pl)
        Vf_tar = τ .* Vf .+ (1-τ) .* Vf_tar

        #Update Progress
        #ProgressMeter.update!(prog,i_parallel) #update progress bar
    end

    # Tell workers that its done
    NaN_mat = zeros(length(params.batch_size))
    fill!(NaN_mat,NaN)
    ending_traj = init_traj(params,params.batch_size)
    ending_traj.r_t = NaN_mat

    for j = 1 : n_workers
        @async put!(input_channel, (ending_traj, Pl, Qf1, Qf2, Vf, Vf_tar))
    end

    #Close Channels
    sleep(0.1)
    close(input_channel)
    close(output_channel)

    return nothing
end

#Function running on the worker
@everywhere function distributed_sac_update(params::Params, input_channel::RemoteChannel, output_channel::RemoteChannel)

   #TODO BREAK!!!!

   # Start loop where work is done
   while true
       # break loop if NaN state received
       try
           #Take the new Input
           input = take!(input_channel)

           #Reorder data:
           traj_local = input[1]
           Pl         = input[2]
           Qf1        = input[3]
           Qf2        = input[4]
           Vf         = input[5]
           Vf_tar     = input[6]

           #Check if u reached final
           if (sum(isnan, traj_local.r_t) > 0)
               GC.gc()
               break
           end

           #DO THE WORK:
           #-----------------------------------------------------------------------
           ĝ_vf, ĝ_qf1, ĝ_qf2, ĝ_pl = grad_all_networks(traj_local, Vf, Vf_tar, Qf1, Qf2, Pl, params)
           #-----------------------------------------------------------------------

           put!(output_channel, (ĝ_vf, ĝ_qf1, ĝ_qf2, ĝ_pl) )

       catch
           println("Some problem occured, worker $(myid()) exiting trajectory optimization function.")
           break
       end
   end

   return nothing
end

max_stars_repo_name: NikonPic/REINFORCEMENT-JULIA

max_issues_repo_name: NikonPic/REINFORCEMENT-JULIA

max_forks_repo_name: NikonPic/REINFORCEMENT-JULIA


text:
function cmp_minhashes(h1::MinHasher, h2::MinHasher)
    return MinHashSketch(h1).hashes ==  MinHashSketch(h2).hashes
end

function test_minhasher(h::MinHasher{F}, x, s::Integer) where F
    truth = sort!(collect(Set([F(i) for i in x])))[1:s]
    h = MinHashSketch(h).hashes
    if truth != h
        println(x)
    end
    @test truth == h
end

function test_minhashing(F, x, s::Integer)
    h = MinHasher{F}(s)
    MinHash.update!(h, x)
    test_minhasher(h, x, s)
end

hashtwo(x) = hash(x, 0x80fa8f430b9cd13a)

@testset "Basic functionality" begin
    for F in (hash, hashtwo)
        test_minhashing(F, join(rand('A':'z', 100)), 20)
        test_minhashing(F, 1:10000, 1000)
        test_minhashing(F, 1:1000, 1000)
        test_minhashing(F, rand(UInt8, 1000), 50)
    end
    # Test default function is hashing as we expect
    h0 = MinHashSketch(MinHash.update!(MinHasher{hash}(25), 1:1000)).hashes
    h1 = MinHashSketch(MinHash.update!(MinHasher(25), 1:1000)).hashes
    @test h0 == h1
end

function test_update(F, s::Integer, x::AbstractVector, partitions::Vector)
    h1 = MinHasher{F}(s)
    h2 = MinHasher{F}(s)
    MinHash.update!(h1, x)
    for p in partitions
        MinHash.update!(h2, x[p])
    end
    @test cmp_minhashes(h1, h2)
end

@testset "Updating" begin
    for F in (hash, hashtwo)
        test_update(F, 20, 'A':'z', [1:20, 10:40, 38:58])
        test_update(F, 1000, 1:10000, [7000:10000, 1:5000, 4000:7500])
        test_update(F, 75, rand(UInt8, 1000), [1:0, 1:1000, 1:0])
    end
end

function test_empty!(s::Integer, x)
    h0 = MinHash.update!(MinHasher(s), x)
    h1 = MinHash.update!(MinHasher(s), 1:100)
    empty!(h1)
    MinHash.update!(h1, x)
    @test cmp_minhashes(h0, h1)
end

@testset "Emptying" begin
    test_empty!(40, 'A':'z')
    test_empty!(100, 1:1000)
end

function test_sketch(F, x, s::Integer)
    truth = sort!([F(i) for i in x])[1:s]
    @test minhash(F, x, s).hashes == truth
end

@testset "Sketch" begin
    for F in (hash, hashtwo)
        test_sketch(F, 'A':'z', 10)
        test_sketch(F, 1:1000, 200)
    end
end


text:
module FESpacesWithLinearConstraintsTests

using Gridap.Algebra
using Gridap.Arrays
using Gridap.Fields
using Gridap.Geometry
using Gridap.FESpaces
using Test
using LinearAlgebra
using Gridap.CellData

domain = (0,1,0,1)
partition = (2,2)
model = CartesianDiscreteModel(domain,partition)
trian = Triangulation(model)

labels = get_face_labeling(model)
add_tag_from_tags!(labels,"dirichlet",[1,2,5])
add_tag_from_tags!(labels,"neumann",[6,7,8])

V = FESpace(
  model=model,valuetype=Float64,reffe=:Lagrangian,order=1,
  conformity=:H1,dirichlet_tags="dirichlet")
test_single_field_fe_space(V)

fdof_to_val = collect(Float64,1:num_free_dofs(V))
ddof_to_val = -collect(Float64,1:num_dirichlet_dofs(V))
vh = FEFunction(V,fdof_to_val,ddof_to_val)

sDOF_to_dof = [1,5,-2]
sDOF_to_dofs = Table([[-1,4],[4,6],[-1,-3]])
sDOF_to_coeffs = Table([[0.5,0.5],[0.5,0.5],[0.5,0.5]])

Vc = FESpaceWithLinearConstraints(
  sDOF_to_dof,
  sDOF_to_dofs,
  sDOF_to_coeffs,
  V)

test_single_field_fe_space(Vc)
@test has_constraints(Vc)

scellids = SkeletonPair([1,2,1,3],[2,4,3,4])
@test isa(get_cell_constraints(Vc,scellids)[1],BlockArrayCoo)

@test Vc.n_fdofs == 6
@test Vc.n_fmdofs == 4

fmdof_to_val = collect(Float64,1:num_free_dofs(Vc))
dmdof_to_val = -collect(Float64,1:num_dirichlet_dofs(Vc))
vch = FEFunction(Vc,fmdof_to_val,dmdof_to_val)
r = [[-1.0, -1.5, 1.0, 1.0], [-1.5, -2.0, 1.0, 2.0], [1.0, 1.0, 3.0, 3.5], [1.0, 2.0, 3.5, 4.0]]
@test get_cell_values(vch) ≈ r

v(x) = sin(4*x[1]+0.4)*cos(5*x[2]+0.7)
vch = interpolate(v,Vc)

#using Gridap.Visualization
#writevtk(trian,"trian",nsubcells=10,cellfields=["vh"=>vh,"vch"=>vch])

u(x) = x[1] + 2*x[2]
f(x) = -Δ(u)(x)
Uc = TrialFESpace(Vc,u)
@test has_constraints(Uc)
uch = interpolate(u,Uc)

btrian = BoundaryTriangulation(model,"neumann")

quad = CellQuadrature(trian,2)
bquad = CellQuadrature(btrian,2)

bn = get_normal_vector(btrian)

strian = SkeletonTriangulation(model)
squad = CellQuadrature(strian,2)

a(u,v) = ∇(v)⋅∇(u)
b1(v) = v*f
b2(v) = v*(bn⋅∇(u))
a3(u,v) = jump(u)*jump(v)
t1 = AffineFETerm(a,b1,trian,quad)
t2 = FESource(b2,btrian,bquad)
t3 = LinearFETerm(a3,strian,squad)
op = AffineFEOperator(Uc,Vc,t1,t2,t3)
uch = solve(op)

#using Gridap.Visualization
#writevtk(trian,"trian",nsubcells=10,cellfields=["uch"=>uch])

e = u - uch

l2(u) = u*u
h1(u) = u*u + a(u,u)

e_l2 = sqrt(sum(integrate(l2(e),trian,quad)))
e_h1 = sqrt(sum(integrate(h1(e),trian,quad)))

tol = 1.e-9
@test e_l2 < tol
@test e_h1 < tol

end # module