text:
### A Pluto.jl notebook ###
# v0.14.0

using Markdown
using InteractiveUtils

# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).
macro bind(def, element)
    quote
        local el = $(esc(element))
        global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : missing
        el
    end
end

# ╔═╡ f07c3450-ef32-11ea-3f5f-2b0fc747ff80
begin
	using TheNumberLine, PlutoUI, Luxor; "✓"
end

# ╔═╡ 62e67a9c-ef25-11ea-3589-6f377d7aa788
md"""
Type value and select `add`

` Type value : ` $(@bind b html"<input type=text>")

` ` $(@bind c html"<input type=button value='add'>")
$(@bind d html"<input type=button value='start over'>")

_For example, `8`, `-9`, or `+2` should be valid choices. You can also `start over` if it looks like something went wrong._
"""

# ╔═╡ dcddc9f9-36aa-44ce-b2c5-284af9928680
#The Number Line is a common teaching tool in e.g. K-12 math classes accross the U.S.
#
#Details of the implementation are found in the following code cells and in the github code repository
#
#https://github.com/gaelforget/TheNumberLine.jl

md"""↩ click here for additional information
"""

# ╔═╡ 78c0fd44-f052-11ea-0264-4378e02814af
begin
	#1. In the code cell at the top where values are entered, you can use
	# a list of a slider instead. Try replacing the _...@bind b htm..._ line with:
	#
	#`Select value of x from the list : `
	#` ` $(@bind b Select(["4","3","2","1","0","-1","-2","-3","-4"],default="0"))
	#
	#or
	#
	#`Choose value of x using slider : `
	#` ` $(@bind b aSlider(-10:10; default=0))

	#2. To restrict the number line to Integer inputs try changing the `TestType` below.
	#
	TestType=Number; NumberLineType=Float64; "Number LineType = $(NumberLineType)"
	#TestType=Int; NumberLineType=Int; "NumberLineType = $(NumberLineType)"

	#3. In the `random turtle` exercise we take a series of consecutive steps on the
	# number line. Each step is either `-1` (1 step left) or `+1` (1 step right)
	# based on a coin flip. We do this N times in a row (10 times for example) and
	# observe our final value at the end (green arrow).
	#
	# All you need to do is copy the following line to a new code cell and run it
	#
	# NumberLinePlot(rand((-1,1),10))
	#
	# The activity is ~ do this a bunch of times and discuss how results can vary

	md"""↩ click here for exercise material
	"""
end

# ╔═╡ 7c1434b2-ef25-11ea-0967-d756ec262715
bb = try
	isa(b,String) ? b1=eval(Meta.parse(b)) : b1=deepcopy(b)
	!isa(b1,TestType) ? b2=parse(NumberLineType,b1) : b2=b1
	b2
  catch
    NaN
end; "✓"

# ╔═╡ 46c870e8-ef2a-11ea-3552-afbc18d117ee
begin
	d
	ii=[0.0]
	jj=[]
end; "✓"

# ╔═╡ 4be4ef1e-ef27-11ea-34f7-cd86ba1c36e2
begin
	c
	d
	length(jj)>0 ? push!(ii,jj[end]) : nothing
	kk=findall((!isnan).(ii))
	smry=NumberLineExpression(ii[kk])
	NumberLinePlot(ii[kk])
end

# ╔═╡ 33165978-f050-11ea-33f0-4971b031ee8b
smry

# ╔═╡ c0e46264-ef30-11ea-0b51-adc95104e22f
push!(jj,bb); "✓"

# ╔═╡ Cell order:
# ╟─62e67a9c-ef25-11ea-3589-6f377d7aa788
# ╟─33165978-f050-11ea-33f0-4971b031ee8b
# ╟─4be4ef1e-ef27-11ea-34f7-cd86ba1c36e2
# ╟─dcddc9f9-36aa-44ce-b2c5-284af9928680
# ╟─78c0fd44-f052-11ea-0264-4378e02814af
# ╟─f07c3450-ef32-11ea-3f5f-2b0fc747ff80
# ╟─7c1434b2-ef25-11ea-0967-d756ec262715
# ╟─46c870e8-ef2a-11ea-3552-afbc18d117ee
# ╟─c0e46264-ef30-11ea-0b51-adc95104e22f


text:
# slow as hell
using DataStructures

function sumby_trie{T<:AbstractString,S<:Number}(by::AbstractVector{T}, val::AbstractVector{S})
  a = Trie{S}()
  szero = zero(S)
  for (byi, vali) = zip(by, val)
    a[byi] = get(a, byi, szero) + vali
  end
  return a
end

@time sumby_trie(id3, v1) # 100 seconds
#@time sumby_dict(id6, v1)

ext: jl


text:
function SeisBandPass(d;dt=0.001,fa=0,fb=0,fc=60,fd=80)

	nt = size(d,1)
	nx = size(d[:,:],2)
	nf = iseven(nt) ? nt : nt + 1
	df = 1/nf/dt
	nw = round(Int,nf/2) + 1

	if(fd*dt*nf < nw)
		iw_max = round(Int,floor(fd*dt*nf))
	else
		iw_max = round(Int,floor(0.5/dt))
	end

	d = pad_first_axis(d,nf)
	m = fft(d,1)/sqrt(size(d,1))
	if fa > 0.
		m[1,:] *= 0.
	end
	for iw=2:iw_max
		f = df*(iw-1)
		if (f<fa)
			m[iw,:] *= 0.
		elseif (f >= fa && f < fb)
			m[iw,:] *= (f-fa)/(fb-fa)
		elseif (f >= fb && f <= fc)
			m[iw,:] *= 1.
		elseif (f > fc && f <= fd)
			m[iw,:] *= 1. - (f-fc)/(fd-fc)
		else
			m[iw,:] *= 0.
		end
	end
	m[iw_max:end,:] = 0.

	# symmetries
	for iw=nw+1:nf
		m[iw,:] = conj(m[nf-iw+2,:])
	end
	d = real(bfft(m,1)/sqrt(size(m,1)))

	return d[1:nt,1:nx];
end

function pad_first_axis(a,N1)
	n1 = size(a,1)
	nx = size(a[:,:],2)
	b = zeros(N1,nx)
	for ix = 1 : nx
		b[1:n1,ix] = a[:,ix]
	end
	return b
end

function SeisBandPass(d,h::Array{Header,1};dt=0.001,fa=0,fb=0,fc=60,fd=80)

	out = SeisBandPass(d;dt=h[1].d1,fa=fa,fb=fb,fc=fc,fd=fd)
	return out,h

end

function SeisBandPass(in::String,out::String;fa=0,fb=0,fc=60,fd=80)

	@compat parameters = Dict(:fa=>fa,:fb=>fb,:fc=>fc,:fd=>fd)
	SeisProcess(in,out,[SeisBandPass],[parameters];group="some")

end


text:
mutable struct Robot
    pose
    velocity
    kp
    kv
    holding
end

mutable struct Object
    id
    pose
    dimensions
    color
end


text:
println("\nTesting linear expressions\n")

#### * ####
n, m1, m2, k = 3, 4, 5, 6
x1 = Variable(randn(m1))
x2 = Variable(randn(m2))
A1 = randn(n, m1)
A2 = randn(n, m2)
b  = randn(n)
b0  = pi
opA1 = MatrixOp(A1)
opA2 = MatrixOp(A2)
# multiply with Variable
ex1 = opA1*x1
@test variables(ex1) == (x1,)
@test operator(ex1)*(~x1) == A1*(~x1)
B1 = randn(k, n)
opB1 = MatrixOp(B1)
# multiply with Expression
ex2 = opB1*ex1
@test variables(ex2) == (x1,)
@test norm(operator(ex2)*(~x1) - B1*A1*(~x1)) < 1e-12
# multiply with Expression with multiple variables
ex3 = opB1*(opA1*x1+opA2*x2)
@test variables(ex3) == (x1,x2)
@test norm(operator(ex3)*(~x1,~x2) - B1*(A1*(~x1)+A2*(~x2))) < 1e-12
# multiply with displacemented Array Expression with multiple variables
ex3 = opB1*(opA1*x1+opA2*x2+b)
@test variables(ex3) == (x1,x2)
@test norm(displacement(ex3) - B1*b) < 1e-12
# multiply with displacemented scalar Expression with multiple variables
ex3 = opB1*(opA1*x1+opA2*x2+b0)
@test variables(ex3) == (x1,x2)
@test norm(displacement(ex3) - B1*(ones(size(B1,2))*b0)) < 1e-12
@test_throws ArgumentError MatrixOp(randn(n,m1+1))*x1
@test_throws ArgumentError MatrixOp(randn(n,m1))*Variable(Complex{Float64},m1)

n, m1, m2, k = 3, 4, 5, 6
A1 = randn(n, m1)
A2 = randn(n, m2)
b1 = randn(n,n)
b2 = randn(n,n)
opA1 = MatrixOp(A1,n)
opA2 = MatrixOp(A2,n)
x1, x2  = Variable(randn(m1,n)), Variable(randn(m2,n))
# multiply Expressions (NonLinearCompose)
ex = (opA1*x1)*(opA2*x2)
@test variables(ex) == (x1,x2)
@test norm(affine(ex)*(~x1,~x2) - (A1*(~x1))*(A2*(~x2))) < 1e-12
ex = (opA1*x1-b1)*(opA2*x2)
@test variables(ex) == (x1,x2)
@test norm(affine(ex)*(~x1,~x2) - (A1*(~x1)-b1)*(A2*(~x2))) < 1e-12
ex = (opA1*x1)*(opA2*x2+b2)
@test variables(ex) == (x1,x2)
@test norm(affine(ex)*(~x1,~x2) - (A1*(~x1))*(A2*(~x2)+b2)) < 1e-12
ex = (opA1*x1+b1)*(opA2*x2+b2)
@test variables(ex) == (x1,x2)
@test norm(affine(ex)*(~x1,~x2) - (A1*(~x1)+b1)*(A2*(~x2)+b2)) < 1e-12
@test_throws ErrorException (opA1*x1)*(opA1*x1)

n, m1, m2, k = 3, 4, 5, 6
A1 = randn(n, m1)
A2 = randn(n, m2)
b1 = randn(n,n)
b2 = randn(n,n)
opA1 = MatrixOp(A1,n)
opA2 = MatrixOp(A2,n)
x1, x2  = Variable(randn(m1,n)), Variable(randn(m2,n))
## multiply Expressions elementwise (Hadamard)
ex = (opA1*x1).*(opA2*x2)
@test variables(ex) == (x1,x2)
@test norm(affine(ex)*(~x1,~x2) - (A1*(~x1)).*(A2*(~x2))) < 1e-12
ex = (opA1*x1-b1).*(opA2*x2)
@test variables(ex) == (x1,x2)
@test norm(affine(ex)*(~x1,~x2) - (A1*(~x1)-b1).*(A2*(~x2))) < 1e-12
ex = (opA1*x1).*(opA2*x2+b2)
@test variables(ex) == (x1,x2)
@test norm(affine(ex)*(~x1,~x2) - (A1*(~x1)).*(A2*(~x2)+b2)) < 1e-12
ex = (opA1*x1+b1).*(opA2*x2+b2)
@test variables(ex) == (x1,x2)
@test norm(affine(ex)*(~x1,~x2) - (A1*(~x1)+b1).*(A2*(~x2)+b2)) < 1e-12
@test_throws ErrorException (opA1*x1)*(opA1*x1)

##### reshape ####
m,n = 8,10
A = randn(n,m)
x = Variable(randn(m))
b = randn(n)
B = reshape(b,2,5)

ex = reshape(x,4,2)
@test norm(operator(ex)*~x - reshape(~x,4,2)) < 1e-12

ex2 = reshape(A*x,2,5)
@test norm(operator(ex2)*~x - reshape(A*~x,2,5)) < 1e-12

ex3 = reshape(A*x,2,5)+B
@test norm(operator(ex2)*~x+displacement(ex3)- reshape(A*~x,2,5)-B) < 1e-12

ex4 = reshape(A*x-b,2,5)
@test norm(operator(ex4)*~x+displacement(ex4)- reshape(A*~x-b,2,5)) < 1e-12

#### + ####

# sum same variable
n, m = 3,4
x = Variable(randn(m))
A = randn(n, m)
B = randn(n, m)
opA = MatrixOp(A)
opB = MatrixOp(B)
ex1 = opA*x+opB*x
@test variables(ex1) == (x,)
@test norm(operator(ex1)*~x - (opA+opB)*~x) < 1e-12

# sum different variables
n, m1, m2 = 3, 4, 5
xa = Variable(randn(m1))
xb = Variable(randn(m2))
xc = Variable(randn(n))
xd = Variable(randn(n))
A = randn(n, m1)
A2 = randn(n, m1)
B = randn(n, m2)
b = randn(n)
b0 = pi
opA = MatrixOp(A)
opA2 = MatrixOp(A2)
opB = MatrixOp(B)
opI = Eye(n)

# (+) sum different variables no HCAT
ex1 = opA*xa+opB*xb
@test variables(ex1) == (xa,xb)
@test norm(operator(ex1)*(~xa,~xb) - hcat(opA,opB)*(~xa,~xb)) <1e-12

# (+) sum of same variables
ex2 = opA2*xa
exs1 = ex1+ex2
exs2 = ex2+ex1
@test variables(exs1) == (xa,xb)
@test norm(operator(exs1)*(~xa,~xb) - hcat(opA+opA2,opB)*(~xa,~xb)) <1e-12
@test variables(exs2) == (xa,xb)
@test norm(operator(exs2)*(~xa,~xb) - hcat(opA+opA2,opB)*(~xa,~xb)) <1e-12

# (+) sum of different variables with HCAT
exs3 = exs1+exs2
@test variables(exs3) == (xa,xb)
@test norm(operator(exs3)*(~xa,~xb) - hcat(2*(opA+opA2),2*opB)*(~xa,~xb)) <1e-12
# (+) sum of different variables with HCAT
exs4 = exs1+(xc+xd)
@test variables(exs4) == (xa,xb,xc,xd)
@test norm(operator(exs4)*(~xa,~xb,~xc,~xd) - hcat(opA+opA2,opB,opI,opI)*(~xa,~xb,~xc,~xd)) <1e-12

# (+) sum Array
ex1 = xd+b
@test norm(displacement(ex1) - b) == 0.

# (+) sum scalar
ex2 = opB*xb+b0
@test (displacement(ex2) - b0) == 0.

# (+) sum displacemented expressions
ex3 = ex1+ex2
@test norm(displacement(ex3) - (b.+b0)) == 0.

#### (.+) sum
n = 3
b = randn(n)

x1 = Variable(randn(1))
x2 = Variable(randn(n))
ex1 = x1.+x2
@test norm(operator(ex1)*(~x1,~x2)-((~x1).+(~x2))) < 1e-9

x1 = Variable(randn(1))
x2 = Variable(randn(n))
ex1 = x1.+(x2+2)
@test norm(operator(ex1)*(~x1,~x2)-((~x1).+(~x2))) < 1e-9
@test displacement(ex1) == 2

x1 = Variable(randn(1))
x2 = Variable(randn(n))
ex1 = (x1+2).+(x2+b)
@test norm(operator(ex1)*(~x1,~x2)-((~x1).+(~x2))) < 1e-9
@test displacement(ex1) == (b.+2)

x1 = Variable(randn(n))
x2 = Variable(randn(1))
ex1 = x1.+x2
@test norm(operator(ex1)*(~x1,~x2)-((~x1).+(~x2))) < 1e-9

x1 = Variable(randn(n))
x2 = Variable(randn(1))
ex1 = x1.+(x2+2)
@test norm(operator(ex1)*(~x1,~x2)-((~x1).+(~x2))) < 1e-9
@test displacement(ex1) == 2

x1 = Variable(randn(n))
x2 = Variable(randn(1))
ex1 = (x1+b).+(x2+2)
@test norm(operator(ex1)*(~x1,~x2)-((~x1).+(~x2))) < 1e-9
@test displacement(ex1) == (b.+2)

n,m =2,4
x1 = Variable(randn(n,m))
x2 = Variable(randn(1,m))
ex1 = x1.+x2+6
@test norm(operator(ex1)*(~x1,~x2)-((~x1).+(~x2))) < 1e-9
@test displacement(ex1) == 6

# #### (.-) sum

n = 3
b = randn(n)

x1 = Variable(randn(1))
x2 = Variable(randn(n))
ex1 = x1.-x2
@test norm(operator(ex1)*(~x1,~x2)-((~x1).-(~x2))) < 1e-9

x1 = Variable(randn(1))
x2 = Variable(randn(n))
ex1 = x1.-(x2+2)
@test norm(operator(ex1)*(~x1,~x2)-((~x1).-(~x2))) < 1e-9
@test displacement(ex1) == -2

x1 = Variable(randn(1))
x2 = Variable(randn(n))
ex1 = (x1+2).-(x2+b)
@test norm(operator(ex1)*(~x1,~x2)-((~x1).-(~x2))) < 1e-9
@test displacement(ex1) == (2 .-b)

x1 = Variable(randn(n))
x2 = Variable(randn(1))
ex1 = x1.-x2
@test norm(operator(ex1)*(~x1,~x2)-((~x1).-(~x2))) < 1e-9

x1 = Variable(randn(n))
x2 = Variable(randn(1))
ex1 = x1.-(x2+2)
@test norm(operator(ex1)*(~x1,~x2)-((~x1).-(~x2))) < 1e-9
@test displacement(ex1) == -2

x1 = Variable(randn(n))
x2 = Variable(randn(1))
ex1 = (x1+b).-(x2+2)
@test norm(operator(ex1)*(~x1,~x2)-((~x1).-(~x2))) < 1e-9
@test displacement(ex1) == (b.-2)

n,m =2,4
x1 = Variable(randn(n,m))
x2 = Variable(randn(1,m))
ex1 = x1.-x2+6
@test norm(operator(ex1)*(~x1,~x2)-((~x1).-(~x2))) < 1e-9
@test displacement(ex1) == 6

# (-) sum different variables no HCAT
ex1 = opA*xa-opB*xb
@test variables(ex1) == (xa,xb)
@test norm(operator(ex1)*(~xa,~xb) - hcat(opA,-opB)*(~xa,~xb)) <1e-12

# (-) sum of same variables
ex2 = opA2*xa
exs1 = ex1-ex2
exs2 = ex2-ex1
@test variables(exs1) == (xa,xb)
@test norm(operator(exs1)*(~xa,~xb) - hcat(opA-opA2,-opB)*(~xa,~xb)) <1e-12
@test variables(exs2) == (xa,xb)
@test norm(operator(exs2)*(~xa,~xb) - hcat(-opA+opA2,+opB)*(~xa,~xb)) <1e-12

# (-) sum of same variables with HCAT
exs3 = exs1-exs2
@test variables(exs3) == (xa,xb)
@test norm(operator(exs3)*(~xa,~xb) - hcat(2*(opA-opA2),-2*opB)*(~xa,~xb)) < 1e-12
# (-) sum of different variables with HCAT
exs4 = exs1-(xc-xd)
@test variables(exs4) == (xa,xb,xc,xd)
@test norm(operator(exs4)*(~xa,~xb,~xc,~xd) - hcat(opA-opA2,-opB,-opI,opI)*(~xa,~xb,~xc,~xd)) <1e-12

# (-) sum Array
ex1 = xd-b
@test norm(displacement(ex1) + b) == 0.

# (-) sum scalar
ex2 = opB*xb-b0
@test (displacement(ex2) + b0) == 0.

# (+) sum displacemented expressions
ex3 = ex1-ex2
@test norm(displacement(ex3) - (-b.+b0)) == 0.

@test_throws DimensionMismatch MatrixOp(randn(10,20))*Variable(20)+randn(11)
@test_throws ErrorException MatrixOp(randn(10,20))*Variable(20)+(3+im)


text:
####
#### Activation
####

"""
    mj_activate(filename::String) -> Cint

Activate the license located at `filename`, return 1 if successful,
otherwise throws a `MuJoCoException`.
"""
function mj_activate(filename::String)
    ccall((:mj_activate, libmujoco), Cint, (Cstring,), filename)
end

"""
    mj_deactivate() -> Cvoid

Deactivate license and free all MuJoCo memory
"""
function mj_deactivate()
    ccall((:mj_deactivate, libmujoco), Cvoid, ())
end

"""
    mj_certQuestion(question::MVector{16,mjtNum}) -> Cvoid

Generate server-side certificate question and store it in `question`.
"""
function mj_certQuestion(question::MVector{16,mjtNum})
    ccall((:mj_certQuestion, libmujoco), Cvoid, (Ptr{mjtNum},), question)
end

"""
    mj_certAnswer(question::MVector{16, mjtNum}, answer::MVector{16,mjtNum}) -> Cvoid

Generate client-side certificate answer given `question` and store it in `answer`.
"""
function mj_certAnswer(question::MVector{16,mjtNum}, answer::MVector{16,mjtNum})
    ccall((:mj_certAnswer, libmujoco), Cvoid, (Ptr{mjtNum}, Ptr{mjtNum}), question, answer)
end

"""
    mj_certCheck(question::MVector{16,mjtNum}, answer::MVector{16,mjtNum}) -> Cint

Check certificate question-answer pair on server. Return 1 if match, 0 if mismatch.
"""
function mj_certCheck(question::MVector{16,mjtNum}, answer::MVector{16,mjtNum})
    ccall((:mj_certCheck, libmujoco), Cint, (Ptr{mjtNum}, Ptr{mjtNum}), question, answer)
end

####
#### Virtual file system
####

"""
    mj_defaultVFS(vfs::Ref{mjVFS}) -> Cvoid

Initialize `vfs` to empty (no deallocation).
"""
function mj_defaultVFS(vfs::Ref{mjVFS})
    ccall((:mj_defaultVFS, libmujoco), Cvoid, (Ptr{mjVFS},), vfs)
end

"""
    mj_addFileVFS(vfs::Ref{mjVFS}, directory::String, filename::String) -> Cint

Add `joinpath(directory, filename)` to `vfs`,
return 0: success, 1: full, 2: repeated name, -1: not found on disk.
"""
function mj_addFileVFS(vfs::Ref{mjVFS}, directory::String, filename::String)
    ccall(
        (:mj_addFileVFS, libmujoco),
        Cint,
        (Ptr{mjVFS}, Cstring, Cstring),
        vfs,
        directory,
        filename,
    )
end

"""
    mj_makeEmptyFileVFS(vfs::Ref{mjVFS}, filename::String, filesize::Integer) -> Cint

Make empty file `filename` of `filesize` bytes in `vfs`, return 0: success, 1: full, 2: repeated name.
"""
function mj_makeEmptyFileVFS(vfs::Ref{mjVFS}, filename::String, filesize::Integer)
    ccall(
        (:mj_makeEmptyFileVFS, libmujoco),
        Cint,
        (Ptr{mjVFS}, Cstring, Cint),
        vfs,
        filename,
        filesize,
    )
end

"""
    mj_findFileVFS(vfs::Ref{mjVFS}, filename::String) -> Cint

Return file index of `filename` in `vfs`, or -1 if not found in `vfs`.
"""
function mj_findFileVFS(vfs::Ref{mjVFS}, filename::String)
    ccall((:mj_findFileVFS, libmujoco), Cint, (Ptr{mjVFS}, Cstring), vfs, filename)
end

"""
    mj_deleteFileVFS(vfs::Ref{mjVFS}, filename::String) -> Cint

Delete `filename` from `vfs`, return 0: success, -1: not found in VFS.
"""
function mj_deleteFileVFS(vfs::Ref{mjVFS}, filename::String)
    ccall((:mj_deleteFileVFS, libmujoco), Cint, (Ptr{mjVFS}, Cstring), vfs, filename)
end

"""
    mj_deleteVFS(vfs::Ref{mjVFS}) -> Cvoid

Delete all files from `vfs`.
"""
function mj_deleteVFS(vfs::Ref{mjVFS})
    ccall((:mj_deleteVFS, libmujoco), Cvoid, (Ptr{mjVFS},), vfs)
end

####
#### Parse and compile
####

"""
    mj_loadXML(filename::String[, vfs::Ref{mjVFS}) -> Ptr{mjModel}

Parse `filename` XML file in MJCF or URDF format, compile it, return low-level model.
If `vfs` is specified, look up files in `vfs` before checking disk.
Throws `MuJoCoException` if failure.
"""
@inline mj_loadXML(filename::String, vfs::Ref{mjVFS}) = _mj_loadXML(filename, vfs)
@inline mj_loadXML(filename::String) = _mj_loadXML(filename, Ptr{mjVFS}(0))
function _mj_loadXML(filename::String, vfs::Union{Ref{mjVFS},Ptr{mjVFS}})
    modelkind(filename) === :MJCF || throw(ArgumentError("Not a XML/MJCF file: $filename"))
    err = MVector{ERRORSIZE,UInt8}(undef)
    pm = ccall(
        (:mj_loadXML, libmujoco),
        Ptr{mjModel},
        (Cstring, Ptr{mjVFS}, Ptr{UInt8}, Cint),
        filename,
        vfs,
        err,
        ERRORSIZE,
    )
    pm == C_NULL && @mjerror SVector(err) "Not a valid XML file"
    return pm
end

"""
    mj_saveLastXML(filename::String, m::Model) -> Cint

Update XML data structures with info from low-level model `m`, save as MJCF
to `filename`. Returns 1 if success, else throws a `MuJoCoException`.
"""
function mj_saveLastXML(filename::String, m::Ptr{mjModel})
    errsz = 1000
    err = MVector{ERRORSIZE,UInt8}(undef)
    ret = ccall(
        (:mj_saveLastXML, libmujoco),
        Cint,
        (Cstring, Ptr{mjModel}, Ptr{UInt8}, Cint),
        filename,
        m,
        err,
        ERRORSIZE,
    )
    ret == 0 && @mjerror SVector(err)
    return ret
end

"""
    mj_freeLastXML() -> Cvoid

    Free last XML model if loaded. Called internally at each load.
"""
function mj_freeLastXML()
    ccall((:mj_freeLastXML, libmujoco), Cvoid, (Cvoid,), Cvoid)
end

####
#### Main simulation
####

"""
    mj_step(m::Model, d::Data) -> Cvoid

Advance simulation. use control callback if specified, otherwise use
controls in `d.ctrl`, `d.xfrc_applied`, `d.qfrc_applied`. RK4 available.
See also: [`mj_step1`](@ref), [`mj_step2`](@ref)
"""
function mj_step(m::Model, d::Data)
    ccall((:mj_step, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_step1(m::Model, d::Data) -> Cvoid

Advance simulation in two steps: before external force/control is set by user.
See also: [`mj_step2`](@ref), [`mj_step`](@ref)
"""
function mj_step1(m::Model, d::Data)
    ccall((:mj_step1, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_step2(m::Model, d::Data) -> Cvoid

Advance simulation in two steps: after external force/control is set by user.
See also: [`mj_step1`](@ref), [`mj_step`](@ref)
"""
function mj_step2(m::Model, d::Data)
    ccall((:mj_step2, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_forward(m::Model, d::Data) -> Cvoid

Compute forward dynamics.
"""
function mj_forward(m::Model, d::Data)
    ccall((:mj_forward, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_inverse(m::Model, d::Data) -> Cvoid

Compute inverse dynamics.
"""
function mj_inverse(m::Model, d::Data)
    ccall((:mj_inverse, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_forwardSkip(m::Model, d::Data, skipstage::mjtStage, skipsensor::Bool) -> Cvoid

Compute forward dynamics, skipping parts of computation pipeline as specified by
`skipstage`. Sensor computations can be skipped using `skipsensor`.
See also: [`mjtStage`](@ref)
"""
function mj_forwardSkip(m::Model, d::Data, skipstage::mjtStage, skipsensor::Bool)
    ccall(
        (:mj_forwardSkip, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Cint, Cint),
        m,
        d,
        skipstage,
        skipsensor,
    )
end

"""
    mj_inverseSkip(m::Model, d::Data, skipstage::mjtStage, skipsensor::Bool) -> Cvoid

Compute inverse dynamics, skipping parts of computation pipeline as specified by
`skipstage`. Sensor computations can be skipped using `skipsensor`.
See also: [`mjtStage`](@ref)
"""
function mj_inverseSkip(m::Model, d::Data, skipstage::mjtStage, skipsensor::Bool)
    ccall(
        (:mj_inverseSkip, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Cint, Cint),
        m,
        d,
        skipstage,
        skipsensor,
    )
end

####
#### Initialization
####

"""
    mj_defaultLROpt(opt::Ref{mjLROpt}) -> Cvoid

Set default options for length range computation.
"""
function mj_defaultLROpt(opt::Ref{mjLROpt})
    ccall((:mj_defaultLROpt, libmujoco), Cvoid, (Ptr{mjLROpt},), opt)
end

"""
    mj_defaultSolRefImp(solref::MJVec{mjtNum}, solimp::MJVec{mjtNum}) -> Cvoid

Set default solver parameters.
"""
function mj_defaultSolRefImp(solref::MJVec{mjtNum}, solimp::MJVec{mjtNum})
    ccall(
        (:mj_defaultSolRefImp, libmujoco),
        Cvoid,
        (Ptr{mjtNum}, Ptr{mjtNum}),
        solref,
        solimp,
    )
end

"""
    mj_defaultOption(opt::Ref{mjOption}) -> Cvoid

Set physics options to default values.
"""
function mj_defaultOption(opt::Ref{mjOption})
    ccall((:mj_defaultOption, libmujoco), Cvoid, (Ptr{mjOption},), opt)
end

"""
    mj_defaultVisual(vis::Ref{mjVisual}) -> Cvoid

Set visual options to default values.
"""
function mj_defaultVisual(vis::Ref{mjVisual})
    ccall((:mj_defaultVisual, libmujoco), Cvoid, (Ptr{mjVisual},), vis)
end

"""
    mj_copyModel(dest::Model, src::Model) -> Ref{mjModel}

Copy model `src` into `dest`
"""
function mj_copyModel(dest::Model, src::Model)
    ccall((:mj_copyModel, libmujoco), Ptr{mjModel}, (Ptr{mjModel}, Ptr{mjModel}), dest, src)
    dest
end

"""
    mj_copyModel(m::Model) -> Ptr{mjModel}

Create a copy of `m`, allocating new memory.
"""
function mj_copyModel(m::Model)
    ccall((:mj_copyModel, libmujoco), Ptr{mjModel}, (Ptr{mjModel}, Ptr{mjModel}), C_NULL, m)
end

"""
    mj_saveModel(m::Model, filename::String) -> Cvoid

Save `m` to `filename`
"""
function mj_saveModel(m::Model, filename::String)
    ccall(
        (:mj_saveModel, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Cstring, Ptr{Cvoid}, Cint),
        m,
        filename,
        C_NULL,
        0,
    )
end

"""
    mj_saveModel(m::Model, buffer::MJVec{UInt8}) -> Cvoid

Save `m` to `buffer`.
"""
function mj_saveModel(m::Model, buffer::MJVec{UInt8})
    ccall(
        (:mj_saveModel, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Cstring, Ptr{Cvoid}, Cint),
        m,
        C_NULL,
        buffer,
        length(buffer),
    )
end

"""
    mj_loadModel(filename::String) -> Ptr{mjModel}

Load binary `MJB` file from `filename` located on local filesystem.
"""
function mj_loadModel(filename::String)
    ccall((:mj_loadModel, libmujoco), Ptr{mjModel}, (Cstring, Ptr{mjVFS}), filename, C_NULL)
end

"""
    mj_loadModel(filename::String) -> Ptr{mjModel}

Load binary `MJB` file from `filename` in `vfs`.
"""
function mj_loadModel(filename::String, vfs::Ref{mjVFS})
    ccall((:mj_loadModel, libmujoco), Ptr{mjModel}, (Cstring, Ptr{mjVFS}), filename, vfs)
end

"""
    mj_deleteModel(m::Ptr{mjModel}) -> Cvoid

De-allocate model `m`.
Should only be called with `m` allocated by MuJoCo.
"""
function mj_deleteModel(m::Ptr{mjModel})
    ccall((:mj_deleteModel, libmujoco), Cvoid, (Ptr{mjModel},), m)
end

"""
    mj_sizeModel(m::Model) -> Cint

Size of buffer in bytes needed to hold `m`.
"""
function mj_sizeModel(m::Model)
    ccall((:mj_sizeModel, libmujoco), Cint, (Ptr{mjModel},), m)
end

"""
    mj_makeData(m::Model) -> Ptr{mjData}
Allocate `mjData` correponding to `m`.
"""
function mj_makeData(m::Model)
    ccall((:mj_makeData, libmujoco), Ptr{mjData}, (Ptr{mjModel},), m)
end

"""
    mj_copyData(dest::Data, m::Model, src::Data) -> Ptr{mjData}

Copy mjData `src` into `dest`.
"""
function mj_copyData(dest::Data, m::Model, src::Data)
    ccall(
        (:mj_copyData, libmujoco),
        Ptr{mjData},
        (Ptr{mjData}, Ptr{mjModel}, Ptr{mjData}),
        dest,
        m,
        src,
    )
end

"""
    mj_resetData(m::Model, d::Data) -> Cvoid

Set data to defaults.
"""
function mj_resetData(m::Model, d::Data)
    ccall((:mj_resetData, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_resetDataDebug(m::Model, d::Data, debug_value::Cuchar) -> Cvoid

Set `d` to defaults, fill everything else with `debug_value`.
"""
function mj_resetDataDebug(m::Model, d::Data, debug_value::Cuchar)
    ccall(
        (:mj_resetDataDebug, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Cuchar),
        m,
        d,
        debug_value,
    )
end

"""
    mj_resetDataKeyframe(m::Model, d::Data, key::Integer) -> Cvoid

Reset `d` and set fields from keyframe `key`.
"""
function mj_resetDataKeyframe(m::Model, d::Data, key::Integer)
    ccall(
        (:mj_resetDataKeyframe, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Cint),
        m,
        d,
        key,
    )
end

"""
    mj_deleteData(d::Ptr{mjData}) -> Nothiing

De-allocate `d`.
Should only be called with `d` allocated by MuJoCo.
"""
function mj_deleteData(d::Ptr{mjData})
    ccall((:mj_deleteData, libmujoco), Cvoid, (Ptr{mjData},), d)
end

"""
    mj_resetCallbacks() -> Cvoid
Reset all callbacks to C_NULL (C_NULL is the default).
"""
function mj_resetCallbacks()
    ccall((:mj_resetCallbacks, libmujoco), Cvoid, ())
end

"""
    mj_setConst(m::Model, d::Data) -> Cvoid

Set constant fields of mjModel, corresponding to qpos0 configuration.
"""
function mj_setConst(m::Model, d::Data)
    ccall((:mj_setConst, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_setLengthRange(m::Model, d::Data, index::Integer, opt::Ref{mjLROpt})

Set actuator_lengthrange for specified actuator; return 1 if ok, otherwise
throws `MuJoCoException`.
"""
function mj_setLengthRange(m::Model, d::Data, index::Integer, opt::Ref{mjLROpt})
    err = MVector{ERRORSIZE,UInt8}(undef)
    ret = ccall(
        (:mj_setLengthRange, libmujoco),
        Cint,
        (Ptr{mjModel}, Ptr{mjData}, Cint, Ptr{mjLROpt}, Cstring, Cint),
        m,
        d,
        index,
        opt,
        error,
        ERRORSIZE,
    )
    ret == 0 && @mjerror SVector(err)
    return ret
end

####
#### Printing
####

"""
    mj_printModel(m::Model, filename::String) -> Cvoid

Print `m` to `filename` on local filesystem.
"""
function mj_printModel(m::Model, filename::String)
    ccall((:mj_printModel, libmujoco), Cvoid, (Ptr{mjModel}, Cstring), m, filename)
end

"""
    mj_printData(m::Model, d::Data, filename::String) -> Cvoid
Print `d` to `filename` on local filesystem.
"""
function mj_printData(m::Model, d::Data, filename::String)
    ccall(
        (:mj_printData, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Cstring),
        m,
        d,
        filename,
    )
end

####
#### Forward simulation components
####

"""
    mj_fwdPosition(m::Model, d::Data) -> Cvoid

Run position-dependent computations.
"""
function mj_fwdPosition(m::Model, d::Data)
    ccall((:mj_fwdPosition, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_fwdVelocity(m::Model, d::Data) -> Cvoid

Run velocity-dependent computations.
"""
function mj_fwdVelocity(m::Model, d::Data)
    ccall((:mj_fwdVelocity, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_fwdActuation(m::Model, d::Data) -> Cvoid

Compute actuator force `d.qfrc_actuation`.
"""
function mj_fwdActuation(m::Model, d::Data)
    ccall((:mj_fwdActuation, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_fwdAcceleration(m::Model, d::Data) -> Cvoid

Add up all non-constraint forces, compute d.qacc_unc
"""
function mj_fwdAcceleration(m::Model, d::Data)
    ccall((:mj_fwdAcceleration, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_fwdConstraint(m::Model, d::Data) -> Cvoid

Run selected constraint solver
"""
function mj_fwdConstraint(m::Model, d::Data)
    ccall((:mj_fwdConstraint, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_Euler(m::Model, d::Data)

Run Euler integrator, semi-implicit in velocity.
"""
function mj_Euler(m::Model, d::Data)
    ccall((:mj_Euler, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_RungeKutta(m::Model, d::Data, N::Integer) -> Cvoid

Run Runge-Kutta explicit order-`N` integrator
"""
function mj_RungeKutta(m::Model, d::Data, N::Integer)
    ccall((:mj_RungeKutta, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}, Cint), m, d, N)
end

####
#### Inverse simulation components
####

"""
    mj_invPosition(m::Model, d::Data) -> Cvoid

Run position-dependent computations in inverse dynamics.
"""
function mj_invPosition(m::Model, d::Data)
    ccall((:mj_invPosition, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_invVelocity(m::Model, d::Data) -> Cvoid

Run velocity-dependent computations in inverse dynamics.
"""
function mj_invVelocity(m::Model, d::Data)
    ccall((:mj_invVelocity, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_invConstraint(m::Model, d::Data) -> Cvoid

Apply the analytical formula for inverse constraint dynamics.
"""
function mj_invConstraint(m::Model, d::Data)
    ccall((:mj_invConstraint, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_compareFwdInv(m::Model, d::Data) -> Cvoid

Compare forward and inverse dynamics, without changing results of forward dynamics.
Saves results in `d.fwdinv`.
"""
function mj_compareFwdInv(m::Model, d::Data)
    ccall((:mj_compareFwdInv, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

####
#### Sub-components
####

"""

    mj_sensorPos(m::Model, d::Data) -> Cvoid

Evaluate position-dependent sensors.
"""
function mj_sensorPos(m::Model, d::Data)
    ccall((:mj_sensorPos, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_sensorVel(m::Model, d::Data) -> Cvoid

Evaluate velcoity-dependent sensors.
"""
function mj_sensorVel(m::Model, d::Data)
    ccall((:mj_sensorVel, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_sensorAcc(m::Model, d::Data) -> Cvoid

Evaluate acceleration and force-dependent sensors.
"""
function mj_sensorAcc(m::Model, d::Data)
    ccall((:mj_sensorAcc, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_energyPos(m::Model, d::Data) -> Cvoid

Evaluate position-dependent energy (potential).
"""
function mj_energyPos(m::Model, d::Data)
    ccall((:mj_energyPos, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_energyVel(m::Model, d::Data) -> Cvoid

Evaluate velocity-dependent energy (kinetic).
"""
function mj_energyVel(m::Model, d::Data)
    ccall((:mj_energyVel, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_checkPos(m::Model, d::Data) -> Cvoid

Check qpos, reset if any element is too big or nan.
"""
function mj_checkPos(m::Model, d::Data)
    ccall((:mj_checkPos, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_checkVel(m::Model, d::Data) -> Cvoid

Check qvel, reset if any element is too big or nan.
"""
function mj_checkVel(m::Model, d::Data)
    ccall((:mj_checkVel, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_checkAcc(m::Model, d::Data) -> Cvoid

Check qacc, reset if any element is too big or nan.
"""
function mj_checkAcc(m::Model, d::Data)
    ccall((:mj_checkAcc, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_kinematics(m::Model, d::Data) -> Cvoid

Run forward kinematics.
"""
function mj_kinematics(m::Model, d::Data)
    ccall((:mj_kinematics, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_comPos(m::Model, d::Data) -> Cvoid

Map inertias and motion dofs to global frame centered at CoM.
"""
function mj_comPos(m::Model, d::Data)
    ccall((:mj_comPos, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_camlight(m::Model, d::Data) -> Cvoid

Compute camera and light positions and orientations.
"""
function mj_camlight(m::Model, d::Data)
    ccall((:mj_camlight, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_tendon(m::Model, d::Data) -> Cvoid

Compute tendon lengths, velocities and moment arms.
"""
function mj_tendon(m::Model, d::Data)
    ccall((:mj_tendon, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_transmission(m::Model, d::Data) -> Cvoid

Compute actuator transmission lengths and moments.
"""
function mj_transmission(m::Model, d::Data)
    ccall((:mj_transmission, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_crb(m::Model, d::Data) -> Cvoid

Run composite rigid body inertia algorithm (CRB).
"""
function mj_crb(m::Model, d::Data)
    ccall((:mj_crb, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_factorM(m::Model, d::Data) -> Cvoid

Compute sparse L'*D*L factorizaton of the inertia matrix
"""
function mj_factorM(m::Model, d::Data)
    ccall((:mj_factorM, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

# TODO for mj_solveM and mj_solveM2, what is n? Test. checkbounds
"""
    mj_solveM(m, d, x, y, n) -> Cvoid

Solve linear system M * x = y using factorization:  x = inv(L'*D*L)*y.
See also: [`mj_solveM2`](@ref)

# Arguments
- `m::Model`
- `d::Data`
- `x::MJVec{mjtNum}`
- `y::MJVec{mjtNum}`
- `n::Integer`

"""
function mj_solveM(m::Model, d::Data, x::MJVec{mjtNum}, y::MJVec{mjtNum}, n::Integer)
    ccall(
        (:mj_solveM, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjtNum}, Ptr{mjtNum}, Cint),
        m,
        d,
        x,
        y,
        length,
    )
end

"""
    mj_solveM2(m, d, x, y, n) -> Cvoid

Half of linear solve:  x = sqrt(inv(D))*inv(L')*y
Same arguments as [`mj_solveM`](@ref).
"""
function mj_solveM2(m::Model, d::Data, x::MJVec, y::MJVec, n::Integer)
    ccall(
        (:mj_solveM2, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjtNum}, Ptr{mjtNum}, Cint),
        m,
        d,
        x,
        y,
        n,
    )
end

"""
    mj_comVel(m::Model, d::Data) -> Cvoid

Compute cvel, cdof_dot.
"""
function mj_comVel(m::Model, d::Data)
    ccall((:mj_comVel, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_passive(m::Model, d::Data) -> Cvoid

Compute qfrc_passive from spring-dampers, viscosity and density.
"""
function mj_passive(m::Model, d::Data)
    ccall((:mj_passive, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_subtreeVel(m::Model, d::Data) -> Cvoid

Compute subtree linear velocity and angular momentum.
"""
function mj_subtreeVel(m::Model, d::Data)
    ccall((:mj_subtreeVel, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_rne(m::Model, d::Data, flg_acc::Integer, result::MJVec{mjtNum}) -> Cvoid

RNE: compute M(qpos)*qacc + C(qpos,qvel); flg_acc=0 removes inertial term.
"""
function mj_rne(m::Model, d::Data, flg_acc::Integer, result::MJVec)
    ccall(
        (:mj_rne, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Cint, Ptr{mjtNum}),
        m,
        d,
        flg_acc,
        result,
    )
end

"""
    mj_rnePostConstraint(m::Model, d::Data) -> Cvoid

RNE with complete data: compute cacc, cfrc_ext, cfrc_int.
"""
function mj_rnePostConstraint(m::Model, d::Data)
    ccall((:mj_rnePostConstraint, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_collision(m::Model, d::Data) -> Cvoid

Run collision detection.
"""
function mj_collision(m::Model, d::Data)
    ccall((:mj_collision, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_makeConstraint(m::Model, d::Data) -> Cvoid

Construct constraints.
"""
function mj_makeConstraint(m::Model, d::Data)
    ccall((:mj_makeConstraint, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_projectConstraint(m::Model, d::Data) -> Cvoid

Compute inverse constaint inertia `efc_AR`.
"""
function mj_projectConstraint(m::Model, d::Data)
    ccall((:mj_projectConstraint, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_referenceConstraint(m::Model, d::Data) -> Cvoid

Compute `efc_vel`, `efc_aref`.
"""
function mj_referenceConstraint(m::Model, d::Data)
    ccall((:mj_referenceConstraint, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjData}), m, d)
end

"""
    mj_constraintUpdate(m, d, jar, flg_coneHessian)
    mj_constraintUpdate(m, d, jar, cost, flg_coneHessian)

Compute `efc_state`, `efc_force`, `qfrc_constraint`, and (optionally) cone Hessians.
If specified, uses cost = s(`jar`) where jar = `Jac`*`qacc`-`aref`.

# Arguments
- `m::Model`
- `d::Data`
- `jar::MJVec{mjtNum}`
- `cost::MJVec{mjtNum}`
- `flg_coneHessian::Integer`
"""
@inline function mj_constraintUpdate(
    m::Model,
    d::Data,
    jar::MJVec{mjtNum},
    flg_coneHessian::Integer,
)
    _mj_constraintUpdate(m, d, jar, C_NULL, flg_coneHessian)
end
@inline function mj_constraintUpdate(
    m::Model,
    d::Data,
    jar::MJVec{mjtNum},
    cost::MJVec{mjtNum},
    flg_coneHessian::Integer,
)
    _mj_constraintUpdate(m, d, jar, cost, flg_coneHessian)
end
function _mj_constraintUpdate(m, d, jar, cost, flg_coneHessian)
    ccall(
        (:mj_constraintUpdate, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, MJVec, MJVec, Integer),
        m,
        d,
        jar,
        cost,
        flg_coneHessian,
    )
end

####
#### Support functions
####

"""
    mj_addContact(m::Model, d::Data, con::Ref{mjContact}) -> Cint

Add contact `con` to `d.contact` list. Return 0 if success; 1 if buffer full.
"""
function mj_addContact(m::Model, d::Data, con::Ref{mjContact})
    ccall(
        (:mj_addContact, libmujoco),
        Cint,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjContact}),
        m,
        d,
        con,
    )
end

"""
    mj_isPyramidal(m::Model) -> Cint

Determine type of friction cone.
"""
function mj_isPyramidal(m::Model)
    ccall((:mj_isPyramidal, libmujoco), Cint, (Ptr{mjModel},), m)
end

"""
    mj_isSparse(m::Model) -> Cint

Determine type of constraint Jacobian.
"""
function mj_isSparse(m::Model)
    ccall((:mj_isSparse, libmujoco), Cint, (Ptr{mjModel},), m)
end

"""
    mj_isDual(m::Model) -> Cint

Determine type of solver (PGS is dual, CG and Newton are primal).
"""
function mj_isDual(m::Model)
    ccall((:mj_isDual, libmujoco), Cint, (Ptr{mjModel},), m)
end

"""
    mj_mulJacVec(m::Model, d::Data, res::MJVec{mjtNum}, vec::MJVec{mjtNum}) -> Cvoid

Multiply dense or sparse constraint Jacobian by vector.
See also: [`mj_mulJacTVec`](@ref)
"""
function mj_mulJacVec(m::Model, d::Data, res::MJVec{mjtNum}, vec::MJVec)
    ccall(
        (:mj_mulJacVec, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjtNum}, Ptr{mjtNum}),
        m,
        d,
        res,
        vec,
    )
end

"""
    mj_mulJacTVec(m::Model, d::Data, res::MJVec{mjtNum}, vec::MJVec{mjtNum}) -> Cvoid

Multiply dense or sparse constraint Jacobian transpose by vector.
See also: [`mj_mulJacVec`](@ref)
"""
function mj_mulJacTVec(m::Model, d::Data, res::MJVec, vec::MJVec)
    ccall(
        (:mj_mulJacTVec, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjtNum}, Ptr{mjtNum}),
        m,
        d,
        res,
        vec,
    )
end

"""
    mj_jac(m, d, jacp, jacr, point, body) -> Cvoid

Compute 3/6-by-nv Jacobian of global `point` attached to `body`.

# Arguments
- `m::Model`
- `d::Data`
- `jacp::MJVec{mjtNum}`
- `jacr::MJVec{mjtNum}`
- `point::SizedMJVec{3,mjtNum}`:
- `body::Integer`
"""
function mj_jac(
    m::Model,
    d::Data,
    jacp::MJVec{mjtNum},
    jacr::MJVec{mjtNum},
    point::StaticVector{3,mjtNum},
    body::Integer,
)
    ccall(
        (:mj_jac, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjtNum}, Ptr{mjtNum}, SVector{3,mjtNum}, Cint),
        m,
        d,
        jacp,
        jacr,
        point,
        body,
    )
end

"""
    mj_jacBody(m, d, jacp, jacr, point, body) -> Cvoid

Compute body frame end-effector Jacobian.

# Arguments
- `m::Model`
- `d::Data`
- `jacp::MJVec`
- `jacr::MJVec`
- `point::SVector{3,mjtNum}`
- `body::Integer`
"""
function mj_jacBody(
    m::Model,
    d::Data,
    jacp::MJVec{mjtNum},
    jacr::MJVec{mjtNum},
    body::Integer,
)
    ccall(
        (:mj_jacBody, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjtNum}, Ptr{mjtNum}, Cint),
        m,
        d,
        jacp,
        jacr,
        body,
    )
end

"""
    mj_jacBody(m, d, jacp, jacr, point, body) -> Cvoid

Compute body frame end-effector Jacobian.

# Arguments
- `m::Model`
- `d::Data`
- `jacp::MJVec`
- `jacr::MJVec`
- `body::Integer`
"""
function mj_jacBodyCom(m::Model, d::Data, jacp::MJVec, jacr::MJVec, body::Integer)
    ccall(
        (:mj_jacBodyCom, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjtNum}, Ptr{mjtNum}, Cint),
        m,
        d,
        jacp,
        jacr,
        body,
    )
end

"""
    mj_jacGeom(m, d, jacp, jacr, point, geom) -> Cvoid

Compute body frame end-effector Jacobian.

# Arguments
- `m::Model`
- `d::Data`
- `jacp::MJVec`
- `jacr::MJVec`
- `geom::Integer`
"""
function mj_jacGeom(m::Model, d::Data, jacp::MJVec, jacr::MJVec, geom::Integer)
    ccall(
        (:mj_jacGeom, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjtNum}, Ptr{mjtNum}, Cint),
        m,
        d,
        jacp,
        jacr,
        geom,
    )
end

"""
    mj_jacSite(m, d, jacp, jacr, point, geom) -> Cvoid

Compute body frame end-effector Jacobian.

# Arguments
- `m::Model`
- `d::Data`
- `jacp::MJVec`
- `jacr::MJVec`
- `site::Integer`
"""
function mj_jacSite(m::Model, d::Data, jacp::MJVec, jacr::MJVec, site::Integer)
    ccall(
        (:mj_jacSite, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjtNum}, Ptr{mjtNum}, Cint),
        m,
        d,
        jacp,
        jacr,
        site,
    )
end

"""
Compute translation Jacobian of point, and rotation Jacobian of axis
"""
function mj_jacPointAxis(
    m::Model,
    d::Data,
    jacPoint::MJVec{mjtNum},
    jacAxis::MJVec{mjtNum},
    point::SVector{3,mjtNum},
    axis::SVector{3,mjtNum},
    body::Integer,
)
    ccall(
        (:mj_jacPointAxis, libmujoco),
        Cvoid,
        (
         Ptr{mjModel},
         Ptr{mjData},
         Ptr{mjtNum},
         Ptr{mjtNum},
         SVector{3,mjtNum},
         SVector{3,mjtNum},
         Cint,
        ),
        m,
        d,
        jacPoint,
        jacAxis,
        point,
        axis,
        body,
    )
end

"""get id of object with specified name; -1: not found; type is mjtObj"""
function mj_name2id(m::Model, type::Union{Integer,mjtObj}, name::String)
    ccall(
        (:mj_name2id, libmujoco),
        Cint,
        (Ptr{mjModel}, Cint, Cstring),
        m,
        type,
        pointer(name),
    )
end

"""get name of object with specified id; 0: invalid type or id; type is mjtObj"""
function mj_id2name(m::Model, type::Union{Integer,mjtObj}, id::Integer)
    name = ccall(
        (:mj_id2name, libmujoco),
        Cstring,
        (Ptr{mjModel}, Cint, Cint),
        m,
        type,
        id,
    ) # julia to c indexing
    name == C_NULL ? nothing : unsafe_string(name)
end

"""convert sparse inertia matrix M into full matrix"""
function mj_fullM(m::Model, dst::MJVec, M::MJVec)
    ccall(
        (:mj_fullM, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjtNum}, Ptr{mjtNum}),
        m,
        dst,
        M,
    )
end

"""multiply vector by inertia matrix"""
function mj_mulM(m::Model, d::Data, res::MJVec, vec::MJVec)
    ccall(
        (:mj_mulM, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjtNum}, Ptr{mjtNum}),
        m,
        d,
        res,
        vec,
    )
end

"""Multiply vector by (inertia matrix)^(1/2)."""
function mj_mulM2(m::Model, d::Data, res::MJVec, vec::MJVec)
    ccall(
        (:mj_mulM2, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjtNum}, Ptr{mjtNum}),
        m,
        d,
        res,
        vec,
    )
end

"""Add inertia matrix to destination matrix.
Destination can be sparse uncompressed, or dense when all int* are NULL
"""
function mj_addM(
    m::Model,
    d::Data,
    dst::MJVec,
    rownnz::Vector{Integer},
    rowadr::Vector{Integer},
    colind::Vector{Integer},
)
    ccall(
        (:mj_addM, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjtNum}, Ptr{Cint}, Ptr{Cint}, Ptr{Cint}),
        m,
        d,
        dst,
        rownnz,
        rowadr,
        colind,
    )
end

"""apply cartesian force and torque (outside xfrc_applied mechanism)"""
function mj_applyFT(
    m::Model,
    d::Data,
    force::MJVec,
    torque::MJVec,
    point::MJVec,
    body::Integer,
    qfrc_target::MJVec,
)
    ccall(
        (:mj_applyFT, libmujoco),
        Cvoid,
        (
         Ptr{mjModel},
         Ptr{mjData},
         Ptr{mjtNum},
         Ptr{mjtNum},
         Ptr{mjtNum},
         Cint,
         Ptr{mjtNum},
        ),
        m,
        d,
        force,
        torque,
        point,
        body,
        qfrc_target,
    )
end

"""compute object 6D velocity in object-centered frame, world/local orientation"""
function mj_objectVelocity(
    m::Model,
    d::Data,
    objtype::Integer,
    objid::Integer,
    res::MJVec,
    flg_local::Integer,
)
    ccall(
        (:mj_objectVelocity, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Cint, Cint, Ptr{mjtNum}, Cint),
        m,
        d,
        objtype,
        objid,
        res,
        flg_local,
    )
end

"""compute object 6D acceleration in object-centered frame, world/local orientation"""
function mj_objectAcceleration(
    m::Model,
    d::Data,
    objtype::Integer,
    objid::Integer,
    res::MJVec,
    flg_local::Integer,
)
    ccall(
        (:mj_objectAcceleration, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Cint, Cint, Ptr{mjtNum}, Cint),
        m,
        d,
        objtype,
        objid,
        res,
        flg_local,
    )
end

"""extract 6D force:torque for one contact, in contact frame"""
function mj_contactForce(m::Model, d::Data, id::Integer, result::MJVec)
    ccall(
        (:mj_contactForce, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Cint, Ptr{mjtNum}),
        m,
        d,
        id,
        result,
    )
end

"""compute velocity by finite-differencing two positions"""
function mj_differentiatePos(m::Model, qvel::MJVec, dt::mjtNum, qpos1::MJVec, qpos2::MJVec)
    ccall(
        (:mj_differentiatePos, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjtNum}, mjtNum, Ptr{mjtNum}, Ptr{mjtNum}),
        m,
        qvel,
        dt,
        qpos1,
        qpos2,
    )
end

"""integrate position with given velocity"""
function mj_integratePos(m::Model, qpos::MJVec, qvel::MJVec, dt::mjtNum)
    ccall(
        (:mj_integratePos, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjtNum}, Ptr{mjtNum}, mjtNum),
        m,
        qpos,
        qvel,
        dt,
    )
end

"""normalize all quaterions in qpos-type vector"""
function mj_normalizeQuat(m::Model, qpos::MJVec)
    ccall((:mj_normalizeQuat, libmujoco), Cvoid, (Ptr{mjModel}, Ptr{mjtNum}), m, qpos)
end

"""map from body local to global Cartesian coordinates"""
function mj_local2Global(
    d::Data,
    xpos::MJVec,
    xmat::MJVec,
    pos::MJVec,
    quat::MJVec,
    body::Integer,
    sameframe::mjtByte,
)
    ccall(
        (:mj_local2Global, libmujoco),
        Cvoid,
        (Ptr{mjData}, Ptr{mjtNum}, Ptr{mjtNum}, Ptr{mjtNum}, Ptr{mjtNum}, Cint, mjtByte),
        d,
        xpos,
        xmat,
        pos,
        quat,
        body,
        sameframe,
    )
end

"""sum all body masses"""
function mj_getTotalmass(m::Model)
    ccall((:mj_getTotalmass, libmujoco), mjtNum, (Ptr{mjModel},), m)
end

"""scale body masses and inertias to achieve specified total mass"""
function mj_setTotalmass(m::Model, newmass::mjtNum)
    ccall((:mj_setTotalmass, libmujoco), Cvoid, (Ptr{mjModel}, mjtNum), m, newmass)
end

"""version number: 1.0.2 is encoded as 102 #TODO comment??"""
function mj_version()
    ccall((:mj_version, libmujoco), Cint, ())
end

#---------------------- Ray collisions -------------------------------------------------

"""
Intersect ray (pnt+x*vec, x>=0) with visible geoms, except geoms in bodyexclude.
Return geomid and distance (x) to nearest surface, or -1 if no intersection.
geomgroup, flg_static are as in mjvOption; geomgroup==NULL skips group exclusion.
"""
function mj_ray(
    m::Model,
    d::Data,
    pnt::MJVec,
    vec::MJVec,
    geomgroup::Vector{mjtByte},
    flg_static::mjtByte,
    bodyexclude::Integer,
    geomid::Vector{Integer},
)
    ccall(
        (:mj_ray, libmujoco),
        mjtNum,
        (
         Ptr{mjModel},
         Ptr{mjData},
         Ptr{mjtNum},
         Ptr{mjtNum},
         Ptr{mjtByte},
         mjtByte,
         Cint,
         Ptr{Cint},
        ),
        m,
        d,
        pnt,
        vec,
        geomgroup,
        flg_static,
        bodyexclude,
        geomid,
    )
end

"""Interect ray with hfield, return nearest distance or -1 if no intersection."""
function mj_rayHfield(m::Model, d::Data, geomid::Integer, pnt::MJVec, vec::MJVec)
    ccall(
        (:mj_rayHfield, libmujoco),
        mjtNum,
        (Ptr{mjModel}, Ptr{mjData}, Cint, Ptr{mjtNum}, Ptr{mjtNum}),
        m,
        d,
        geomid,
        pnt,
        vec,
    )
end

"""Interect ray with mesh, return nearest distance or -1 if no intersection."""
function mj_rayMesh(m::Model, d::Data, geomid::Integer, pnt::MJVec, vec::MJVec)
    ccall(
        (:mj_rayMesh, libmujoco),
        mjtNum,
        (Ptr{mjModel}, Ptr{mjData}, Cint, Ptr{mjtNum}, Ptr{mjtNum}),
        m,
        d,
        geomid,
        pnt,
        vec,
    )
end

#---------------------- Abstract interaction -------------------------------------------

"""set default camera"""
function mjv_defaultCamera(cam::Ref{mjvCamera})
    ccall((:mjv_defaultCamera, libmujoco), Cvoid, (Ptr{mjvCamera},), cam)
end

"""set default perturbation"""
function mjv_defaultPerturb(pert::Ref{mjvPerturb})
    ccall((:mjv_defaultPerturb, libmujoco), Cvoid, (Ptr{mjvPerturb},), pert)
end

"""transform pose from room to model space"""
function mjv_room2model(
    modelpos::MJVec,
    modelquat::MJVec,
    roompos::MJVec,
    roomquat::MJVec,
    scn::Ref{mjvScene},
)
    ccall(
        (:mjv_room2model, libmujoco),
        Cvoid,
        (Ptr{mjtNum}, Ptr{mjtNum}, Ptr{mjtNum}, Ptr{mjtNum}, Ptr{mjvScene}),
        modelpos,
        modelquat,
        roompos,
        roomquat,
        scn,
    )
end

"""transform pose from model to room space"""
function mjv_model2room(
    roompos::MJVec,
    roomquat::MJVec,
    modelpos::MJVec,
    modelquat::MJVec,
    scn::Ref{mjvScene},
)
    ccall(
        (:mjv_model2room, libmujoco),
        Cvoid,
        (Ptr{mjtNum}, Ptr{mjtNum}, Ptr{mjtNum}, Ptr{mjtNum}, Ptr{mjvScene}),
        roompos,
        roomquat,
        modelpos,
        modelquat,
        scn,
    )
end

"""get camera info in model space: average left and right OpenGL cameras"""
function mjv_cameraInModel(headpos::MJVec, forward::MJVec, scn::Ref{mjvScene})
    ccall(
        (:mjv_cameraInModel, libmujoco),
        Cvoid,
        (Ptr{mjtNum}, Ptr{mjtNum}, Ptr{mjvScene}),
        headpos,
        forward,
        scn,
    )
end

"""get camera info in room space: average left and right OpenGL cameras"""
function mjv_cameraInRoom(headpos::MJVec, forward::MJVec, scn::Ref{mjvScene})
    ccall(
        (:mjv_cameraInRoom, libmujoco),
        Cvoid,
        (Ptr{mjtNum}, Ptr{mjtNum}, Ptr{mjvScene}),
        headpos,
        forward,
        scn,
    )
end

"""get frustum height at unit distance from camera; average left and right OpenGL cameras"""
function mjv_frustumHeight(scn::Ref{mjvScene})
    ccall((:mjv_frustumHeight, libmujoco), mjtNum, (Ptr{mjvScene},), scn)
end

"""rotate 3D vec in horizontal plane by angle between (0,1) and (forward_x,forward_y)"""
function mjv_alignToCamera(res::MJVec, vec::MJVec, forward::MJVec)
    ccall(
        (:mjv_alignToCamera, libmujoco),
        Cvoid,
        (Ptr{mjtNum}, Ptr{mjtNum}, Ptr{mjtNum}),
        res,
        vec,
        forward,
    )
end

"""move camera with mouse; action is mjtMouse"""
function mjv_moveCamera(
    m::Model,
    action::Union{Integer, mjtMouse},
    reldx::mjtNum,
    reldy::mjtNum,
    scn::Ref{mjvScene},
    cam::Ref{mjvCamera},
)
    ccall(
        (:mjv_moveCamera, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Cint, mjtNum, mjtNum, Ptr{mjvScene}, Ptr{mjvCamera}),
        m,
        action,
        reldx,
        reldy,
        scn,
        cam,
    )
end

"""move perturb object with mouse; action is mjtMouse"""
function mjv_movePerturb(
    m::Model,
    d::Data,
    action::Union{Integer, mjtMouse},
    reldx::mjtNum,
    reldy::mjtNum,
    scn::Ref{mjvScene},
    pert::Ref{mjvPerturb},
)
    ccall(
        (:mjv_movePerturb, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Cint, mjtNum, mjtNum, Ptr{mjvScene}, Ptr{mjvPerturb}),
        m,
        d,
        action,
        reldx,
        reldy,
        scn,
        pert,
    )
end

"""move model with mouse; action is mjtMouse"""
function mjv_moveModel(
    m::Model,
    action::Integer,
    reldx::mjtNum,
    reldy::mjtNum,
    roomup::MJVec,
    scn::Ref{mjvScene},
)
    ccall(
        (:mjv_moveModel, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Cint, mjtNum, mjtNum, Ptr{mjtNum}, Ptr{mjvScene}),
        m,
        action,
        reldx,
        reldy,
        roomup,
        scn,
    )
end

"""copy perturb pos,quat from selected body; set scale for perturbation"""
function mjv_initPerturb(m::Model, d::Data, scn::Ref{mjvScene}, pert::Ref{mjvPerturb})
    ccall(
        (:mjv_initPerturb, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjvScene}, Ptr{mjvPerturb}),
        m,
        d,
        scn,
        pert,
    )
end

"""set perturb pos,quat in d->mocap when selected body is mocap, and in d->qpos otherwise
d->qpos written only if flg_paused and subtree root for selected body has free joint
"""
function mjv_applyPerturbPose(m::Model, d::Data, pert::Ref{mjvPerturb}, flg_paused::Integer)
    ccall(
        (:mjv_applyPerturbPose, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjvPerturb}, Cint),
        m,
        d,
        pert,
        flg_paused,
    )
end

"""set perturb force,torque in d->xfrc_applied, if selected body is dynamic"""
function mjv_applyPerturbForce(m::Model, d::Data, pert::Ref{mjvPerturb})
    ccall(
        (:mjv_applyPerturbForce, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjvPerturb}),
        m,
        d,
        pert,
    )
end

"""Return the average of two OpenGL cameras."""
function mjv_averageCamera(cam1::Ptr{mjvGLCamera}, cam2::Ref{mjvGLCamera})
    ccall(
        (:mjv_averageCamera, libmujoco),
        mjvGLCamera,
        (Ptr{mjvGLCamera}, Ptr{mjvGLCamera}),
        cam1,
        cam2,
    )
end

"""Select geom or skin with mouse, return bodyid; -1: none selected."""
function mjv_select(
    m::Model,
    d::Data,
    vopt::Ref{mjvOption},
    aspectratio::mjtNum,
    relx::mjtNum,
    rely::mjtNum,
    scn::Ref{mjvScene},
    selpnt::MJVec,
    geomid::Ref{Cint},
    skinid::Ref{Cint}
)
    ccall(
        (:mjv_select, libmujoco),
        Cint,
        (
         Ptr{mjModel},
         Ptr{mjData},
         Ptr{mjvOption},
         mjtNum,
         mjtNum,
         mjtNum,
         Ptr{mjvScene},
         Ptr{mjtNum},
         Ptr{Cint},
         Ptr{Cint},
        ),
        m,
        d,
        vopt,
        aspectratio,
        relx,
        rely,
        scn,
        selpnt,
        geomid,
        skinid,
    )
end

#---------------------- Asbtract visualization -----------------------------------------

"""set default visualization options"""
function mjv_defaultOption(opt::Ref{mjvOption})
    ccall((:mjv_defaultOption, libmujoco), Cvoid, (Ptr{mjvOption},), opt)
end

"""Set default figure."""
function mjv_defaultFigure(fig::Ref{mjvFigure})
    ccall((:mjv_defaultFigure, libmujoco), Cvoid, (Ptr{mjvFigure},), fig)
end

"""Initialize given geom fields when not NULL, set the rest to their default values."""
function mjv_initGeom(
    geom::Ref{mjvGeom},
    type::Integer,
    size::MJVec,
    pos::MJVec,
    mat::MJVec,
    rgba::Ptr{Float32},
)
    ccall(
        (:mjv_initGeom, libmujoco),
        Cvoid,
        (Ptr{mjvGeom}, Cint, Ptr{mjtNum}, Ptr{mjtNum}, Ptr{mjtNum}, Ptr{Cfloat}),
        geom,
        type,
        size,
        pos,
        mat,
        rbga,
    )
end

"""Set (type, size, pos, mat) for connector-type geom between given points.
Assume that mjv_initGeom was already called to set all other properties.
"""
function mjv_makeConnector(
    geom::Ref{mjvGeom},
    type::Integer,
    width::mjtNum,
    a0::mjtNum,
    a1::mjtNum,
    a2::mjtNum,
    b0::mjtNum,
    b1::mjtNum,
    b2::mjtNum,
)
    ccall(
        (:mjv_makeConnector, libmujoco),
        Cvoid,
        (Ptr{mjvGeom}, Cint, mjtNum, mjtNum, mjtNum, mjtNum, mjtNum, mjtNum, mjtNum),
        geom,
        type,
        width,
        a0,
        a1,
        a2,
        b0,
        b1,
        b2,
    )
end

"""Set default abstract scene."""
function mjv_defaultScene(scn::Ref{mjvScene})
    ccall((:mjv_defaultScene, libmujoco), Cvoid, (Ptr{mjvScene},), scn)
end

"""allocate and init abstract scene"""
function mjv_makeScene(m::Model, scn::Ref{mjvScene}, maxgeom::Integer)
    ccall(
        (:mjv_makeScene, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjvScene}, Cint),
        m,
        scn,
        maxgeom,
    )
end

"""free abstract scene"""
function mjv_freeScene(scn::Ref{mjvScene})
    ccall((:mjv_freeScene, libmujoco), Cvoid, (Ptr{mjvScene},), scn)
end

"""update entire scene"""
function mjv_updateScene(
    m::Model,
    d::Data,
    opt::Ref{mjvOption},
    pert::Ref{mjvPerturb},
    cam::Ref{mjvCamera},
    catmask::Union{Integer, mjtCatBit},
    scn::Ref{mjvScene},
)
    ccall(
        (:mjv_updateScene, libmujoco),
        Cvoid,
        (
         Ptr{mjModel},
         Ptr{mjData},
         Ptr{mjvOption},
         Ptr{mjvPerturb},
         Ptr{mjvCamera},
         Cint,
         Ptr{mjvScene},
        ),
        m,
        d,
        opt,
        pert,
        cam,
        catmask,
        scn,
    )
end

"""add geoms from selected categories"""
function mjv_addGeoms(
    m::Model,
    d::Data,
    opt::Ref{mjvOption},
    pert::Ref{mjvPerturb},
    catmask::Union{Integer, mjtCatBit},
    scn::Ref{mjvScene},
)
    ccall(
        (:mjv_addGeoms, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjvOption}, Ptr{mjvPerturb}, Cint, Ptr{mjvScene}),
        m,
        d,
        opt,
        pert,
        catmask,
        scn,
    )
end

"""Make list of lights."""
function mjv_makeLights(m::Model, d::Data, scn::Ref{mjvScene})
    ccall(
        (:mjv_makeLights, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjvScene}),
        m,
        d,
        scn,
    )
end

"""update camera only"""
function mjv_updateCamera(m::Model, d::Data, cam::Ref{mjvCamera}, scn::Ref{mjvScene})
    ccall(
        (:mjv_updateCamera, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjvCamera}, Ptr{mjvScene}),
        m,
        d,
        cam,
        scn,
    )
end

"""Update skins."""
function mjv_updateSkin(m::Model, d::Data, scn::Ref{mjvScene})
    ccall(
        (:mjv_updateSkin, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjData}, Ptr{mjvScene}),
        m,
        d,
        scn,
    )
end

#---------------------- OpenGL rendering -----------------------------------------------

"""set default mjrContext"""
function mjr_defaultContext(con::Ref{mjrContext})
    ccall((:mjr_defaultContext, libmujoco), Cvoid, (Ptr{mjrContext},), con)
end

"""allocate resources in custom OpenGL context; fontscale is mjtFontScale"""
function mjr_makeContext(m::Model, con::Ref{mjrContext}, fontscale::Union{mjtFontScale, Integer})
    ccall(
        (:mjr_makeContext, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjrContext}, Cint),
        m,
        con,
        fontscale,
    )
end

"""Change font of existing context."""
function mjr_changeFont(fontscale::Integer, con::Ref{mjrContext})
    ccall((:mjr_changeFont, libmujoco), Cvoid, (Cint, Ptr{mjrContext}), fontscale, con)
end

"""Add Aux buffer with given index to context; free previous Aux buffer."""
function mjr_addAux(
    index::Integer,
    width::Integer,
    height::Integer,
    samples::Integer,
    con::Ref{mjrContext},
)
    ccall(
        (:mjr_addAux, libmujoco),
        Cvoid,
        (Cint, Cint, Cint, Cint, Ptr{mjrContext}),
        index,
        width,
        height,
        samples,
        con,
    )
end

"""free resources in custom OpenGL context, set to default"""
function mjr_freeContext(con::Ref{mjrContext})
    ccall((:mjr_freeContext, libmujoco), Cvoid, (Ptr{mjrContext},), con)
end

"""(re) upload texture to GPU"""
function mjr_uploadTexture(m::Model, con::Ref{mjrContext}, texid::Integer)
    ccall(
        (:mjr_uploadTexture, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjrContext}, Cint),
        m,
        con,
        texid,
    )
end

"""(re) upload mesh to GPU"""
function mjr_uploadMesh(m::Model, con::Ref{mjrContext}, meshid::Integer)
    ccall(
        (:mjr_uploadMesh, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjrContext}, Cint),
        m,
        con,
        meshid,
    )
end

"""(re) upload height field to GPU"""
function mjr_uploadHField(m::Model, con::Ref{mjrContext}, hfieldid::Integer)
    ccall(
        (:mjr_uploadHField, libmujoco),
        Cvoid,
        (Ptr{mjModel}, Ptr{mjrContext}, Cint),
        m,
        con,
        hfieldid,
    )
end

"""Make con->currentBuffer current again."""
function mjr_restoreBuffer(con::Ref{mjrContext})
    ccall((:mjr_restoreBuffer, libmujoco), Cvoid, (Ptr{mjrContext},), con)
end

"""set OpenGL framebuffer for rendering: mjFB_WINDOW or mjFB_OFFSCREEN
if only one buffer is available, set that buffer and ignore framebuffer argument
"""
function mjr_setBuffer(framebuffer::Integer, con::Ref{mjrContext})
    ccall((:mjr_setBuffer, libmujoco), Cvoid, (Cint, Ptr{mjrContext}), framebuffer, con)
end

"""read pixels from current OpenGL framebuffer to client buffer
viewport is in OpenGL framebuffer; client buffer starts at (0,0)
"""
function mjr_readPixels(
    rgb::MJVec{Cuchar}, # TODO can rgb be C_NULL as well?
    depth::Union{Ptr{Nothing}, MJVec},
    viewport::mjrRect,
    con::Ref{mjrContext},
)
    ccall(
        (:mjr_readPixels, libmujoco),
        Cvoid,
        (Ptr{Cuchar}, Ptr{Cfloat}, mjrRect, Ptr{mjrContext}),
        rgb,
        depth,
        viewport,
        con,
    )
end

"""draw pixels from client buffer to current OpenGL framebuffer
viewport is in OpenGL framebuffer; client buffer starts at (0,0)
"""
function mjr_drawPixels(
    rgb::MJVec{Cuchar},
    depth::MJVec,
    viewport::mjrRect,
    con::Ref{mjrContext},
)
    ccall(
        (:mjr_drawPixels, libmujoco),
        Cvoid,
        (Ptr{Cuchar}, Ptr{Cfloat}, mjrRect, Ptr{mjrContext}),
        rgb,
        depth,
        viewport,
        con,
    )
end

"""blit from src viewpoint in current framebuffer to dst viewport in other framebuffer
if src, dst have different size and flg_depth==0, color is interpolated with GL_LINEAR
"""
function mjr_blitBuffer(
    src::mjrRect,
    dst::mjrRect,
    flg_color::Integer,
    flg_depth::Integer,
    con::Ref{mjrContext},
)
    ccall(
        (:mjr_blitBuffer, libmujoco),
        Cvoid,
        (mjrRect, mjrRect, Cint, Cint, Ptr{mjrContext}),
        src,
        dst,
        flg_color,
        flg_depth,
        con,
    )
end

"""Set Aux buffer for custom OpenGL rendering (call restoreBuffer when done)."""
function mjr_setAux(index::Integer, con::Ref{mjrContext})
    ccall((:mjr_setAux, libmujoco), Cvoid, (Cint, Ptr{mjrContext}), index, con)
end

"""Blit from Aux buffer to con->currentBuffer."""
function mjr_blitAux(
    index::Integer,
    src::mjrRect,
    left::Integer,
    bottom::Integer,
    con::Ref{mjrContext},
)
    ccall(
        (:mjr_blitAux, libmujoco),
        Cvoid,
        (Cint, mjrRect, Cint, Cint, Ptr{mjrContext}),
        index,
        src,
        left,
        bottom,
        con,
    )
end

"""draw text at (x,y) in relative coordinates; font is mjtFont"""
function mjr_text(
    font::Union{Integer, mjtFont},
    txt::AbstractString,
    con::Ref{mjrContext},
    x::Real,
    y::Real,
    r::Real,
    g::Real,
    b::Real,
)
    ccall(
        (:mjr_text, libmujoco),
        Cvoid,
        (Cint, Cstring, Ptr{mjrContext}, Cfloat, Cfloat, Cfloat, Cfloat, Cfloat),
        font,
        txt,
        con,
        x,
        y,
        r,
        g,
        b,
    )
end

"""draw text overlay; font is mjtFont; gridpos is mjtGridPos"""
function mjr_overlay(
    font::Union{Integer, mjtFont},
    gridpos::Union{Integer, mjtGridPos},
    viewport::mjrRect,
    overlay::String,
    overlay2::String,
    con::Ref{mjrContext},
)
    ccall(
        (:mjr_overlay, libmujoco),
        Cvoid,
        (Cint, Cint, mjrRect, Cstring, Cstring, Ptr{mjrContext}),
        font,
        gridpos,
        viewport,
        overlay,
        overlay2,
        con,
    )
end

"""get maximum viewport for active buffer"""
function mjr_maxViewport(con::Ref{mjrContext})
    ccall((:mjr_maxViewport, libmujoco), mjrRect, (Ptr{mjrContext},), con)
end

"""draw rectangle"""
function mjr_rectangle(viewport::mjrRect, r::Cfloat, g::Cfloat, b::Cfloat, a::Cfloat)
    ccall(
        (:mjr_rectangle, libmujoco),
        Cvoid,
        (mjrRect, Cfloat, Cfloat, Cfloat, Cfloat),
        viewport,
        r,
        g,
        b,
        a,
    )
end

"""draw lines"""
function mjr_figure(viewport::mjrRect, fig::Ref{mjvFigure}, con::Ref{mjrContext})
    ccall(
        (:mjr_figure, libmujoco),
        Cvoid,
        (mjrRect, Ptr{mjvFigure}, Ptr{mjrContext}),
        viewport,
        fig,
        con,
    )
end

"""3D rendering"""
function mjr_render(viewport::mjrRect, scn::Ref{mjvScene}, con::Ref{mjrContext})
    ccall(
        (:mjr_render, libmujoco),
        Cvoid,
        (mjrRect, Ptr{mjvScene}, Ptr{mjrContext}),
        viewport,
        scn,
        con,
    )
end

"""call glFinish"""
function mjr_finish()
    ccall((:mjr_finish, libmujoco), Cvoid, ())
end

"""call glGetError and return result"""
function mjr_getError()
    ccall((:mjr_getError, libmujoco), Cint, ())
end

"""Find first rectangle containing mouse, -1: not found."""
function mjr_findRect(x::Integer, y::Integer, nrect::Integer, rect::MJVec{mjrRect})
    ccall(
        (:mjr_findRect, libmujoco),
        Cint,
        (Cint, Cint, Cint, Ptr{mjrRect}),
        x,
        y,
        nrect,
        rect,
    )
end

#---------------------- Utility functions: error and memory ----------------------------

"""print matrix to screen"""
function mju_printMat(mat::MJVec, nr::Integer, nc::Integer)
    ccall((:mju_printMat, libmujoco), Cvoid, (Ptr{mjtNum}, Cint, Cint), mat, nr, nc)
end

"""Print sparse matrix to screen."""
function mju_printMatSparse(
    mat::MJVec,
    nr::Integer,
    rownnz::Vector{Integer},
    rowadr::Vector{Integer},
    colind::Vector{Integer},
)
    ccall(
        (:mju_printMatSparse, libmujoco),
        Cvoid,
        (Ptr{mjtNum}, Cint, Ptr{Cint}, Ptr{Cint}, Ptr{Cint}),
        mat,
        nr,
        rownnz,
        rowadr,
        colind,
    )
end

"""Interect ray with pure geom, return nearest distance or -1 if no intersection."""
function mju_rayGeom(
    pos::MJVec,
    mat::MJVec,
    size::MJVec,
    pnt::MJVec,
    vec::MJVec,
    geomtype::Integer,
)
    ccall(
        (:mju_rayGeom, libmujoco),
        mjtNum,
        (Ptr{mjtNum}, Ptr{mjtNum}, Ptr{mjtNum}, Ptr{mjtNum}, Ptr{mjtNum}, Cint),
        pos,
        mat,
        size,
        pnt,
        vec,
        geomtype,
    )
end

"""Interect ray with skin, return nearest vertex id."""
function mju_raySkin(
    nface::Integer,
    nvert::Integer,
    face::MJVec{Integer},
    vert::MJVec{Float32},
    pnt::MJVec,
    vec::MJVec,
    vertid::MJVec{Integer},
)
    ccall(
        (:mju_raySkin, libmujoco),
        mjtNum,
        (Integer, Integer, Ptr{Cint}, Ptr{Cfloat}, Ptr{mjtNum}, Ptr{mjtNum}, Ptr{Cint}),
        nface,
        nvert,
        face,
        veert,
        pnt,
        vec,
        vertid,
    )
end

"""main error function; does not return to caller"""
function mju_error(msg::String)
    ccall((:mju_error, libmujoco), Cvoid, (Cstring,), msg)
end

"""error function mju_with int argument; msg is a printf format string"""
function mju_error_i(msg::String, i::Integer)
    ccall((:mju_error_i, libmujoco), Cvoid, (Cstring, Cint), msg, i)
end

"""error function mju_with string argument"""
function mju_error_s(msg::String, text::String)
    ccall((:mju_error_s, libmujoco), Cvoid, (Cstring, Cstring), msg, text)
end

"""main warning function; returns to caller"""
function mju_warning(msg::String)
    ccall((:mju_warning, libmujoco), Cvoid, (Cstring,), msg)
end

"""warning function mju_with int argument"""
function mju_warning_i(msg::String, i::Integer)
    ccall((:mju_warning_i, libmujoco), Cvoid, (Cstring, Cint), msg, i)
end

"""warning function mju_with string argument"""
function mju_warning_s(msg::String, text::String)
    ccall((:mju_warning_s, libmujoco), Cvoid, (Cstring, Cstring), msg, text)
end

"""clear user error and memory handlers"""
function mju_clearHandlers()
    ccall((:mju_clearHandlers, libmujoco), Cvoid, ())
end

"""allocate memory; byte-align on 8; pad size to multiple of 8"""
function mju_malloc(size::Integer)
    ccall((:mju_malloc, libmujoco), Ptr{Cvoid}, (Cint,), size)
end

"""free memory (with free() by default)"""
function mju_free(ptr::Ptr{Cvoid})
    ccall((:mju_free, libmujoco), Cvoid, (Ptr{Cvoid},), ptr)
end

"""high-level warning function: count warnings in Data, print only the first"""
function mj_warning(d::Data, warning::Integer, info::Integer)
    ccall((:mj_warning, libmujoco), Cvoid, (Ptr{mjData}, Cint, Cint), d, warning, info)
end

"""Write [datetime, type: message] to MUJOCO_LOG.TXT."""
function mju_writeLog(type::String, msg::String)
    ccall((:mju_writeLog, libmujoco), Cvoid, (Cstring, Cstring), type, msg)
end

#---------------------- Utility functions: miscellaneous -------------------------------

"""Muscle active force, prm = (range[2], force, scale, lmin, lmax, vmax, fpmax, fvmax)."""
function mju_muscleGain(
    len::mjtNum,
    vel::mjtNum,
    lengthrange::MJVec,
    acc0::mjtNum,
    prm::MJVec,
)
    @assert length(lengthrange) >= 2
    @assert length(prm) >= 9
    ccall(
        (:mju_muscleGain, libmujoco),
        mjtNum,
        (mjtNum, mjtNum, Ptr{mjtNum}, mjtNum, Ptr{mjtNum}),
        len,
        vel,
        lengthrange,
        acc0,
        prm,
    )
end

"""Muscle passive force, prm = (range[2], force, scale, lmin, lmax, vmax, fpmax, fvmax)."""
function mju_muscleBias(len::mjtNum, lengthrange::MJVec, acc0::mjtNum, prm::MJVec)
    @assert length(lengthrange) >= 2
    @assert length(prm) >= 9
    ccall(
        (:mju_muscleBias, libmujoco),
        mjtNum,
        (mjtNum, Ptr{mjtNum}, mjtNum, Ptr{mjtNum}),
        len,
        lengthrange,
        acc0,
        prm,
    )
end

"""Muscle activation dynamics, prm = (tau_act, tau_deact)."""
function mju_muscleDynamics(ctrl::mjtNum, act::mjtNum, prm::MJVec)
    @assert length(prm) >= 2
    ccall(
        (:mju_muscleDynamics, libmujoco),
        mjtNum,
        (mjtNum, mjtNum, Ptr{mjtNum}),
        ctrl,
        act,
        prm,
    )
end

"""convert contact force to pyramid representation"""
function mju_encodePyramid(pyramid::MJVec, force::MJVec, mu::MJVec, dim::Integer)
    ccall(
        (:mju_encodePyramid, libmujoco),
        Cvoid,
        (Ptr{mjtNum}, Ptr{mjtNum}, Ptr{mjtNum}, Cint),
        pyramid,
        force,
        mu,
        dim,
    )
end

"""convert pyramid representation to contact force"""
function mju_decodePyramid(force::MJVec, pyramid::MJVec, mu::MJVec, dim::Integer)
    ccall(
        (:mju_decodePyramid, libmujoco),
        Cvoid,
        (Ptr{mjtNum}, Ptr{mjtNum}, Ptr{mjtNum}, Cint),
        force,
        pyramid,
        mu,
        dim,
    )
end

"""integrate spring-damper analytically, return pos(dt)"""
function mju_springDamper(pos0::mjtNum, vel0::mjtNum, Kp::mjtNum, Kv::mjtNum, dt::mjtNum)
    ccall(
        (:mju_springDamper, libmujoco),
        mjtNum,
        (mjtNum, mjtNum, mjtNum, mjtNum, mjtNum),
        pos0,
        vel0,
        Kp,
        Kv,
        dt,
    )
end

"""convert type id (mjtObj) to type name"""
function mju_type2Str(type::Union{mjtObj, Integer})
    name = ccall((:mju_type2Str, libmujoco), Cstring, (Cint,), type)
    name == C_NULL ? nothing : unsafe_string(name)
end

"""convert type name to type id (mjtObj)"""
function mju_str2Type(str::String)
    ccall((:mju_str2Type, libmujoco), Cint, (Cstring,), str)
end

"""warning text"""
function mju_warningText(warning::Integer, info::Integer)
    ccall((:mju_warningText, libmujoco), Cstring, (Cint, Cint), warning, info)
end

"""return 1 if nan or abs(x)>mjMAXVAL, 0 otherwise"""
function mju_isBad(x::mjtNum)
    ccall((:mju_isBad, libmujoco), Cint, (mjtNum,), x)
end

"""return 1 if all elements are 0"""
function mju_isZero(vec::MJVec, n::Integer)
    ccall((:mju_isZero, libmujoco), Cint, (Ptr{mjtNum}, Cint), vec, n)
end

"""standard normal random number generator (optional second number)"""
function mju_standardNormal(num2::MJVec)
    ccall((:mju_standardNormal, libmujoco), mjtNum, (Ptr{mjtNum},), num2)
end

"""convert from float to mjtNum"""
function mju_f2n(res::MJVec, vec::MJVec, n::Integer)
    ccall((:mju_f2n, libmujoco), Cvoid, (Ptr{mjtNum}, Ptr{Cfloat}, Cint), res, vec, n)
end

"""convert from mjtNum to float"""
function mju_n2f(res::MJVec, vec::MJVec, n::Integer)
    ccall((:mju_n2f, libmujoco), Cvoid, (Ptr{Cfloat}, Ptr{mjtNum}, Cint), res, vec, n)
end

"""convert from double to mjtNum"""
function mju_d2n(res::MJVec, vec::MJVec{Cdouble}, n::Integer)
    ccall((:mju_d2n, libmujoco), Cvoid, (Ptr{mjtNum}, Ptr{Cdouble}, Cint), res, vec, n)
end

"""convert from mjtNum to double"""
function mju_n2d(res::MJVec{Cdouble}, vec::MJVec, n::Integer)
    ccall((:mju_n2d, libmujoco), Cvoid, (Ptr{Cdouble}, Ptr{mjtNum}, Cint), res, vec, n)
end

"""insertion sort, increasing order"""
function mju_insertionSort(list::MJVec, n::Integer)
    ccall((:mju_insertionSort, libmujoco), Cvoid, (Ptr{mjtNum}, Cint), list, n)
end

"""Generate Halton sequence."""
function mju_Halton(index::Integer, base::Integer)
    ccall((:mju_Halton, libmujoco), mjtNum, (Cint, Cint), index, base)
end

"""Call strncpy, then set dst[n-1] = 0."""
function mju_strncpy(dst::String, src::String, n::Integer)
    ccall((:mju_strncpy, libmujoco), String, (Cstring, Cstring, Cint), dst, src, n)
end


text:
using BSON: @save, @load
using PyPlot
using LaTeXStrings
using Optim
using QuadGK

@load "./Measurement_k=2.bson" E2
@load "./Measurement_k=3.bson" E3
@load "./Measurement_k=4.bson" E4
@load "./Measurement_k=5.bson" E5
@load "./Measurement_k=6.bson" E6
@load "./Measurement_k=7.bson" E7

g(τ) = quadgk(u->(u-τ)^2*sqrt(2/π)*exp(-u^2/2), τ, Inf, rtol=1e-3)[1]
function δ(n, s)
    ρ = s/n
    f(τ) = ρ*(1+τ^2) + (1 - ρ)*g(τ)
    res = optimize(f, 0.0, 1000.0)
    return (minimum(res) - 1/sqrt(n*s))*n
end
# δ(n, s) = s*log(n/s);
Δ(k, n, s) = max(50, k^2*δ(n, s));
s = 5;
ns = collect(50:15:500)
ticks = [50, 200, 350, 500]
c = 0.5
vx = 0.1

fig, axes = subplots(nrows=1, ncols=3)
fig.subplots_adjust(bottom=0.1, top=0.9, left=0.1, right=0.85, wspace=0.27, hspace=0.02)

subplot(1,3,1)
im = imshow(0.7*E2, cmap="Blues", extent=[50,500,50,500], vmin=0, vmax=vx)
k = 2; ms = map(n->Δ(k,n,s), ns); plot(ns, ms, color="red")
nl = 50 + mapreduce(x->x<0,+,ns - c*ms)*15
plot(repeat([nl], 31), ns, color="yellow", linestyle="dashed")
xticks(ticks, fontsize=6)
yticks(ticks, fontsize=6)
xlabel("n")
ylabel("m")
title("k=2")

subplot(1,3,2)
im = imshow(E4, cmap="Blues", extent=[50,500,50,500], vmin=0, vmax=vx)
k = 3; ms = map(n->Δ(k,n,s), ns); plot(ns, ms, color="red")
nl = 50 + mapreduce(x->x<0,+,ns - c*ms)*15
plot(repeat([nl], 31), ns, color="yellow", linestyle="dashed")
xticks(ticks, fontsize=6)
yticks(ticks, fontsize=6)
xlabel("n")
# ylabel("m")
title("k=3")

subplot(1,3,3)
k = 4; ms = map(n->Δ(k,n,s), ns)
im = imshow(E6, cmap="Blues", extent=[50,500,50,500], vmin=0, vmax=vx)
plot(ns, ms, color="red")
nl = 50 + mapreduce(x->x<0,+,ns - c*ms)*15
plot(repeat([nl], 31), ns, color="yellow", linestyle="dashed")
xticks(ticks, fontsize=6)
yticks(ticks, fontsize=6)
xlabel("n")
# ylabel("m")
title("k=4")

# subplot(2,3,4)
# im = imshow(E5, cmap="Blues", extent=[50,500,50,500], vmin=0, vmax=0.1)
# k = 5; ms = map(n->Δ(k,n,s), ns); plot(ns, ms, color="red")
# nl = 50 + mapreduce(x->x<0,+,ns - c*ms)*15
# plot(repeat([nl], 31), ns, color="yellow", linestyle="dashed")
# xticks(ticks, fontsize=6)
# yticks(ticks, fontsize=6)
# title("k=5")

# subplot(2,3,5)
# im = imshow(E6, cmap="Blues", extent=[50,500,50,500], vmin=0, vmax=0.1)
# k = 6; ms = map(n->Δ(k,n,s), ns); plot(ns, ms, color="red")
# nl = 50 + mapreduce(x->x<0,+,ns - c*ms)*15
# plot(repeat([nl], 31), ns, color="yellow", linestyle="dashed")
# xticks(ticks, fontsize=6)
# yticks(ticks, fontsize=6)
# title("k=6")

# subplot(2,3,6)
# im = imshow(E7, cmap="Blues", extent=[50,500,50,500], vmin=0, vmax=0.1)
# k = 7; ms = map(n->Δ(k,n,s), ns); plot(ns, ms, color="red")
# nl = 50 + mapreduce(x->x<0,+,ns - c*ms)*15
# plot(repeat([nl], 31), ns, color="yellow", linestyle="dashed")
# xticks(ticks, fontsize=6)
# yticks(ticks, fontsize=6)
# title("k=7")

cb_ax = fig.add_axes([0.9, 0.36, 0.02, 0.28])
fig.colorbar(im, cax=cb_ax)


text:
module HSM

include("hierarchical_state_machine.jl")

# Types
export AbstractHsmEvent, AbstractHsmState, HsmStateInfo,
    HsmStateTransitionError, HsmUnhandledEventError

# Interfaces
export handle_event!, transition_to_deep_history!,
    transition_to_shallow_history!, transition_to_state!

# Extendable Interfaces
export on_entry!, on_event!, on_exit!, on_initialize!

# Getters and setters
export active_substate, active_substate!, parent_state, parent_state!

end # module


text:
module PathTracer

export Vect, Ray, Sphere, Plane, Scene

using LinearAlgebra
using UnPack, Setfield, MuladdMacro
using Images, FileIO
using Printf
using Distributions
using Base.Cartesian
using ProgressMeter

###
### Math
###
struct Vect{T} <: AbstractVector{T}
    x::T
    y::T
    z::T
end
Vect(x, y, z) = Vect(promote(x, y, z)...,)
Base.getindex(v::Vect, i::Int) = getfield(v, i)
Base.size(::Vect) = (3,)
Base.Tuple(v::Vect) = v.x, v.y, v.z
Vect(xx::Tuple) = Vect(xx...,)
Vect(x::Number) = Vect(@ntuple 3 i->x)
@inline randvect(d::Distribution) = Vect(@ntuple 3 i->rand(d))
Base.promote_rule(::Type{Vect{T}}, ::Type{Vect{S}}) where {T,S} = Vect{promote_type(T, S)}
Base.convert(::Type{Vect{T}}, v::Vect{S}) where {T,S} = Vect(@ntuple 3 i->convert(T, v[i]))
Images.RGB(v::Vect) = RGB((@ntuple 3 i->v[i])...)

@muladd LinearAlgebra.dot(v0::Vect, v1::Vect) = v0.x * v1.x + v0.y * v1.y + v0.z * v1.z
@muladd LinearAlgebra.cross(v0::Vect, v1::Vect) = Vect(
    v0.y * v1.z - v0.z * v1.y,
    v0.z * v1.x - v0.x * v1.z,
    v0.x * v1.y - v0.y * v1.x,
   )
LinearAlgebra.norm(v::Vect) = sqrt(dot(v, v))
LinearAlgebra.normalize(v::Vect) = v * inv(norm(v))
for op in [:+, :-, :*, :/]
    @eval Base.$op(v0::Vect, v1::Vect) = Vect(@ntuple 3 i -> $op(v0[i], v1[i]))
    @eval Base.$op(v0::Vect, s::Number) = Vect(@ntuple 3 i -> $op(v0[i], s))
    if op !== :/
        @eval Base.$op(s::Number, v0::Vect) = Vect(@ntuple 3 i -> $op(s, v0[i]))
    end
end
Base.:(-)(v::Vect{T}) where T = Vect(@ntuple 3 i -> -v[i])
Base.muladd(v1::Vect, v2::Vect, v3::Vect) = Vect(@ntuple 3 i -> muladd(v1[i], v2[i], v3[i]))
Base.muladd(v1::Vect, v2::Number, v3::Vect) = Vect(@ntuple 3 i -> muladd(v1[i], v2, v3[i]))
Base.zero(::Type{Vect{T}}) where T = Vect(@ntuple 3 _->zero(T))
Base.zero(::T) where {T<:Vect} = zero(T)

###
### Ray
###
struct Ray{V}
    org::V
    dir::V
    Ray(org::V, dir::V) where V = new{V}(org, normalize(dir))
end
@inline @muladd extrapolate(ray::Ray, t) = ray.org + t * ray.dir

struct Intersection{T,P,N,M}
    t::T
    p::P
    n::N
    front::Bool
    material::M
end
@inline function set_face_normal(insec::Intersection, r::Ray, outward_norm::Vect)
    @set! insec.front = front = r.dir'outward_norm < 0
    @set! insec.n = front ? outward_norm : -outward_norm
    return insec
end

###
### Material
###
abstract type AbstractMaterial
end
@enum MaterialType begin
    LAMBERTIAN
    METAL
    DIELECTRIC
end
Base.@kwdef struct Material{C,E,F,I} <: AbstractMaterial
    albedo::C = Vect(0, 0, 0.0)
    emission::E = nothing
    fuzz::F = 0.0
    ir::I = 1.0
    type::MaterialType = LAMBERTIAN
end
@inline @muladd function scatter(insec::Intersection, ray::Ray)
    @unpack dir = ray
    @unpack n, p, material, front = insec
    if material.type === LAMBERTIAN
        scatter_dir = n + random_unit_vector()
        attenutation = material.albedo
        visable = true
    elseif material.type === METAL
        scatter_dir = reflect(dir, n) + material.fuzz * random_in_unit_sphere()
        attenutation = material.albedo
        visable = scatter_dir'n > 0
    else # DIELECTRIC
        attenutation = Vect(1, 1, 1.0)
        @unpack ir = material
        ir = front ? inv(ir) : ir
        scatter_dir = refract(dir, n, ir)
        visable = true
    end
    scattered = Ray(p, scatter_dir)
    return visable, scattered, attenutation
end

@muladd reflect(v::Vect, n::Vect) = v - (2*(v'n))*n # assume normalized
@inline @fastmath @muladd function refract(uv::Vect, n::Vect, ir)
    cosθ = min(-(uv'n), 1)
    sinθ = sqrt(1 - cosθ^2)
    cannot_refract = ir * sinθ > 1
    (cannot_refract || reflectance(cosθ, ir) > rand()) && return reflect(uv, n)
    r_perp = ir * (uv + cosθ*n)
    r_para = -sqrt(abs(1 - r_perp'r_perp)) * n
    return r_perp + r_para
end

@inline function reflectance(cosθ, ir)
    r₀ = (1 - ir) / (1 + ir)
    r₀ = r₀^2
    return r₀ + (1 - r₀)*(1 - cosθ)^5
end

###
### Shapes
###
abstract type AbstractShapes
end
struct Sphere{V,T,M} <: AbstractShapes
    center::V
    radius::T
    material::M
end
@inline @muladd function Base.intersect(sphere::Sphere, ray::Ray)
    T = eltype(ray.dir)
    rs = ray.org - sphere.center
    B = (2 * rs)'ray.dir
    C = rs'rs - sphere.radius^2
    D = B^2 - 4 * C
    if D > zero(D)
        dist = sqrt(D)
        sol1 = -B + dist
        sol2 = -B - dist
        return sol2 > 1.0e-6 ? sol2/2 :
               sol1 > 1.0e-6 ? sol1/2 : zero(T)
    end
    return zero(T)
end
@inline normal(sphere::Sphere, p0) = normalize(p0 - sphere.center)

struct Plane{V,M} <: AbstractShapes
    p::V
    n::V
    material::M
    Plane(p::V, n::V, material::M) where {V,M} = new{V,M}(p, normalize(n), material)
end

@inline @muladd function Base.intersect(plane::Plane, ray::Ray)
    T = eltype(ray.dir)
    v = ray.dir'plane.n

    abs(v) < 1.0e-6 && return zero(T)

    iv = -inv(v)
    t = (plane.n'ray.org + plane.p) * iv
    return t < 1.0e-6 ? zero(T) : t
end
normal(plane::Plane, _) = plane.n

###
### Camera and Coordinate transformation
###
struct Camera{L,P,V}
    lens_radius::L
    origin::P
    lower_left_corner::P
    horizontal::V
    vertical::V
    u::V
    v::V
    w::V
end
Camera(lens_radius, args...) = Camera(lens_radius, promote(args...)...)
@muladd function Camera(;
                lookfrom = Vect(0, 0, 0.0),
                lookat = Vect(0, 0, -1.0),
                vup = Vect(0, 1, 0.0),
                vfov = 90,
                aspect_ratio = 16/9,
                aperture = 2.0,
                focus_dist = norm(lookfrom - lookat),
               )
    θ = deg2rad(vfov)
    h = tan(θ/2)
    viewport_height = 2h
    viewport_width = aspect_ratio * viewport_height

    w = normalize(lookfrom - lookat)
    u = normalize(vup × w)
    v = w × u

    origin = lookfrom
    horizontal = focus_dist * viewport_width * u
    vertical = focus_dist * viewport_height * v
    lower_left_corner = origin - horizontal/2 - vertical/2 - focus_dist*w
    lens_radius = aperture / 2
    Camera(lens_radius, origin, lower_left_corner, horizontal, vertical, u, v, w)
end
@muladd function Ray(camera::Camera, s, t)
    @unpack lens_radius, origin, lower_left_corner, horizontal, vertical, u, v, w = camera
    rd = lens_radius * random_in_unit_disk()
    offset = u * rd.x + v * rd.y
    org = origin + offset
    Ray(org, lower_left_corner + s * horizontal + t * vertical - org)
end

function xy2xyz((x, y), (w, h))
    fovx = pi / 4
    fovy = (h / w) * fovx
    Vect(
         ((2 * x - w) / w) * tan(fovx),
        -((2 * y - h) / h) * tan(fovy),
        -1.0,
       );
end

function plane2hemishpere(u1, u2)
    r = sqrt(1.0 - u1^2)
    φ = 2 * PI * u2;
    return Vect(cos(φ)*r, sin(φ)*r, u1)
end

###
### Sampling
###
@inline function random_in_unit_sphere()
    while true
        p = randvect(Uniform(-1.0, 1.0))
        p'p < 1 && return p
    end
end

@inline random_in_hemisphere(n) = (v = random_in_unit_sphere(); dot(n, v) > 0 ? v : -v)

@inline function random_unit_vector()
    φ = rand(Uniform(0, 2pi))
    z = rand(Uniform(-1, 1.0))
    r = sqrt(1.0 - z^2)
    return Vect(cos(φ)*r, sin(φ)*r, z)
end

@inline function random_in_unit_disk()
    while true
        p = Vect(rand(Uniform(-1, 1.0)), rand(Uniform(-1, 1.0)), 0.0)
        p'p < 1 && return p
    end
end

###
### Scene
###
struct Scene{I,S,P}
    img::I
    spheres::S
    planes::P
    spp::Int # smaples per pixel
end

@inline function Base.intersect(scene::Scene, ray::Ray)
    insec = Intersection(Inf, zero(ray.org), zero(ray.dir), false, first(scene.spheres).material)
    hit = false
    for o in scene.spheres
        t = intersect(o, ray)
        if 1.0e-6 < t < insec.t
            @set! insec.t = t
            @set! insec.p = p = extrapolate(ray, t)
            @set! insec.n = n = normal(o, p)
            insec = set_face_normal(insec, ray, n)
            @set! insec.material = o.material
            hit = true
        end
    end
    return hit, insec
end

###
### Ray tracing
###
@muladd function ray_color(scene::Scene, r::Ray, depth::Int)
    black = Vect(0.0, 0.0, 0.0)
    depth <= 0 && return black
    hit, insec = intersect(scene, r)
    if hit
        visable, scattered, attenutation = scatter(insec, r)
        if visable
            color = ray_color(scene, scattered, depth-1)
            return color * attenutation
        else
            return black
        end
    end
    t = 0.5 * (r.dir.y + 1)
    (1.0-t)*Vect(1.0, 1.0, 1.0) + t*Vect(0.5, 0.7, 1.0)
end

@muladd function raytrace!(scene::Scene, camera::Camera, depth::Int; verbose=true)
    @unpack img, spp = scene
    @unpack origin, lower_left_corner, horizontal, vertical = camera
    he, wi = size(img)
    scale = inv(spp)
    progress = Progress(wi, dt=0.5,
                        barglyphs=BarGlyphs('|','█', ['▁' ,'▂' ,'▃' ,'▄' ,'▅' ,'▆', '▇'],' ','|',))
    Threads.@threads for w in 0:wi-1
        verbose && next!(progress)
        for h in 0:he-1
            vcolor = Vect(0.0, 0.0, 0.0)
            for _ in 1:spp
                # anti-aliasing
                u = (w + rand()) / (wi - 1)
                v = (h + rand()) / (he - 1)
                ray = Ray(camera, u, v)
                vcolor += ray_color(scene, ray, depth)
            end
            # gamma correction
            color = RGB((@ntuple 3 i->sqrt(scale * vcolor[i]))...)
            img[he-h, w+1] = color
        end
    end
    return scene
end

function make_scene(;image_height = 1200, aspect_ratio = 3/2, spp=5)
    image_width = floor(Int, image_height * aspect_ratio)
    img = zeros(RGB{Float64}, image_height, image_width)
    material_ground = Material(albedo=Vect(0.5, 0.5, 0.5), type=LAMBERTIAN)
    s = Sphere(Vect(0.0, -1000.0, 0.0), 1000.0, material_ground)
    spheres = [s]
    for a in -11:11, b in -11:11
        choose_mat = rand()
        center = Vect(a + 0.9*rand(), 0.2, b + 0.9*rand())
        if norm(center - Vect(4, 0.2, 0)) > 0.9
            if choose_mat < 0.8
                albedo = randvect(Uniform(0, 1.0)) * randvect(Uniform(0, 1.0))
                sphere_material = Material(albedo=albedo, type=LAMBERTIAN)
            elseif choose_mat < 0.95
                albedo = randvect(Uniform(0, 1.0))
                fuzz = rand(Uniform(0, 0.5))
                sphere_material = Material(albedo=albedo, fuzz=fuzz, type=METAL)
            else
                sphere_material = Material(ir=1.5, type=DIELECTRIC)
            end
            push!(spheres, Sphere(center, 0.2, sphere_material))
        end
    end

    material1 = Material(ir=1.5, type=DIELECTRIC)
    push!(spheres, Sphere(Vect(0.0, 1, 0), 1.0, material1))

    material2 = Material(albedo=Vect(0.4, 0.2, 0.1), type=LAMBERTIAN)
    push!(spheres, Sphere(Vect(-4.0, 1, 0), 1.0, material2))

    material3 = Material(albedo=Vect(0.7, 0.6, 0.5), fuzz=0.0, type=METAL)
    push!(spheres, Sphere(Vect(4.0, 1, 0), 1.0, material3))
    Scene(img, spheres, nothing, spp)
end

make_camera(;aspect_ratio=3/2) = Camera(;
        lookfrom = Vect(13,  2,  3.0),
        lookat   = Vect(0,   0,  0.0),
        vup      = Vect(0,   1,  0.0),
        vfov     = 20,
        aspect_ratio = aspect_ratio,
        aperture = 0.1,
        focus_dist = 10.0,
    )

function main(;
                verbose = true,
                image_height = 1200,
                aspect_ratio = 4/3,
                spp::Int = 5,
                depth::Int = 5,
             )
    scene = make_scene(image_height=image_height, aspect_ratio=aspect_ratio, spp=spp)

    camera = make_camera(aspect_ratio=aspect_ratio)

    raytrace!(scene, camera, depth; verbose=verbose)
    save(File(format"PNG", "ray.png"), scene.img)
end

export main, make_scene, make_camera, raytrace!

end # module


text:
######################################################################
# vehicle.jl
#
######################################################################

# Vehicle is the mobile sensor
# x is east-west position
# y is north-south position
# (0,0) is south west
type Vehicle
	x::Float64				# x-location
	y::Float64				# y-location
	heading::Float64		# degrees east of north
	max_step::Float64
	sensor::Sensor

	function Vehicle(x::Real, y::Real, h::Real, ms::Real, s::Sensor)
		return new(float(x),float(y),float(h),float(ms),s)
	end

	# Default uses BearingOnly
	function Vehicle(x::Real, y::Real)
		return new( float(x), float(y), 0.0, 2.0, BearingOnly(10.0) )
	end
	function Vehicle(x::Real, y::Real, h::Real)
        return new( float(x), float(y), float(h), 2.0, BearingOnly(10.0) )
	end
	function Vehicle(x::Real, y::Real, s::Sensor)
		return new( float(x), float(y), 0.0, 2.0, s)
	end

end

function get_pose(x::Vehicle)
    return (x.x, x.y, x.heading)
end

function reset!(m::SearchDomain, x::Vehicle)
	x.x = m.length/2.0
	x.y = m.length/2.0
	x.heading = 0.0
end

function new_pose(p::Pose, a::Action)
	new_x = p[1] + a[1]
	new_y = p[2] + a[2]
	new_h = mod(p[3] + a[3], 360.0)
    return new_x, new_y, new_h
end

# Does the bounds checking on the action, to see if stays in search domain
# Ensures heading is within [0,360) (other parts of code assume this)
function new_pose(m::SearchDomain, x::Vehicle, a::Action)
	return new_pose(m, (x.x, x.y, x.heading), a)
end
# TODO: add vehicle limits...
function new_pose(m::SearchDomain, p::Pose, a::Action)
	#new_x = max(min(p[1] + a[1], m.length), 0.0)
	#new_y = max(min(p[2] + a[2], m.length), 0.0)
	new_x = p[1] + a[1]
	new_y = p[2] + a[2]
	new_h = mod(p[3] + a[3], 360.0)
	return new_x, new_y, new_h
end

"""
`act!(m::SearchDomain, x::Vehicle, a::Action)`
"""
function act!(m::SearchDomain, x::Vehicle, a::Action)
	x.x, x.y, x.heading = new_pose(m, x, a)
end

"""
`observe(m::SearchDomain, x::Vehicle)`

Sample an observation. Returns a float between 0 and 360.
"""
function observe(m::SearchDomain, x::Vehicle)
	p = (x.x, x.y, x.heading)
	observe(m.theta, x.sensor, p)
end

# version for array of vehicles
function observe(m::SearchDomain, vx::Vector{Vehicle})
	num_vehicles = length(vx)
	o_arr = Array{Float64}(num_vehicles)
	for i = 1:num_vehicles
		pose_i = (vx[i].x, vx[i].y, vx[i].heading)
		o_arr[i] = observe(m, vx[i].sensor, pose_i)
	end
	return o_arr
end

# not sure where else to put this
# variant of true_bearing that takes in vehicle
true_bearing(x::Vehicle, theta) = true_bearing( (x.x, x.y), theta)


text:
module MetaLearning

using Flux
using Distributions: Uniform, Normal
using Statistics: mean
using Printf
using Plots
using Base.Iterators: partition
using Random: randperm

export SineWave, Linear, transfer_learn, fomaml, reptile, eval_model,
       xavier_uniform, plot_eval_data

"""
```
eval_model(model, x::AbstractArray, testx::AbstractArray, task=SineWave();
           opt=Descent(1e-2), updates=32)
```

Evaluates the `model` on a sine wave `task` training to sample `x` with `updates`
amount of gradient steps using `opt`.

Evaluation loss is calculated based on the mean squared error
between model predictions and sine wave values on `testx`.
"""
function eval_model(model, x::AbstractArray, testx::AbstractArray, task=SineWave();
                    opt=Descent(0.02), updates=32)
    weights = params(model)
    prev_weights = deepcopy(Flux.data.(weights))

    y = task(x)
    testy = task(testx)
    init_preds = model(testx')
    test_loss = Flux.mse(init_preds, testy')

    test_losses = Float32[]
    push!(test_losses, Flux.data(test_loss))

    print(task, "\n")
    @printf("Before finetuning, Loss = %f\n", test_loss)
    for i in 1:updates
        l = Flux.mse(model(x'), y')
        Flux.back!(l)
        Flux.Optimise._update_params!(opt, weights)
        test_loss = Flux.mse(model(testx'), testy')
        push!(test_losses, Flux.data(test_loss))
        @printf("After %d fits, Loss = %f\n", i, test_loss)
    end
    final_preds = model(testx')

    # reset weights to state before finetune
    Flux.loadparams!(model, prev_weights)

    return (x=x, testx=testx, y=y, testy=testy,
            initial_predictions=Array(Flux.data(init_preds)'),
            final_predictions=Array(Flux.data(final_preds)'),
            test_losses=test_losses)
end

function plot_eval_data(data::NamedTuple, title="")
    return plot([data.x, data.testx, data.testx, data.testx],
                [data.y, data.testy, data.initial_predictions, data.final_predictions],
                line=[:scatter :path :path :path],
                label=["Sampled points", "Ground truth", "Before finetune", "After finetune"],
                foreground_color_legend=:white, background_color_legend=:transparent,
                title=title,
                xlim=(-5.5, 5.5))
end

include("sine.jl")
include("linear.jl")
include("transfer.jl")
include("maml.jl")
include("reptile.jl")

end # module

max_stars_repo_name: JuliaTagBot/MetaLearning

max_issues_repo_name: JuliaTagBot/MetaLearning

max_forks_repo_name: JuliaTagBot/MetaLearning


text:
using Abaco
using BenchmarkTools
using Test

Abaco.loginit()

# My time zone: Saturday, October 30, 2021 3:43:35 PM GMT+02:00 DST
mo = "Cristallo"

interval = 1
ages = 4

function onresult(ts, ne, name, value, inputs)
    @info "age [$ts]: scope: [$ne] $name = $value"
    @test 1 == 0 # onresult should not be invoked
end

abaco = abaco_init(onresult, interval=interval, ages=ages)

formula(abaco, "myformula = (x + y)")

for ts in 0:6
    ingest(abaco, ts, mo, "x", ts)
end

# too old, formula must not be evaluated
ingest(abaco, 1, mo, "y", 4)


text:
#list of added packages
DataFrames Distributions StatsBase GLM CategoricalArrays Dates NLopt
ForwardDiff Formatting TexTables DataStructures Atom Juno
LinearAlgebra Gadfly HCubature HTTP Measures Formatting ODBC
CodecZlib CSV GZip NLopt CategoricalArrays Serialization Compose
Distributed Random Cairo Fontconfig Compose uCSV Revise StaticArrays

#routines for adding the packages
add DataFrames Distributions StatsBase GLM CategoricalArrays Dates NLopt ForwardDiff Formatting TexTables DataStructures Atom Juno LinearAlgebra Gadfly HCubature HTTP Measures Formatting ODBC CodecZlib CSV GZip NLopt CategoricalArrays Serialization Compose Distributed Random Cairo Fontconfig Compose uCSV Revise StaticArrays
add https://github.com/clintonTE/Finometrics

max_stars_repo_name: clintonTE/CCA

max_issues_repo_name: clintonTE/CCA

max_forks_repo_name: clintonTE/CCA