text:
using Rubin
using Tests
using Elliptic
using HypergeometricFunctions
using Polylogarithms
using SpecialFunctions

@test integrate((c*e+d*e*x)^3*(a+b*arctan(c+d*x)), x) == :(1//4*b*x*e^3+-1//4*b*d^-1*e^3*arctan(c+d*x)+-1//12*b*d^-1*e^3*(c+d*x)^3+1//4*d^-1*e^3*(c+d*x)^4*(a+b*arctan(c+d*x)))
@test integrate((c*e+d*e*x)^2*(a+b*arctan(c+d*x)), x) == :(-1//6*b*d^-1*e^2*(c+d*x)^2+1//3*d^-1*e^2*(c+d*x)^3*(a+b*arctan(c+d*x))+1//6*b*d^-1*e^2*log(1+(c+d*x)^2))
@test integrate((a+b*arctan(c+d*x))*(c*e+d*e*x), x) == :(-1//2*b*e*x+(1/2)*b*e*d^-1*arctan(c+d*x)+(1/2)*e*d^-1*(c+d*x)^2*(a+b*arctan(c+d*x)))
@test integrate((c*e+d*e*x)^-1*(a+b*arctan(c+d*x)), x) == :(a*d^-1*e^-1*log(c+d*x)+(1/2)*im*b*d^-1*e^-1*Polylogarithms.polylog(2,-1*im*(c+d*x))+-1//2*im*b*d^-1*e^-1*Polylogarithms.polylog(2,im*(c+d*x)))
@test integrate((c*e+d*e*x)^-2*(a+b*arctan(c+d*x)), x) == :(b*d^-1*e^-2*log(c+d*x)+-1*d^-1*e^-2*(c+d*x)^-1*(a+b*arctan(c+d*x))+-1//2*b*d^-1*e^-2*log(1+(c+d*x)^2))
@test integrate((c*e+d*e*x)^-3*(a+b*arctan(c+d*x)), x) == :(-1//2*b*d^-1*e^-3*(c+d*x)^-1+-1//2*b*d^-1*e^-3*arctan(c+d*x)+-1//2*d^-1*e^-3*(c+d*x)^-2*(a+b*arctan(c+d*x)))
@test integrate((a+b*arctan(c+d*x))^2*(c*e+d*e*x)^3, x) == :(-1//4*d^-1*e^3*(a+b*arctan(c+d*x))^2+(1/2)*a*b*x*e^3+-1//3*b^2*d^-1*e^3*log(1+(c+d*x)^2)+1//4*d^-1*e^3*(a+b*arctan(c+d*x))^2*(c+d*x)^4+1//12*b^2*d^-1*e^3*(c+d*x)^2+(1/2)*b^2*d^-1*e^3*(c+d*x)*arctan(c+d*x)+-1//6*b*d^-1*e^3*(c+d*x)^3*(a+b*arctan(c+d*x)))
@test integrate((a+b*arctan(c+d*x))^2*(c*e+d*e*x)^2, x) == :(1//3*x*b^2*e^2+-1//3*im*d^-1*e^2*(a+b*arctan(c+d*x))^2+-1//3*b^2*d^-1*e^2*arctan(c+d*x)+1//3*d^-1*e^2*(a+b*arctan(c+d*x))^2*(c+d*x)^3+-2//3*b*d^-1*e^2*(a+b*arctan(c+d*x))*log(2*(1+im*(c+d*x))^-1)+-1//3*im*b^2*d^-1*e^2*Polylogarithms.polylog(2,1+-2*(1+im*(c+d*x))^-1)+-1//3*b*d^-1*e^2*(c+d*x)^2*(a+b*arctan(c+d*x)))
@test integrate((a+b*arctan(c+d*x))^2*(c*e+d*e*x), x) == :((1/2)*e*d^-1*(a+b*arctan(c+d*x))^2+(1/2)*e*b^2*d^-1*log(1+(c+d*x)^2)+(1/2)*e*d^-1*(a+b*arctan(c+d*x))^2*(c+d*x)^2+-1*a*b*e*x+-1*e*b^2*d^-1*(c+d*x)*arctan(c+d*x))
@test integrate((a+b*arctan(c+d*x))^2*(c*e+d*e*x)^-1, x) == :((1/2)*b^2*d^-1*e^-1*Polylogarithms.polylog(3,-1+2*(1+im*(c+d*x))^-1)+2*d^-1*e^-1*(a+b*arctan(c+d*x))^2*arctanh(1+-2*(1+im*(c+d*x))^-1)+-1//2*b^2*d^-1*e^-1*Polylogarithms.polylog(3,1+-2*(1+im*(c+d*x))^-1)+im*b*d^-1*e^-1*(a+b*arctan(c+d*x))*Polylogarithms.polylog(2,-1+2*(1+im*(c+d*x))^-1)+-1*im*b*d^-1*e^-1*(a+b*arctan(c+d*x))*Polylogarithms.polylog(2,1+-2*(1+im*(c+d*x))^-1))
@test integrate((a+b*arctan(c+d*x))^2*(c*e+d*e*x)^-2, x) == :(-1*im*d^-1*e^-2*(a+b*arctan(c+d*x))^2+-1*d^-1*e^-2*(a+b*arctan(c+d*x))^2*(c+d*x)^-1+-1*im*b^2*d^-1*e^-2*Polylogarithms.polylog(2,-1+2*(1+-1*im*(c+d*x))^-1)+2*b*d^-1*e^-2*(a+b*arctan(c+d*x))*log(2+-2*(1+-1*im*(c+d*x))^-1))
@test integrate((a+b*arctan(c+d*x))^2*(c*e+d*e*x)^-3, x) == :(-1//2*d^-1*e^-3*(a+b*arctan(c+d*x))^2+b^2*d^-1*e^-3*log(c+d*x)+-1//2*b^2*d^-1*e^-3*log(1+(c+d*x)^2)+-1//2*d^-1*e^-3*(a+b*arctan(c+d*x))^2*(c+d*x)^-2+-1*b*d^-1*e^-3*(c+d*x)^-1*(a+b*arctan(c+d*x)))
@test integrate((a+b*arctan(c+d*x))^2*(c*e+d*e*x)^-4, x) == :(-1//3*b^2*d^-1*e^-4*(c+d*x)^-1+-1//3*b^2*d^-1*e^-4*arctan(c+d*x)+-1//3*d^-1*e^-4*(a+b*arctan(c+d*x))^2*(c+d*x)^-3+1//3*im*d^-1*e^-4*(a+b*arctan(c+d*x))^2+-2//3*b*d^-1*e^-4*(a+b*arctan(c+d*x))*log(2+-2*(1+-1*im*(c+d*x))^-1)+-1//3*b*d^-1*e^-4*(c+d*x)^-2*(a+b*arctan(c+d*x))+1//3*im*b^2*d^-1*e^-4*Polylogarithms.polylog(2,-1+2*(1+-1*im*(c+d*x))^-1))
@test integrate((a+b*arctan(c+d*x))^2*(c*e+d*e*x)^-5, x) == :(1//4*d^-1*e^-5*(a+b*arctan(c+d*x))^2+-2//3*b^2*d^-1*e^-5*log(c+d*x)+-1//4*d^-1*e^-5*(a+b*arctan(c+d*x))^2*(c+d*x)^-4+-1//12*b^2*d^-1*e^-5*(c+d*x)^-2+1//3*b^2*d^-1*e^-5*log(1+(c+d*x)^2)+(1/2)*b*d^-1*e^-5*(c+d*x)^-1*(a+b*arctan(c+d*x))+-1//6*b*d^-1*e^-5*(c+d*x)^-3*(a+b*arctan(c+d*x)))
@test integrate((a+b*arctan(c+d*x))^3*(c*e+d*e*x)^2, x) == :(a*x*b^2*e^2+-1//2*b*d^-1*e^2*(a+b*arctan(c+d*x))^2+-1//2*b^3*d^-1*e^2*Polylogarithms.polylog(3,1+-2*(1+im*(c+d*x))^-1)+-1//2*b^3*d^-1*e^2*log(1+(c+d*x)^2)+-1//3*im*d^-1*e^2*(a+b*arctan(c+d*x))^3+1//3*d^-1*e^2*(a+b*arctan(c+d*x))^3*(c+d*x)^3+b^3*d^-1*e^2*(c+d*x)*arctan(c+d*x)+-1*b*d^-1*e^2*(a+b*arctan(c+d*x))^2*log(2*(1+im*(c+d*x))^-1)+-1//2*b*d^-1*e^2*(a+b*arctan(c+d*x))^2*(c+d*x)^2+-1*im*b^2*d^-1*e^2*(a+b*arctan(c+d*x))*Polylogarithms.polylog(2,1+-2*(1+im*(c+d*x))^-1))
@test integrate((a+b*arctan(c+d*x))^3*(c*e+d*e*x), x) == :((1/2)*e*d^-1*(a+b*arctan(c+d*x))^3+(1/2)*e*d^-1*(a+b*arctan(c+d*x))^3*(c+d*x)^2+-3*e*b^2*d^-1*(a+b*arctan(c+d*x))*log(2*(1+im*(c+d*x))^-1)+-3//2*im*b*e*d^-1*(a+b*arctan(c+d*x))^2+-3//2*im*e*b^3*d^-1*Polylogarithms.polylog(2,1+-2*(1+im*(c+d*x))^-1)+-3//2*b*e*d^-1*(a+b*arctan(c+d*x))^2*(c+d*x))
@test integrate((a+b*arctan(c+d*x))^3*(c*e+d*e*x)^-1, x) == :(2*d^-1*e^-1*(a+b*arctan(c+d*x))^3*arctanh(1+-2*(1+im*(c+d*x))^-1)+-3//2*b^2*d^-1*e^-1*(a+b*arctan(c+d*x))*Polylogarithms.polylog(3,1+-2*(1+im*(c+d*x))^-1)+-3//4*im*b^3*d^-1*e^-1*Polylogarithms.polylog(4,-1+2*(1+im*(c+d*x))^-1)+3//2*b^2*d^-1*e^-1*(a+b*arctan(c+d*x))*Polylogarithms.polylog(3,-1+2*(1+im*(c+d*x))^-1)+3//4*im*b^3*d^-1*e^-1*Polylogarithms.polylog(4,1+-2*(1+im*(c+d*x))^-1)+-3//2*im*b*d^-1*e^-1*(a+b*arctan(c+d*x))^2*Polylogarithms.polylog(2,1+-2*(1+im*(c+d*x))^-1)+3//2*im*b*d^-1*e^-1*(a+b*arctan(c+d*x))^2*Polylogarithms.polylog(2,-1+2*(1+im*(c+d*x))^-1))
@test integrate((a+b*arctan(c+d*x))^3*(c*e+d*e*x)^-2, x) == :(-1*im*d^-1*e^-2*(a+b*arctan(c+d*x))^3+-1*d^-1*e^-2*(a+b*arctan(c+d*x))^3*(c+d*x)^-1+3//2*b^3*d^-1*e^-2*Polylogarithms.polylog(3,-1+2*(1+-1*im*(c+d*x))^-1)+3*b*d^-1*e^-2*(a+b*arctan(c+d*x))^2*log(2+-2*(1+-1*im*(c+d*x))^-1)+-3*im*b^2*d^-1*e^-2*(a+b*arctan(c+d*x))*Polylogarithms.polylog(2,-1+2*(1+-1*im*(c+d*x))^-1))
@test integrate((a+b*arctan(c+d*x))^3*(c*e+d*e*x)^-3, x) == :(-1//2*d^-1*e^-3*(a+b*arctan(c+d*x))^3+-1//2*d^-1*e^-3*(a+b*arctan(c+d*x))^3*(c+d*x)^-2+3*b^2*d^-1*e^-3*(a+b*arctan(c+d*x))*log(2+-2*(1+-1*im*(c+d*x))^-1)+-3//2*im*b*d^-1*e^-3*(a+b*arctan(c+d*x))^2+-3//2*im*b^3*d^-1*e^-3*Polylogarithms.polylog(2,-1+2*(1+-1*im*(c+d*x))^-1)+-3//2*b*d^-1*e^-3*(a+b*arctan(c+d*x))^2*(c+d*x)^-1)
@test integrate((a+b*arctan(c+d*x))^3*(c*e+d*e*x)^-4, x) == :(b^3*d^-1*e^-4*log(c+d*x)+-1//2*b*d^-1*e^-4*(a+b*arctan(c+d*x))^2+-1//2*b^3*d^-1*e^-4*Polylogarithms.polylog(3,-1+2*(1+-1*im*(c+d*x))^-1)+-1//2*b^3*d^-1*e^-4*log(1+(c+d*x)^2)+-1//3*d^-1*e^-4*(a+b*arctan(c+d*x))^3*(c+d*x)^-3+1//3*im*d^-1*e^-4*(a+b*arctan(c+d*x))^3+-1*b*d^-1*e^-4*(a+b*arctan(c+d*x))^2*log(2+-2*(1+-1*im*(c+d*x))^-1)+-1*b^2*d^-1*e^-4*(c+d*x)^-1*(a+b*arctan(c+d*x))+-1//2*b*d^-1*e^-4*(a+b*arctan(c+d*x))^2*(c+d*x)^-2+im*b^2*d^-1*e^-4*(a+b*arctan(c+d*x))*Polylogarithms.polylog(2,-1+2*(1+-1*im*(c+d*x))^-1))
@test integrate((2+2x)^-1*arctan(1+x), x) == :(-1//4*im*Polylogarithms.polylog(2,im*(1+x))+1//4*im*Polylogarithms.polylog(2,-1*im*(1+x)))
@test integrate((d*x+a*d*b^-1)^-1*arctan(a+b*x), x) == :((1/2)*im*d^-1*Polylogarithms.polylog(2,-1*im*(a+b*x))+-1//2*im*d^-1*Polylogarithms.polylog(2,im*(a+b*x)))
@test integrate((e+f*x)^3*(a+b*arctan(c+d*x)), x) == :(1//4*f^-1*(e+f*x)^4*(a+b*arctan(c+d*x))+-1//12*b*d^-4*f^3*(c+d*x)^3+-1//2*b*d^-4*f^2*(c+d*x)^2*(d*e+-1*c*f)+-1//4*b*f*x*d^-3*(-1*f^2*(1+-6*c^2)+6*d^2*e^2+-12*c*d*e*f)+-1//4*b*d^-4*f^-1*(d^4*e^4+f^4*(1+c^4+-6*c^2)+-1*d^2*e^2*f^2*(6+-6*c^2)+-4*c*f*d^3*e^3+4*c*d*e*f^3*(3+-1*c^2))*arctan(c+d*x)+-1//2*b*d^-4*(d*e+-1*c*f)*(d*e+-1*f*(1+c))*(f+d*e+-1*c*f)*log(1+(c+d*x)^2))
@test integrate((e+f*x)^2*(a+b*arctan(c+d*x)), x) == :(1//3*f^-1*(e+f*x)^3*(a+b*arctan(c+d*x))+-1//6*b*d^-3*f^2*(c+d*x)^2+-1//6*b*d^-3*(-1*f^2*(1+-3*c^2)+3*d^2*e^2+-6*c*d*e*f)*log(1+(c+d*x)^2)+-1*b*f*x*d^-2*(d*e+-1*c*f)+-1//3*b*d^-3*f^-1*(d*e+-1*c*f)*(d^2*e^2+-1*f^2*(3+-1*c^2)+-2*c*d*e*f)*arctan(c+d*x))
@test integrate((a+b*arctan(c+d*x))*(e+f*x), x) == :((1/2)*f^-1*(e+f*x)^2*(a+b*arctan(c+d*x))+-1//2*b*f*x*d^-1+-1//2*b*d^-2*(d*e+-1*c*f)*log(1+(c+d*x)^2)+-1//2*b*d^-2*f^-1*(d*e+-1*f*(1+c))*(f+d*e+-1*c*f)*arctan(c+d*x))
@test integrate(a+b*arctan(c+d*x), x) == :(a*x+-1//2*b*d^-1*log(1+(c+d*x)^2)+b*d^-1*(c+d*x)*arctan(c+d*x))
@test integrate((e+f*x)^-1*(a+b*arctan(c+d*x)), x) == :(f^-1*(a+b*arctan(c+d*x))*log(2*d*(1+-1*im*(c+d*x))^-1*(im*f+d*e+-1*c*f)^-1*(e+f*x))+-1*f^-1*(a+b*arctan(c+d*x))*log(2*(1+-1*im*(c+d*x))^-1)+(1/2)*im*b*f^-1*Polylogarithms.polylog(2,1+-2*(1+-1*im*(c+d*x))^-1)+-1//2*im*b*f^-1*Polylogarithms.polylog(2,1+-2*d*(1+-1*im*(c+d*x))^-1*(im*f+d*e+-1*c*f)^-1*(e+f*x)))
@test integrate((e+f*x)^-2*(a+b*arctan(c+d*x)), x) == :(-1*f^-1*(e+f*x)^-1*(a+b*arctan(c+d*x))+b*d*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*log(e+f*x)+-1*b*d*(2*d^2*e^2+2*f^2*(1+c^2)+-4*c*d*e*f)^-1*log(1+c^2+d^2*x^2+2*c*d*x)+b*d*f^-1*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*(d*e+-1*c*f)*arctan(c+d*x))
@test integrate((e+f*x)^-3*(a+b*arctan(c+d*x)), x) == :(-1//2*f^-1*(e+f*x)^-2*(a+b*arctan(c+d*x))+-1*b*d*(e+f*x)^-1*(2*d^2*e^2+2*f^2*(1+c^2)+-4*c*d*e*f)^-1+b*d^2*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-2*(d*e+-1*c*f)*log(e+f*x)+-1//2*b*d^2*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-2*(d*e+-1*c*f)*log(1+c^2+d^2*x^2+2*c*d*x)+(1/2)*b*d^2*f^-1*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-2*(d*e+-1*f*(1+c))*(f+d*e+-1*c*f)*arctan(c+d*x))
@test integrate((a+b*arctan(c+d*x))^2*(e+f*x)^2, x) == :(1//3*f^-1*(a+b*arctan(c+d*x))^2*(e+f*x)^3+-1//3*b^2*d^-3*f^2*arctan(c+d*x)+1//3*im*d^-3*(a+b*arctan(c+d*x))^2*(-1*f^2*(1+-3*c^2)+3*d^2*e^2+-6*c*d*e*f)+1//3*x*b^2*d^-2*f^2+f*b^2*d^-3*(d*e+-1*c*f)*log(1+(c+d*x)^2)+-1//3*b*d^-3*f^2*(c+d*x)^2*(a+b*arctan(c+d*x))+-1//3*d^-3*f^-1*(a+b*arctan(c+d*x))^2*(d*e+-1*c*f)*(d^2*e^2+-1*f^2*(3+-1*c^2)+-2*c*d*e*f)+1//3*im*b^2*d^-3*(-1*f^2*(1+-3*c^2)+3*d^2*e^2+-6*c*d*e*f)*Polylogarithms.polylog(2,1+-2*(1+im*(c+d*x))^-1)+2//3*b*d^-3*(a+b*arctan(c+d*x))*(-1*f^2*(1+-3*c^2)+3*d^2*e^2+-6*c*d*e*f)*log(2*(1+im*(c+d*x))^-1)+-2*a*b*f*x*d^-2*(d*e+-1*c*f)+-2*f*b^2*d^-3*(c+d*x)*(d*e+-1*c*f)*arctan(c+d*x))
@test integrate((a+b*arctan(c+d*x))^2*(e+f*x), x) == :((1/2)*f^-1*(a+b*arctan(c+d*x))^2*(e+f*x)^2+im*d^-2*(a+b*arctan(c+d*x))^2*(d*e+-1*c*f)+(1/2)*f*b^2*d^-2*log(1+(c+d*x)^2)+im*b^2*d^-2*(d*e+-1*c*f)*Polylogarithms.polylog(2,1+-2*(1+im*(c+d*x))^-1)+-1*a*b*f*x*d^-1+-1*f*b^2*d^-2*(c+d*x)*arctan(c+d*x)+2*b*d^-2*(a+b*arctan(c+d*x))*(d*e+-1*c*f)*log(2*(1+im*(c+d*x))^-1)+-1//2*d^-2*f^-1*(a+b*arctan(c+d*x))^2*(d*e+-1*f*(1+c))*(f+d*e+-1*c*f))
@test integrate((a+b*arctan(c+d*x))^2, x) == :(im*d^-1*(a+b*arctan(c+d*x))^2+d^-1*(a+b*arctan(c+d*x))^2*(c+d*x)+im*b^2*d^-1*Polylogarithms.polylog(2,1+-2*(1+im*(c+d*x))^-1)+2*b*d^-1*(a+b*arctan(c+d*x))*log(2*(1+im*(c+d*x))^-1))
@test integrate((a+b*arctan(c+d*x))^2*(e+f*x)^-1, x) == :(f^-1*(a+b*arctan(c+d*x))^2*log(2*d*(1+-1*im*(c+d*x))^-1*(im*f+d*e+-1*c*f)^-1*(e+f*x))+(1/2)*b^2*f^-1*Polylogarithms.polylog(3,1+-2*d*(1+-1*im*(c+d*x))^-1*(im*f+d*e+-1*c*f)^-1*(e+f*x))+-1*f^-1*(a+b*arctan(c+d*x))^2*log(2*(1+-1*im*(c+d*x))^-1)+-1//2*b^2*f^-1*Polylogarithms.polylog(3,1+-2*(1+-1*im*(c+d*x))^-1)+im*b*f^-1*(a+b*arctan(c+d*x))*Polylogarithms.polylog(2,1+-2*(1+-1*im*(c+d*x))^-1)+-1*im*b*f^-1*(a+b*arctan(c+d*x))*Polylogarithms.polylog(2,1+-2*d*(1+-1*im*(c+d*x))^-1*(im*f+d*e+-1*c*f)^-1*(e+f*x)))
@test integrate((a+b*arctan(c+d*x))^2*(e+f*x)^-2, x) == :(-1*f^-1*(a+b*arctan(c+d*x))^2*(e+f*x)^-1+im*d*b^2*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*arctan(c+d*x)^2+im*d*b^2*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*Polylogarithms.polylog(2,1+-2*(1+im*(c+d*x))^-1)+im*d*b^2*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*Polylogarithms.polylog(2,1+-2*(1+-1*im*(c+d*x))^-1)+-1*im*d*b^2*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*Polylogarithms.polylog(2,1+-2*d*(1+-1*im*(c+d*x))^-1*(im*f+d*e+-1*c*f)^-1*(e+f*x))+-1*a*b*d*(f^2+(d*e+-1*c*f)^2)^-1*log(1+(c+d*x)^2)+-2*d*b^2*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*arctan(c+d*x)*log(2*(1+-1*im*(c+d*x))^-1)+2*a*b*d*(f^2+(d*e+-1*c*f)^2)^-1*log(e+f*x)+2*d*b^2*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*arctan(c+d*x)*log(2*(1+im*(c+d*x))^-1)+2*d*b^2*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*arctan(c+d*x)*log(2*d*(1+-1*im*(c+d*x))^-1*(im*f+d*e+-1*c*f)^-1*(e+f*x))+d*b^2*f^-1*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*arctan(c+d*x)^2*(d*e+-1*c*f)+2*a*b*d*f^-1*(f^2+(d*e+-1*c*f)^2)^-1*(d*e+-1*c*f)*arctan(c+d*x))
@test integrate((a+b*arctan(c+d*x))^3*(e+f*x)^2, x) == :(1//3*f^-1*(a+b*arctan(c+d*x))^3*(e+f*x)^3+(1/2)*b^3*d^-3*(-1*f^2*(1+-3*c^2)+3*d^2*e^2+-6*c*d*e*f)*Polylogarithms.polylog(3,1+-2*(1+im*(c+d*x))^-1)+-1//2*b*d^-3*f^2*(a+b*arctan(c+d*x))^2+-1//2*b^3*d^-3*f^2*log(1+(c+d*x)^2)+1//3*im*d^-3*(a+b*arctan(c+d*x))^3*(-1*f^2*(1+-3*c^2)+3*d^2*e^2+-6*c*d*e*f)+a*x*b^2*d^-2*f^2+b*d^-3*(a+b*arctan(c+d*x))^2*(-1*f^2*(1+-3*c^2)+3*d^2*e^2+-6*c*d*e*f)*log(2*(1+im*(c+d*x))^-1)+b^3*d^-3*f^2*(c+d*x)*arctan(c+d*x)+-1//2*b*d^-3*f^2*(a+b*arctan(c+d*x))^2*(c+d*x)^2+-1//3*d^-3*f^-1*(a+b*arctan(c+d*x))^3*(d*e+-1*c*f)*(d^2*e^2+-1*f^2*(3+-1*c^2)+-2*c*d*e*f)+im*b^2*d^-3*(a+b*arctan(c+d*x))*(-1*f^2*(1+-3*c^2)+3*d^2*e^2+-6*c*d*e*f)*Polylogarithms.polylog(2,1+-2*(1+im*(c+d*x))^-1)+-6*f*b^2*d^-3*(a+b*arctan(c+d*x))*(d*e+-1*c*f)*log(2*(1+im*(c+d*x))^-1)+-3*im*b*f*d^-3*(a+b*arctan(c+d*x))^2*(d*e+-1*c*f)+-3*im*f*b^3*d^-3*(d*e+-1*c*f)*Polylogarithms.polylog(2,1+-2*(1+im*(c+d*x))^-1)+-3*b*f*d^-3*(a+b*arctan(c+d*x))^2*(c+d*x)*(d*e+-1*c*f))
@test integrate((a+b*arctan(c+d*x))^3*(e+f*x), x) == :((1/2)*f^-1*(a+b*arctan(c+d*x))^3*(e+f*x)^2+im*d^-2*(a+b*arctan(c+d*x))^3*(d*e+-1*c*f)+3//2*b^3*d^-2*(d*e+-1*c*f)*Polylogarithms.polylog(3,1+-2*(1+im*(c+d*x))^-1)+-3*f*b^2*d^-2*(a+b*arctan(c+d*x))*log(2*(1+im*(c+d*x))^-1)+3*b*d^-2*(a+b*arctan(c+d*x))^2*(d*e+-1*c*f)*log(2*(1+im*(c+d*x))^-1)+-3//2*im*b*f*d^-2*(a+b*arctan(c+d*x))^2+-3//2*im*f*b^3*d^-2*Polylogarithms.polylog(2,1+-2*(1+im*(c+d*x))^-1)+-3//2*b*f*d^-2*(a+b*arctan(c+d*x))^2*(c+d*x)+-1//2*d^-2*f^-1*(a+b*arctan(c+d*x))^3*(d*e+-1*f*(1+c))*(f+d*e+-1*c*f)+3*im*b^2*d^-2*(a+b*arctan(c+d*x))*(d*e+-1*c*f)*Polylogarithms.polylog(2,1+-2*(1+im*(c+d*x))^-1))
@test integrate((a+b*arctan(c+d*x))^3, x) == :(im*d^-1*(a+b*arctan(c+d*x))^3+d^-1*(a+b*arctan(c+d*x))^3*(c+d*x)+3//2*b^3*d^-1*Polylogarithms.polylog(3,1+-2*(1+im*(c+d*x))^-1)+3*b*d^-1*(a+b*arctan(c+d*x))^2*log(2*(1+im*(c+d*x))^-1)+3*im*b^2*d^-1*(a+b*arctan(c+d*x))*Polylogarithms.polylog(2,1+-2*(1+im*(c+d*x))^-1))
@test integrate((a+b*arctan(c+d*x))^3*(e+f*x)^-1, x) == :(f^-1*(a+b*arctan(c+d*x))^3*log(2*d*(1+-1*im*(c+d*x))^-1*(im*f+d*e+-1*c*f)^-1*(e+f*x))+-1*f^-1*(a+b*arctan(c+d*x))^3*log(2*(1+-1*im*(c+d*x))^-1)+-3//2*b^2*f^-1*(a+b*arctan(c+d*x))*Polylogarithms.polylog(3,1+-2*(1+-1*im*(c+d*x))^-1)+-3//4*im*b^3*f^-1*Polylogarithms.polylog(4,1+-2*(1+-1*im*(c+d*x))^-1)+3//2*b^2*f^-1*(a+b*arctan(c+d*x))*Polylogarithms.polylog(3,1+-2*d*(1+-1*im*(c+d*x))^-1*(im*f+d*e+-1*c*f)^-1*(e+f*x))+3//4*im*b^3*f^-1*Polylogarithms.polylog(4,1+-2*d*(1+-1*im*(c+d*x))^-1*(im*f+d*e+-1*c*f)^-1*(e+f*x))+-3//2*im*b*f^-1*(a+b*arctan(c+d*x))^2*Polylogarithms.polylog(2,1+-2*d*(1+-1*im*(c+d*x))^-1*(im*f+d*e+-1*c*f)^-1*(e+f*x))+3//2*im*b*f^-1*(a+b*arctan(c+d*x))^2*Polylogarithms.polylog(2,1+-2*(1+-1*im*(c+d*x))^-1))
@test integrate((a+b*arctan(c+d*x))^3*(e+f*x)^-2, x) == :(-1*f^-1*(a+b*arctan(c+d*x))^3*(e+f*x)^-1+-3*d*b^3*(2*d^2*e^2+2*f^2*(1+c^2)+-4*c*d*e*f)^-1*Polylogarithms.polylog(3,1+-2*(1+-1*im*(c+d*x))^-1)+3*d*b^3*(2*d^2*e^2+2*f^2*(1+c^2)+-4*c*d*e*f)^-1*Polylogarithms.polylog(3,1+-2*(1+im*(c+d*x))^-1)+3*d*b^3*(2*d^2*e^2+2*f^2*(1+c^2)+-4*c*d*e*f)^-1*Polylogarithms.polylog(3,1+-2*d*(1+-1*im*(c+d*x))^-1*(im*f+d*e+-1*c*f)^-1*(e+f*x))+im*d*b^3*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*arctan(c+d*x)^3+-3*b*d*a^2*(2*f^2+2*(d*e+-1*c*f)^2)^-1*log(1+(c+d*x)^2)+-3*d*b^3*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*arctan(c+d*x)^2*log(2*(1+-1*im*(c+d*x))^-1)+3*b*d*a^2*(f^2+(d*e+-1*c*f)^2)^-1*log(e+f*x)+3*d*b^3*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*arctan(c+d*x)^2*log(2*(1+im*(c+d*x))^-1)+3*d*b^3*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*arctan(c+d*x)^2*log(2*d*(1+-1*im*(c+d*x))^-1*(im*f+d*e+-1*c*f)^-1*(e+f*x))+d*b^3*f^-1*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*arctan(c+d*x)^3*(d*e+-1*c*f)+-6*a*d*b^2*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*arctan(c+d*x)*log(2*(1+-1*im*(c+d*x))^-1)+-3*im*a*d*b^2*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*Polylogarithms.polylog(2,1+-2*d*(1+-1*im*(c+d*x))^-1*(im*f+d*e+-1*c*f)^-1*(e+f*x))+-3*im*d*b^3*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*Polylogarithms.polylog(2,1+-2*d*(1+-1*im*(c+d*x))^-1*(im*f+d*e+-1*c*f)^-1*(e+f*x))*arctan(c+d*x)+3*im*a*d*b^2*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*arctan(c+d*x)^2+3*im*a*d*b^2*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*Polylogarithms.polylog(2,1+-2*(1+im*(c+d*x))^-1)+3*im*a*d*b^2*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*Polylogarithms.polylog(2,1+-2*(1+-1*im*(c+d*x))^-1)+3*im*d*b^3*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*Polylogarithms.polylog(2,1+-2*(1+im*(c+d*x))^-1)*arctan(c+d*x)+3*im*d*b^3*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*Polylogarithms.polylog(2,1+-2*(1+-1*im*(c+d*x))^-1)*arctan(c+d*x)+6*a*d*b^2*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*arctan(c+d*x)*log(2*(1+im*(c+d*x))^-1)+6*a*d*b^2*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*arctan(c+d*x)*log(2*d*(1+-1*im*(c+d*x))^-1*(im*f+d*e+-1*c*f)^-1*(e+f*x))+3*a*d*b^2*f^-1*(d^2*e^2+f^2*(1+c^2)+-2*c*d*e*f)^-1*arctan(c+d*x)^2*(d*e+-1*c*f)+3*b*d*a^2*f^-1*(f^2+(d*e+-1*c*f)^2)^-1*(d*e+-1*c*f)*arctan(c+d*x))
@test integrate(x^3*arctan(a+b*x), x) == :(-1//12*b^-4*(a+b*x)^3+1//4*x^4*arctan(a+b*x)+(1/2)*a*b^-4*(a+b*x)^2+-1//4*b^-4*(1+a^4+-6*a^2)*arctan(a+b*x)+1//4*x*b^-3*(1+-6*a^2)+-1//2*a*b^-4*(1+-1*a^2)*log(1+(a+b*x)^2))
@test integrate(x^2*arctan(a+b*x), x) == :(-1//6*b^-3*(a+b*x)^2+1//3*x^3*arctan(a+b*x)+a*x*b^-2+1//6*b^-3*(1+-3*a^2)*log(1+(a+b*x)^2)+-1//3*a*b^-3*(3+-1*a^2)*arctan(a+b*x))
@test integrate(x*arctan(a+b*x), x) == :((1/2)*x^2*arctan(a+b*x)+-1//2*x*b^-1+(1/2)*a*b^-2*log(1+(a+b*x)^2)+(1/2)*b^-2*(1+-1*a^2)*arctan(a+b*x))
@test integrate(arctan(a+b*x), x) == :(-1//2*b^-1*log(1+(a+b*x)^2)+b^-1*(a+b*x)*arctan(a+b*x))
@test integrate(x^-1*arctan(a+b*x), x) == :(arctan(a+b*x)*log(2*b*x*(1+-1*im*(a+b*x))^-1*(im+-1a)^-1)+(1/2)*im*Polylogarithms.polylog(2,1+-2*(1+-1*im*(a+b*x))^-1)+-1*arctan(a+b*x)*log(2*(1+-1*im*(a+b*x))^-1)+-1//2*im*Polylogarithms.polylog(2,1+-2*b*x*(1+-1*im*(a+b*x))^-1*(im+-1a)^-1))
@test integrate(x^-2*arctan(a+b*x), x) == :(-1*x^-1*arctan(a+b*x)+b*(1+a^2)^-1*log(x)+-1*b*(2+2*a^2)^-1*log(1+(a+b*x)^2)+-1*a*b*(1+a^2)^-1*arctan(a+b*x))
@test integrate(x^-3*arctan(a+b*x), x) == :(-1//2*x^-2*arctan(a+b*x)+-1*b*x^-1*(2+2*a^2)^-1+(1/2)*a*b^2*(1+a^2)^-2*log(1+(a+b*x)^2)+-1*a*b^2*(1+a^2)^-2*log(x)+-1//2*b^2*(1+a^2)^-2*(1+-1*a^2)*arctan(a+b*x))
@test integrate(x^-4*arctan(a+b*x), x) == :(-1//3*x^-3*arctan(a+b*x)+-1*b*x^-2*(6+6*a^2)^-1+-1//3*b^3*(1+a^2)^-3*(1+-3*a^2)*log(x)+1//6*b^3*(1+a^2)^-3*(1+-3*a^2)*log(1+(a+b*x)^2)+2//3*a*b^2*x^-1*(1+a^2)^-2+1//3*a*b^3*(1+a^2)^-3*(3+-1*a^2)*arctan(a+b*x))
@test integrate((c+d*x^3)^-1*arctan(a+b*x), x) == :(-1//6*im*c^-2//3*d^-1//3*Polylogarithms.polylog(2,d^1//3*(b*c^1//3+d^1//3*(im+-1a))^-1*(im+-1a+-1*b*x))+-1//6*(-1)^1//6*c^-2//3*d^-1//3*Polylogarithms.polylog(2,(-1)^1//3*d^1//3*(b*c^1//3+(-1)^1//3*d^1//3*(im+a))^-1*(im+a+b*x))+-1//6*(-1)^5//6*c^-2//3*d^-1//3*Polylogarithms.polylog(2,-1*(-1)^2//3*d^1//3*(b*c^1//3+-1*(-1)^2//3*d^1//3*(im+a))^-1*(im+a+b*x))+1//6*im*c^-2//3*d^-1//3*Polylogarithms.polylog(2,-1*d^1//3*(b*c^1//3+-1*d^1//3*(im+a))^-1*(im+a+b*x))+1//6*(-1)^1//6*c^-2//3*d^-1//3*Polylogarithms.polylog(2,-1*(-1)^1//3*d^1//3*(b*c^1//3+-1*(-1)^1//3*d^1//3*(im+-1a))^-1*(im+-1a+-1*b*x))+1//6*(-1)^5//6*c^-2//3*d^-1//3*Polylogarithms.polylog(2,-1*(-1)^1//6*d^1//3*(im*b*c^1//3+-1*(-1)^1//6*d^1//3*(im+-1a))^-1*(im+-1a+-1*b*x))+-1//6*im*c^-2//3*d^-1//3*log(b*(b*c^1//3+d^1//3*(im+-1a))^-1*(c^1//3+x*d^1//3))*log(1+im*a+im*b*x)+-1//6*(-1)^1//6*c^-2//3*d^-1//3*log(b*(b*c^1//3+(-1)^1//3*d^1//3*(im+a))^-1*(c^1//3+-1*x*(-1)^1//3*d^1//3))*log(1+-1*im*a+-1*im*b*x)+-1//6*(-1)^5//6*c^-2//3*d^-1//3*log(b*(b*c^1//3+(-1)^1//6*d^1//3*(1+-1*im*a))^-1*(c^1//3+x*(-1)^2//3*d^1//3))*log(1+-1*im*a+-1*im*b*x)+1//6*im*c^-2//3*d^-1//3*log(b*(b*c^1//3+-1*d^1//3*(im+a))^-1*(c^1//3+x*d^1//3))*log(1+-1*im*a+-1*im*b*x)+1//6*(-1)^1//6*c^-2//3*d^-1//3*log(b*(b*c^1//3+-1*(-1)^1//3*d^1//3*(im+-1a))^-1*(c^1//3+-1*x*(-1)^1//3*d^1//3))*log(1+im*a+im*b*x)+1//6*(-1)^5//6*c^-2//3*d^-1//3*log(b*(b*c^1//3+(-1)^2//3*d^1//3*(im+-1a))^-1*(c^1//3+x*(-1)^2//3*d^1//3))*log(1+im*a+im*b*x))
@test integrate((c+d*x^2)^-1*arctan(a+b*x), x) == :(-1//4*im*d^-1//2*(-1c)^-1//2*Polylogarithms.polylog(2,-1*d^(1/2)*(b*(-1c)^(1/2)+-1*d^(1/2)*(im+a))^-1*(im+a+b*x))+-1//4*im*d^-1//2*(-1c)^-1//2*Polylogarithms.polylog(2,-1*d^(1/2)*(b*(-1c)^(1/2)+-1*d^(1/2)*(im+-1a))^-1*(im+-1a+-1*b*x))+1//4*im*d^-1//2*(-1c)^-1//2*Polylogarithms.polylog(2,d^(1/2)*(b*(-1c)^(1/2)+d^(1/2)*(im+a))^-1*(im+a+b*x))+1//4*im*d^-1//2*(-1c)^-1//2*Polylogarithms.polylog(2,d^(1/2)*(b*(-1c)^(1/2)+d^(1/2)*(im+-1a))^-1*(im+-1a+-1*b*x))+-1//4*im*d^-1//2*(-1c)^-1//2*log(b*(b*(-1c)^(1/2)+-1*d^(1/2)*(im+a))^-1*((-1c)^(1/2)+x*d^(1/2)))*log(1+-1*im*a+-1*im*b*x)+-1//4*im*d^-1//2*(-1c)^-1//2*log(b*(b*(-1c)^(1/2)+-1*d^(1/2)*(im+-1a))^-1*((-1c)^(1/2)+-1*x*d^(1/2)))*log(1+im*a+im*b*x)+1//4*im*d^-1//2*(-1c)^-1//2*log(b*(b*(-1c)^(1/2)+d^(1/2)*(im+a))^-1*((-1c)^(1/2)+-1*x*d^(1/2)))*log(1+-1*im*a+-1*im*b*x)+1//4*im*d^-1//2*(-1c)^-1//2*log(b*(b*(-1c)^(1/2)+d^(1/2)*(im+-1a))^-1*((-1c)^(1/2)+x*d^(1/2)))*log(1+im*a+im*b*x))
@test integrate((c+d*x)^-1*arctan(a+b*x), x) == :(d^-1*arctan(a+b*x)*log(2*b*(1+-1*im*(a+b*x))^-1*(im*d+b*c+-1*a*d)^-1*(c+d*x))+(1/2)*im*d^-1*Polylogarithms.polylog(2,1+-2*(1+-1*im*(a+b*x))^-1)+-1*d^-1*arctan(a+b*x)*log(2*(1+-1*im*(a+b*x))^-1)+-1//2*im*d^-1*Polylogarithms.polylog(2,1+-2*b*(1+-1*im*(a+b*x))^-1*(im*d+b*c+-1*a*d)^-1*(c+d*x)))
@test integrate((c+d*x^-1)^-1*arctan(a+b*x), x) == :((1/2)*im*d*c^-2*Polylogarithms.polylog(2,c*(im*c+b*d+-1*a*c)^-1*(im+-1a+-1*b*x))+-1//2*im*d*c^-2*Polylogarithms.polylog(2,c*(c*(im+a)+-1*b*d)^-1*(im+a+b*x))+-1//2*b^-1*c^-1*(1+im*a+im*b*x)*log(1+im*a+im*b*x)+-1//2*b^-1*c^-1*(1+-1*im*a+-1*im*b*x)*log(-1*im*(im+a+b*x))+(1/2)*im*d*c^-2*log(b*(b*d+c*(im+-1a))^-1*(d+c*x))*log(1+im*a+im*b*x)+-1//2*im*d*c^-2*log(-1*b*(c*(im+a)+-1*b*d)^-1*(d+c*x))*log(1+-1*im*a+-1*im*b*x))
@test integrate((c+d*x^-2)^-1*arctan(a+b*x), x) == :(-1//2*b^-1*c^-1*(1+im*a+im*b*x)*log(1+im*a+im*b*x)+-1//2*b^-1*c^-1*(1+-1*im*a+-1*im*b*x)*log(-1*im*(im+a+b*x))+-1//4*im*d^(1/2)*(-1c)^-3//2*Polylogarithms.polylog(2,(-1c)^(1/2)*((-1c)^(1/2)*(1+im*a)+-1*im*b*d^(1/2))^-1*(1+im*a+im*b*x))+-1//4*im*d^(1/2)*(-1c)^-3//2*Polylogarithms.polylog(2,(-1c)^(1/2)*(im*(-1c)^(1/2)+a*(-1c)^(1/2)+b*d^(1/2))^-1*(im+a+b*x))+1//4*im*d^(1/2)*(-1c)^-3//2*Polylogarithms.polylog(2,(-1c)^(1/2)*(im*(-1c)^(1/2)+a*(-1c)^(1/2)+-1*b*d^(1/2))^-1*(im+a+b*x))+1//4*im*d^(1/2)*(-1c)^-3//2*Polylogarithms.polylog(2,(-1c)^(1/2)*(im*(-1c)^(1/2)+-1*a*(-1c)^(1/2)+-1*b*d^(1/2))^-1*(im+-1a+-1*b*x))+-1//4*im*d^(1/2)*(-1c)^-3//2*log(b*(im*(-1c)^(1/2)+a*(-1c)^(1/2)+b*d^(1/2))^-1*(d^(1/2)+-1*x*(-1c)^(1/2)))*log(1+-1*im*a+-1*im*b*x)+-1//4*im*d^(1/2)*(-1c)^-3//2*log(b*(im*(-1c)^(1/2)+b*d^(1/2)+-1*a*(-1c)^(1/2))^-1*(d^(1/2)+x*(-1c)^(1/2)))*log(1+im*a+im*b*x)+1//4*im*d^(1/2)*(-1c)^-3//2*log(-1*b*((-1c)^(1/2)*(im+a)+-1*b*d^(1/2))^-1*(d^(1/2)+x*(-1c)^(1/2)))*log(1+-1*im*a+-1*im*b*x)+1//4*im*d^(1/2)*(-1c)^-3//2*log(-1*b*(im*(-1c)^(1/2)+-1*a*(-1c)^(1/2)+-1*b*d^(1/2))^-1*(d^(1/2)+-1*x*(-1c)^(1/2)))*log(1+im*a+im*b*x))
@test integrate((c+d*x^-3)^-1*arctan(a+b*x), x) == :(-1//2*b^-1*c^-1*(1+im*a+im*b*x)*log(1+im*a+im*b*x)+-1//2*b^-1*c^-1*(1+-1*im*a+-1*im*b*x)*log(-1*im*(im+a+b*x))+-1//6*im*c^-4//3*d^1//3*Polylogarithms.polylog(2,c^1//3*(c^1//3*(im+a)+-1*b*d^1//3)^-1*(im+a+b*x))+-1//6*(-1)^1//6*c^-4//3*d^1//3*Polylogarithms.polylog(2,(-1)^1//3*c^1//3*(-1*b*d^1//3+(-1)^1//3*c^1//3*(im+-1a))^-1*(im+-1a+-1*b*x))+-1//6*(-1)^5//6*c^-4//3*d^1//3*Polylogarithms.polylog(2,(-1)^1//6*c^1//3*((-1)^1//6*c^1//3*(im+-1a)+-1*im*b*d^1//3)^-1*(im+-1a+-1*b*x))+1//6*im*c^-4//3*d^1//3*Polylogarithms.polylog(2,c^1//3*(b*d^1//3+c^1//3*(im+-1a))^-1*(im+-1a+-1*b*x))+1//6*(-1)^1//6*c^-4//3*d^1//3*Polylogarithms.polylog(2,(-1)^1//3*c^1//3*(b*d^1//3+(-1)^1//3*c^1//3*(im+a))^-1*(im+a+b*x))+1//6*(-1)^5//6*c^-4//3*d^1//3*Polylogarithms.polylog(2,(-1)^2//3*c^1//3*(-1*b*d^1//3+(-1)^2//3*c^1//3*(im+a))^-1*(im+a+b*x))+-1//6*im*c^-4//3*d^1//3*log(-1*b*(c^1//3*(im+a)+-1*b*d^1//3)^-1*(d^1//3+x*c^1//3))*log(1+-1*im*a+-1*im*b*x)+-1//6*(-1)^1//6*c^-4//3*d^1//3*log(-1*b*(-1*b*d^1//3+(-1)^1//3*c^1//3*(im+-1a))^-1*(d^1//3+-1*x*(-1)^1//3*c^1//3))*log(1+im*a+im*b*x)+-1//6*(-1)^5//6*c^-4//3*d^1//3*log(b*(b*d^1//3+(-1)^2//3*c^1//3*(im+-1a))^-1*(d^1//3+x*(-1)^2//3*c^1//3))*log(1+im*a+im*b*x)+1//6*im*c^-4//3*d^1//3*log(b*(b*d^1//3+c^1//3*(im+-1a))^-1*(d^1//3+x*c^1//3))*log(1+im*a+im*b*x)+1//6*(-1)^1//6*c^-4//3*d^1//3*log(b*(b*d^1//3+(-1)^1//3*c^1//3*(im+a))^-1*(d^1//3+-1*x*(-1)^1//3*c^1//3))*log(1+-1*im*a+-1*im*b*x)+1//6*(-1)^5//6*c^-4//3*d^1//3*log(b*(b*d^1//3+(-1)^1//6*c^1//3*(1+-1*im*a))^-1*(d^1//3+x*(-1)^2//3*c^1//3))*log(1+-1*im*a+-1*im*b*x))
@test integrate((c+d*x^(1/2))^-1*arctan(a+b*x), x) == :(im*c*d^-2*Polylogarithms.polylog(2,b^(1/2)*(c*b^(1/2)+d*(-1im+-1a)^(1/2))^-1*(c+d*x^(1/2)))+im*c*d^-2*Polylogarithms.polylog(2,b^(1/2)*(c*b^(1/2)+-1*d*(-1im+-1a)^(1/2))^-1*(c+d*x^(1/2)))+im*d^-1*x^(1/2)*log(1+-1*im*a+-1*im*b*x)+-1*im*c*d^-2*Polylogarithms.polylog(2,b^(1/2)*(c*b^(1/2)+d*(im+-1a)^(1/2))^-1*(c+d*x^(1/2)))+-1*im*c*d^-2*Polylogarithms.polylog(2,b^(1/2)*(c*b^(1/2)+-1*d*(im+-1a)^(1/2))^-1*(c+d*x^(1/2)))+-1*im*d^-1*x^(1/2)*log(1+im*a+im*b*x)+im*c*d^-2*log(d*(c*b^(1/2)+d*(-1im+-1a)^(1/2))^-1*((-1im+-1a)^(1/2)+-1*b^(1/2)*x^(1/2)))*log(c+d*x^(1/2))+im*c*d^-2*log(-1*d*(c*b^(1/2)+-1*d*(-1im+-1a)^(1/2))^-1*((-1im+-1a)^(1/2)+b^(1/2)*x^(1/2)))*log(c+d*x^(1/2))+im*c*d^-2*log(c+d*x^(1/2))*log(1+im*a+im*b*x)+-1*im*c*d^-2*log(d*(c*b^(1/2)+d*(im+-1a)^(1/2))^-1*((im+-1a)^(1/2)+-1*b^(1/2)*x^(1/2)))*log(c+d*x^(1/2))+-1*im*c*d^-2*log(-1*d*(c*b^(1/2)+-1*d*(im+-1a)^(1/2))^-1*((im+-1a)^(1/2)+b^(1/2)*x^(1/2)))*log(c+d*x^(1/2))+-1*im*c*d^-2*log(c+d*x^(1/2))*log(1+-1*im*a+-1*im*b*x)+-2*im*b^-1//2*d^-1*(im+-1a)^(1/2)*arctanh(b^(1/2)*x^(1/2)*(im+-1a)^-1//2)+2*im*b^-1//2*d^-1*(im+a)^(1/2)*arctan(b^(1/2)*x^(1/2)*(im+a)^-1//2))
@test integrate((c+d*x^-1//2)^-1*arctan(a+b*x), x) == :(im*c^-3*d^2*Polylogarithms.polylog(2,b^(1/2)*(c*(im+-1a)^(1/2)+d*b^(1/2))^-1*(d+c*x^(1/2)))+im*c^-3*d^2*Polylogarithms.polylog(2,-1*b^(1/2)*(c*(im+-1a)^(1/2)+-1*d*b^(1/2))^-1*(d+c*x^(1/2)))+-1*im*c^-3*d^2*Polylogarithms.polylog(2,b^(1/2)*(c*(-1im+-1a)^(1/2)+d*b^(1/2))^-1*(d+c*x^(1/2)))+-1*im*c^-3*d^2*Polylogarithms.polylog(2,-1*b^(1/2)*(c*(-1im+-1a)^(1/2)+-1*d*b^(1/2))^-1*(d+c*x^(1/2)))+-1//2*b^-1*c^-1*(1+im*a+im*b*x)*log(1+im*a+im*b*x)+-1//2*b^-1*c^-1*(1+-1*im*a+-1*im*b*x)*log(-1*im*(im+a+b*x))+im*d*c^-2*x^(1/2)*log(1+im*a+im*b*x)+im*c^-3*d^2*log(c*(c*(im+-1a)^(1/2)+d*b^(1/2))^-1*((im+-1a)^(1/2)+-1*b^(1/2)*x^(1/2)))*log(d+c*x^(1/2))+im*c^-3*d^2*log(c*(c*(im+-1a)^(1/2)+-1*d*b^(1/2))^-1*((im+-1a)^(1/2)+b^(1/2)*x^(1/2)))*log(d+c*x^(1/2))+im*c^-3*d^2*log(d+c*x^(1/2))*log(1+-1*im*a+-1*im*b*x)+-1*im*d*c^-2*x^(1/2)*log(1+-1*im*a+-1*im*b*x)+-1*im*c^-3*d^2*log(c*(c*(-1im+-1a)^(1/2)+d*b^(1/2))^-1*((-1im+-1a)^(1/2)+-1*b^(1/2)*x^(1/2)))*log(d+c*x^(1/2))+-1*im*c^-3*d^2*log(c*(c*(-1im+-1a)^(1/2)+-1*d*b^(1/2))^-1*((-1im+-1a)^(1/2)+b^(1/2)*x^(1/2)))*log(d+c*x^(1/2))+-1*im*c^-3*d^2*log(d+c*x^(1/2))*log(1+im*a+im*b*x)+-2*im*d*b^-1//2*c^-2*(im+a)^(1/2)*arctan(b^(1/2)*x^(1/2)*(im+a)^-1//2)+2*im*d*b^-1//2*c^-2*(im+-1a)^(1/2)*arctanh(b^(1/2)*x^(1/2)*(im+-1a)^-1//2))
@test integrate((1+x^2)^-1*arctan(a+b*x), x) == :(-1//4*Polylogarithms.polylog(2,(im+a+-1*im*b)^-1*(im+a+b*x))+-1//4*Polylogarithms.polylog(2,-1*(a+-1*im*(1+-1b))^-1*(im+-1a+-1*b*x))+1//4*Polylogarithms.polylog(2,(a+im*(1+b))^-1*(im+a+b*x))+1//4*Polylogarithms.polylog(2,-1*(a+-1*im*(1+b))^-1*(im+-1a+-1*b*x))+-1//4*log(b*(a+-1*im*(1+-1b))^-1*(im+-1x))*log(1+im*a+im*b*x)+-1//4*log(-1*b*(a+im*(1+-1b))^-1*(im+x))*log(1+-1*im*a+-1*im*b*x)+1//4*log(b*(a+im*(1+b))^-1*(im+-1x))*log(1+-1*im*a+-1*im*b*x)+1//4*log(-1*b*(a+-1*im*(1+b))^-1*(im+x))*log(1+im*a+im*b*x))
@test integrate((a+b*x^2)^-1*arctan(d+e*x), x) == :(-1//4*im*b^-1//2*(-1a)^-1//2*Polylogarithms.polylog(2,b^(1/2)*(b^(1/2)*(im+d)+-1*e*(-1a)^(1/2))^-1*(im+d+e*x))+-1//4*im*b^-1//2*(-1a)^-1//2*Polylogarithms.polylog(2,b^(1/2)*(b^(1/2)*(im+-1d)+-1*e*(-1a)^(1/2))^-1*(im+-1d+-1*e*x))+1//4*im*b^-1//2*(-1a)^-1//2*Polylogarithms.polylog(2,b^(1/2)*(e*(-1a)^(1/2)+b^(1/2)*(im+d))^-1*(im+d+e*x))+1//4*im*b^-1//2*(-1a)^-1//2*Polylogarithms.polylog(2,b^(1/2)*(e*(-1a)^(1/2)+b^(1/2)*(im+-1d))^-1*(im+-1d+-1*e*x))+-1//4*im*b^-1//2*(-1a)^-1//2*log(-1*e*(b^(1/2)*(im+d)+-1*e*(-1a)^(1/2))^-1*((-1a)^(1/2)+x*b^(1/2)))*log(1+-1*im*d+-1*im*e*x)+-1//4*im*b^-1//2*(-1a)^-1//2*log(-1*e*(b^(1/2)*(im+-1d)+-1*e*(-1a)^(1/2))^-1*((-1a)^(1/2)+-1*x*b^(1/2)))*log(1+im*d+im*e*x)+1//4*im*b^-1//2*(-1a)^-1//2*log(e*(e*(-1a)^(1/2)+b^(1/2)*(im+d))^-1*((-1a)^(1/2)+-1*x*b^(1/2)))*log(1+-1*im*d+-1*im*e*x)+1//4*im*b^-1//2*(-1a)^-1//2*log(e*(e*(-1a)^(1/2)+b^(1/2)*(im+-1d))^-1*((-1a)^(1/2)+x*b^(1/2)))*log(1+im*d+im*e*x))
@test integrate((a+b*x+c*x^2)^-1*arctan(d+e*x), x) == :((b^2+-4*a*c)^-1//2*arctan(d+e*x)*log(2*e*(1+-1*im*(d+e*x))^-1*(e*(b+-1*(b^2+-4*a*c)^(1/2))+2*c*(im+-1d))^-1*(b+-1*(b^2+-4*a*c)^(1/2)+2*c*x))+(1/2)*im*(b^2+-4*a*c)^-1//2*Polylogarithms.polylog(2,1+(1+-1*im*(d+e*x))^-1*(e*(b+(b^2+-4*a*c)^(1/2))+2*c*(im+-1d))^-1*(-4*c*(d+e*x)+-2*e*(b+(b^2+-4*a*c)^(1/2))+4*c*d))+-1*(b^2+-4*a*c)^-1//2*arctan(d+e*x)*log(2*e*(1+-1*im*(d+e*x))^-1*(e*(b+(b^2+-4*a*c)^(1/2))+2*c*(im+-1d))^-1*(b+(b^2+-4*a*c)^(1/2)+2*c*x))+-1//2*im*(b^2+-4*a*c)^-1//2*Polylogarithms.polylog(2,1+(1+-1*im*(d+e*x))^-1*(b*e+-1*e*(b^2+-4*a*c)^(1/2)+-2*c*d+2*im*c)^-1*(-4*c*(d+e*x)+-2*e*(b+-1*(b^2+-4*a*c)^(1/2))+4*c*d)))
@test integrate((1+a^2+b^2*x^2+2*a*b*x)^-1//2*arctan(a+b*x), x) == :(im*b^-1*Polylogarithms.polylog(2,-1*im*(1+im*(a+b*x))^(1/2)*(1+-1*im*(a+b*x))^-1//2)+-1*im*b^-1*Polylogarithms.polylog(2,im*(1+im*(a+b*x))^(1/2)*(1+-1*im*(a+b*x))^-1//2)+-2*im*b^-1*arctan((1+im*(a+b*x))^(1/2)*(1+-1*im*(a+b*x))^-1//2)*arctan(a+b*x))
@test integrate((c*(1+a^2)+c*b^2*x^2+2*a*b*c*x)^-1//2*arctan(a+b*x), x) == :(im*b^-1*(1+(a+b*x)^2)^(1/2)*(c+c*(a+b*x)^2)^-1//2*Polylogarithms.polylog(2,-1*im*(1+im*(a+b*x))^(1/2)*(1+-1*im*(a+b*x))^-1//2)+-1*im*b^-1*(1+(a+b*x)^2)^(1/2)*(c+c*(a+b*x)^2)^-1//2*Polylogarithms.polylog(2,im*(1+im*(a+b*x))^(1/2)*(1+-1*im*(a+b*x))^-1//2)+-2*im*b^-1*(1+(a+b*x)^2)^(1/2)*(c+c*(a+b*x)^2)^-1//2*arctan((1+im*(a+b*x))^(1/2)*(1+-1*im*(a+b*x))^-1//2)*arctan(a+b*x))
@test integrate((a+b*x)^2*(1+a^2+b^2*x^2+2*a*b*x)^-1//2*arctan(a+b*x), x) == :(-1//2*b^-1*(1+(a+b*x)^2)^(1/2)+(1/2)*im*b^-1*Polylogarithms.polylog(2,im*(1+im*(a+b*x))^(1/2)*(1+-1*im*(a+b*x))^-1//2)+-1//2*im*b^-1*Polylogarithms.polylog(2,-1*im*(1+im*(a+b*x))^(1/2)*(1+-1*im*(a+b*x))^-1//2)+im*b^-1*arctan((1+im*(a+b*x))^(1/2)*(1+-1*im*(a+b*x))^-1//2)*arctan(a+b*x)+(1/2)*b^-1*(1+(a+b*x)^2)^(1/2)*(a+b*x)*arctan(a+b*x))
@test integrate((a+b*x)^2*(c*(1+a^2)+c*b^2*x^2+2*a*b*c*x)^-1//2*arctan(a+b*x), x) == :(-1//2*b^-1*c^-1*(c+c*(a+b*x)^2)^(1/2)+(1/2)*im*b^-1*(1+(a+b*x)^2)^(1/2)*(c+c*(a+b*x)^2)^-1//2*Polylogarithms.polylog(2,im*(1+im*(a+b*x))^(1/2)*(1+-1*im*(a+b*x))^-1//2)+(1/2)*b^-1*c^-1*(c+c*(a+b*x)^2)^(1/2)*(a+b*x)*arctan(a+b*x)+-1//2*im*b^-1*(1+(a+b*x)^2)^(1/2)*(c+c*(a+b*x)^2)^-1//2*Polylogarithms.polylog(2,-1*im*(1+im*(a+b*x))^(1/2)*(1+-1*im*(a+b*x))^-1//2)+im*b^-1*(1+(a+b*x)^2)^(1/2)*(c+c*(a+b*x)^2)^-1//2*arctan((1+im*(a+b*x))^(1/2)*(1+-1*im*(a+b*x))^-1//2)*arctan(a+b*x))

max_stars_repo_path: test/5 Inverse trig functions/5.3 Inverse tangent/5.3.5 u (a+b arctan(c+d x))^p.jl


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

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

# ╔═╡ a0fb4f28-bfe4-4877-bf07-31acb9a56d2c
using HypertextLiteral

# ╔═╡ 57232d88-b74f-4823-be61-8db450c93f5c
using Markdown: withtag, htmlesc

# ╔═╡ d738b448-387b-4942-af82-cc93042705a4
function skip_as_script(m::Module)
	if isdefined(m, :PlutoForceDisplay)
		return m.PlutoForceDisplay
	else
		isdefined(m, :PlutoRunner) && parentmodule(m) == Main
	end
end

# ╔═╡ e8c5ba24-10e9-49e8-8c11-0add092637f8
"""
	@skip_as_script expression

Marks a expression as Pluto-only, which means that it won't be executed when running outside Pluto. Do not use this for your own projects.
"""
macro skip_as_script(ex) skip_as_script(__module__) ? esc(ex) : nothing end

# ╔═╡ e1bbe1d7-68ef-4ee1-8174-d1ae1f822acb
macro only_as_script(ex) skip_as_script(__module__) ? nothing : esc(ex) end

# ╔═╡ 81adbd39-5780-4cc6-a53f-a4472bacf1c0
if skip_as_script(@__MODULE__)
	import Pkg
	Pkg.activate(Base.current_project(@__DIR__))
	Text("Project env active")
end

# ╔═╡ d8f907cd-2f89-4d54-a311-998dc8ee148e
teststr = "<x>\"\"woa"

# ╔═╡ ac542b84-dbc8-47e2-8835-9e43582b6ad7
import Random: randstring

# ╔═╡ 6da84fb9-a629-4e4c-819e-dd87a3e267ce
import Dates

# ╔═╡ d088bcdb-d851-4ad7-b5a0-751c1f348995
begin
	struct Slider
		range::AbstractRange
		default::Number
		show_value::Bool
	end

	"""A Slider on the given `range`.

	## Examples
	`@bind x Slider(1:10)`

	`@bind x Slider(0.00 : 0.01 : 0.30)`

	`@bind x Slider(1:10; default=8, show_value=true)`

	"""
	Slider(range::AbstractRange; default=missing, show_value=false) = Slider(range, (default === missing) ? first(range) : default, show_value)

	function Base.show(io::IO, m::MIME"text/html", slider::Slider)
		show(io, m, @htl("""
				<input
				type="range"
				min=$(first(slider.range))
				step=$(step(slider.range))
				max=$(last(slider.range))

				value=$(slider.default)
				oninput=$(slider.show_value ? "this.nextElementSibling.value=this.value" : "")
				>

				$(
				slider.show_value ? @htl("<output>$(slider.default)</output>") : nothing
				)

				"""))
	end

	Base.get(slider::Slider) = slider.default
end

# ╔═╡ f59eef32-4732-46db-87b0-3564433ce43e
begin
	"""A box where you can type in a number, within a specific range.

	## Examples
	`@bind x NumberField(1:10)`

	`@bind x NumberField(0.00 : 0.01 : 0.30)`

	`@bind x NumberField(1:10; default=8)`

	"""
	struct NumberField
		range::AbstractRange
		default::Number
	end

	NumberField(range::AbstractRange; default=missing) = NumberField(range, (default === missing) ? first(range) : default)

	function Base.show(io::IO, ::MIME"text/html", numberfield::NumberField)
		print(io, """<input type="number" min="$(first(numberfield.range))" step="$(step(numberfield.range))" max="$(last(numberfield.range))" value="$(numberfield.default)">""")
	end

	Base.get(numberfield::NumberField) = numberfield.default

end

# ╔═╡ b7c21c22-17f5-44b8-98de-a261d5c7192b
begin
	"""A button that sends back the same value every time that it is clicked.

	You can use it to _trigger reactive cells_.

	**See also [`CounterButton`](@ref)** to get the *number of times* the button was clicked.

	## Examples

	In one cell:

	```julia
	@bind go Button("Go!")
	```

	and in a second cell:

	```julia
	begin
		# reference the bound variable - clicking the button will run this cell
		go

		md"My favorite number is $(rand())!"
	end
	```
	"""
	struct LabelButton
		label::AbstractString
	end
	LabelButton() = LabelButton("Click")

	function Base.show(io::IO, m::MIME"text/html", button::LabelButton)
		show(io, m, @htl("""<input type="button" value="$(button.label)">"""))
	end

	Base.get(button::LabelButton) = button.label
end

# ╔═╡ 7f8e4abf-e7e7-47bc-b1cc-514fa1af106c
const Button = LabelButton

# ╔═╡ 3ae2351b-ac4a-4669-bb11-39a1c029b301
Button()

# ╔═╡ 548bda96-2461-48a3-a3ad-6d113337826e
begin
	"""A button that sends back the number of times that it was clicked.

	You can use it to _trigger reactive cells_.

	## Examples

	In one cell:

	```julia
	@bind go CounterButton("Go!")
	```

	and in a second cell:

	```julia
	begin
		# reference the bound variable - clicking the button will run this cell
		go

		md"My favorite number is $(rand())!"
	end
	```
	"""
	struct CounterButton
		label::AbstractString
	end
	CounterButton() = CounterButton("Click")

	function Base.show(io::IO, m::MIME"text/html", button::CounterButton)
		show(io, m, @htl("""

		<input type="button" value="$(button.label)">

		"""))
	end

	Base.get(button::CounterButton) = button.label
end

# ╔═╡ 76c3b77b-08aa-4899-bbdd-4f8faa8d1486
begin
	"""A checkbox to choose a Boolean value `true`/`false`.

	## Examples

	`@bind programming_is_fun CheckBox()`

	`@bind julia_is_fun CheckBox(default=true)`

	`md"Would you like the thing? \$(@bind enable_thing CheckBox())"`
	"""
	struct CheckBox
		default::Bool
	end

	CheckBox(;default::Bool=false) = CheckBox(default)

	function Base.show(io::IO, ::MIME"text/html", button::CheckBox)
		print(io, """<input type="checkbox"$(button.default ? " checked" : "")>""")
	end

	Base.get(checkbox::CheckBox) = checkbox.default
end

# ╔═╡ f81bb386-203b-4392-b974-a1e2146b1a08
begin
	"""A text input (`<input type="text">`) - the user can type text, the text is returned as `String` via `@bind`.

	If `dims` is a tuple `(cols::Integer, row::Integer)`, a `<textarea>` will be shown, with the given dimensions

	Use `default` to set the initial value.

	See the [Mozilla docs about `<input type="text">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/text) and [`<textarea>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea)

	# Examples
	`@bind poem TextField()`

	`@bind poem TextField((30,5); default="Hello\nJuliaCon!")`"""
	struct TextField
		dims::Union{Tuple{Integer,Integer},Nothing}
		default::AbstractString
	end

	TextField(dims::Union{Tuple{Integer,Integer},Nothing}=nothing; default::AbstractString="") = TextField(dims, default)

	function Base.show(io::IO, m::MIME"text/html", textfield::TextField)
		show(io, m,
		if textfield.dims === nothing
			@htl("""<input type="text" value=$(textfield.default)>""")
		else
			@htl("""<textarea cols=$(textfield.dims[1]) rows=$(textfield.dims[2])>$(textfield.default)</textarea>""")
		end
		)
	end

	Base.get(textfield::TextField) = textfield.default
end

# ╔═╡ 4363f31e-1d71-4ad8-bfe8-04403d2d3621
TextField((30,2), default=teststr);

# ╔═╡ c9614498-54a8-4925-9353-7a13d3303916
begin
	"""A password input (`<input type="password">`) - the user can type text, the text is returned as `String` via `@bind`.

	This does not provide any special security measures, it just renders black dots (•••) instead of the typed characters.

	Use `default` to set the initial value.

	See the [Mozilla docs about `<input type="password">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/password)

	# Examples
	`@bind secret_poem PasswordField()`

	`@bind secret_poem PasswordField(default="Te dansen omdat men leeft")`"""
	Base.@kwdef struct PasswordField
		default::AbstractString=""
	end

	function Base.show(io::IO, m::MIME"text/html", passwordfield::PasswordField)
		show(io, m, @htl("""<input type="password" value=$(passwordfield.default)>"""))
	end

	Base.get(passwordfield::PasswordField) = passwordfield.default

end

# ╔═╡ eb4e17fd-07ba-4031-a39f-0d9fccd3d886
begin
	"""A dropdown menu (`<select>`) - the user can choose one of the `options`, an array of `String`s.

	See [`MultiSelect`](@ref) for a version that allows multiple selected items.

	`options` can also be an array of pairs `key::String => value::Any`. The `key` is returned via `@bind`; the `value` is shown.

	See the [Mozilla docs about `select`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select)

	# Examples
	`@bind veg Select(["potato", "carrot"])`

	`@bind veg Select(["potato" => "🥔", "carrot" => "🥕"])`

	`@bind veg Select(["potato" => "🥔", "carrot" => "🥕"], default="carrot")`"""
	struct Select
		options::Vector{Pair{<:AbstractString,<:Any}}
		default::Union{Missing, AbstractString}
	end

	Select(options::AbstractVector{<:AbstractString}; default=missing) = Select([o => o for o in options], default)

	Select(options::AbstractVector{<:Pair{<:AbstractString,<:Any}}; default=missing) = Select(options, default)

	function Base.show(io::IO, m::MIME"text/html", select::Select)
		show(io, m, @htl("""
				<select>$(
		map(select.options) do o
				@htl(
				"<option value=$(o.first) selected=$(!ismissing(select.default) && o.first == select.default)>$(
				o.second
				)</option>")
			end
		)</select>"""))
	end

	Base.get(select::Select) = ismissing(select.default) ? first(select.options).first : select.default

end

# ╔═╡ d64bb805-b700-4fd6-8894-2980152ce250
Select(["a" => "✅", "b" => "🆘", "c" => "🆘"])

# ╔═╡ 4f3ba840-28ce-4790-b929-ce6af8920189
Select(["a" => "🆘", "b" => "✅", "c" => "🆘"]; default="b")

# ╔═╡ 5bacf96d-f24b-4e8b-81c7-47140f286e27
begin
"""A multi-selector (`<select multi>`) - the user can choose one or more of the `options`, an array of `Strings.

See [`Select`](@ref) for a version that allows only one selected item.

`options` can also be an array of pairs `key::String => value::Any`. The `key` is returned via `@bind`; the `value` is shown.

See the [Mozilla docs about `select`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select)

# Examples
`@bind veg MultiSelect(["potato", "carrot"])`

`@bind veg MultiSelect(["potato" => "🥔", "carrot" => "🥕"])`

`@bind veg MultiSelect(["potato" => "🥔", "carrot" => "🥕"], default=["carrot"])`"""
struct MultiSelect
    options::Vector{Pair{<:AbstractString,<:Any}}
    default::Union{Missing, AbstractVector{AbstractString}}
end
MultiSelect(options::AbstractVector{<:AbstractString}; default=missing) = MultiSelect([o => o for o in options], default)
MultiSelect(options::AbstractVector{<:Pair{<:AbstractString,<:Any}}; default=missing) = MultiSelect(options, default)

function Base.show(io::IO, m::MIME"text/html", select::MultiSelect)
	show(io, m, @htl("""
			<select multiple>$(
	map(select.options) do o
			@htl(
			"<option value=$(o.first) selected=$(!ismissing(select.default) && o.first ∈ select.default)>$(
			o.second
			)</option>")
		end
	)</select>"""))
end

Base.get(select::MultiSelect) = ismissing(select.default) ? Any[] : select.default
end

# ╔═╡ 998a3bd7-2d09-4b3f-8a41-50736b666dea
MultiSelect(["a" => "🆘", "b" => "✅", "c" => "🆘",  "d" => "✅", "c" => "🆘2", "c3" => "🆘"]; default=["b","d"])

# ╔═╡ e058076f-46fc-4435-ab45-530e27c95478
begin
"""A file upload box. The chosen file will be read by the browser, and the bytes are sent back to Julia.

The optional `accept` argument can be an array of `MIME`s. The user can only select files with these MIME. If only `image/*` MIMEs are allowed, then smartphone browsers will open the camera instead of a file browser.

## Examples

`@bind file_data FilePicker()`

`file_data["data"]`

You can limit the allowed MIME types:

```julia
@bind image_data FilePicker([MIME("image/jpg"), MIME("image/png")])
# and use MIME groups:
@bind image_data FilePicker([MIME("image/*")])
```
"""
struct FilePicker
    accept::Array{MIME,1}
end
FilePicker() = FilePicker(MIME[])

function Base.show(io::IO, m::MIME"text/html", filepicker::FilePicker)
	show(io, m, @htl("""<input type='file' accept=$(
    join(string.(filepicker.accept), ",")
    )>"""))
end

Base.get(select::FilePicker) = Dict("name" => "", "data" => UInt8[], "type" => "")
end

# ╔═╡ db65293b-891a-43a3-8a42-b23bf542755f
FilePicker([MIME"image/png"()])

# ╔═╡ 42e9e5ab-7d34-4300-a6c0-47f5cde658d8
begin
"""A group of radio buttons - the user can choose one of the `options`, an array of `String`s.

`options` can also be an array of pairs `key::String => value::Any`. The `key` is returned via `@bind`; the `value` is shown.

# Examples
`@bind veg Radio(["potato", "carrot"])`

`@bind veg Radio(["potato" => "🥔", "carrot" => "🥕"])`

`@bind veg Radio(["potato" => "🥔", "carrot" => "🥕"], default="carrot")`

"""
struct Radio
    options::Vector{Pair{<:AbstractString,<:Any}}
    default::Union{Nothing, AbstractString}
end
Radio(options::AbstractVector{<:AbstractString}; default=nothing) = Radio([o => o for o in options], default)
Radio(options::AbstractVector{<:Pair{<:AbstractString,<:Any}}; default=nothing) = Radio(options, default)

function Base.show(io::IO, m::MIME"text/html", radio::Radio)
    groupname = randstring('a':'z')

	h = @htl("""
		<form>$(
		map(radio.options) do o
			@htl("""

				<input
					type="radio"
					id=$(groupname * o.first)
					name=$(groupname)
					value=$(o.first)
					checked=$(radio.default === o.first)
					>

                $(
					o.second
				)

""")
        end
		)

		</form>
	""")
	show(io, m, h)
end

Base.get(radio::Radio) = radio.default
end

# ╔═╡ 7c4303a1-19be-41a2-a6c7-90146e01401d
md"""
nothing checked by defualt, the initial value should be `nothing`
"""

# ╔═╡ d9522557-07e6-4a51-ae92-3abe7a7d2732
r1s = [];

# ╔═╡ d611e6f7-c574-4f0f-a46f-48ec8cf4b5aa
begin

"""A date input (`<input type="date">`) - the user can pick a date, the date is returned as `Dates.DateTime` via `@bind`.

Use `default` to set the initial value.

See the [Mozilla docs about `<input type="date">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date)

# Examples
`@bind best_day_of_my_live DateField()`

`@bind best_day_of_my_live DateField(default=today())`"""
Base.@kwdef struct DateField
    default::Union{Dates.TimeType,Nothing}=nothing
end

function Base.show(io::IO, m::MIME"text/html", datefield::DateField)
	show(io, m, @htl("""<input
				type="date"
				value=$(datefield.default === nothing ? "" : Dates.format(datefield.default, "Y-mm-dd"))
			>"""))
end
Base.get(datefield::DateField) = datefield.default === nothing ? nothing : Dates.DateTime(datefield.default)
end

# ╔═╡ ea7c4d05-c516-4f07-9d48-7df9ce997939
begin

"""A time input (`<input type="time">`) - the user can pick a time, the time is returned as `String` via `@bind` (e.g. `"15:45"`). Value is `""` until a time is picked.

Use `default` to set the initial value.

See the [Mozilla docs about `<input type="time">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/time)

# Examples
`@bind lunch_time TimeField()`

`@bind lunch_time TimeField(default=now())`"""
Base.@kwdef struct TimeField
    default::Union{Dates.TimeType,Nothing}=nothing
end

function Base.show(io::IO, m::MIME"text/html", timefield::TimeField)
	show(io, m, @htl("<input
		type='time'
		value=$(
			timefield.default === nothing ? nothing : Dates.format(timefield.default, "HH:MM")
		)
	>"))
end
Base.get(timefield::TimeField) = timefield.default === nothing ?  "" : Dates.format(timefield.default, "HH:MM")
end

# ╔═╡ 4c9c1e24-235f-44f6-83f3-9f985f7fb536
# bti

# ╔═╡ e9feb20c-3667-4ea9-9278-6b68ece1de6c
begin

"""A color input (`<input type="color">`) - the user can pick an RGB color, the color is returned as color hex `String` via `@bind`. The value is lowercase and starts with `#`.

Use `default` to set the initial value.

See the [Mozilla docs about `<input type="color">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/color)

# Examples
`@bind color ColorStringPicker()`

`@bind color ColorStringPicker(default="#aabbcc")`
"""
Base.@kwdef struct ColorStringPicker
    default::String="#000000"
end

function Base.show(io::IO, ::MIME"text/html", colorStringPicker::ColorStringPicker)
    withtag(() -> (), io, :input, :type=>"color", :value=>colorStringPicker.default)
end
Base.get(colorStringPicker::ColorStringPicker) = colorStringPicker.default
end

# ╔═╡ ec870eea-36a4-48b6-95d7-f7c083e29856
bs = @bind s1 Slider(1:10)

# ╔═╡ b44f1128-32a5-4d1d-a00b-446143074056
bs

# ╔═╡ f6cd1201-da84-4dee-9e88-b65fa1ff749e
@bind s2 Slider(0:.1:1, default=.5, show_value=true)

# ╔═╡ 05f6a603-b738-47b1-b335-acaaf480a240
s1, s2

# ╔═╡ c6d68308-53e7-4c60-8649-8f0161f28d70
@bind b1 Button(teststr)

# ╔═╡ c111da12-d0ca-4b9b-8ede-20f4303a1c4b
b1

# ╔═╡ cd08b524-d778-4acd-9fac-851d90df7179
@bind cb1 CounterButton()

# ╔═╡ 6135dca4-86f9-4675-8a45-fa16b3d2c3eb
cb1

# ╔═╡ 6cb75589-5496-4edd-9b21-ea49d5c0e733
bc = @bind c1 CheckBox()

# ╔═╡ bcee47b1-0f45-4649-8517-0e93fa92bfe5
bc

# ╔═╡ 73656df8-ac9f-466d-a8d0-0a2e5dbdbd8c
@bind c2 CheckBox(true)

# ╔═╡ e89ee9a3-5c78-4ff8-81e9-f44f5150d5f6
c1, c2

# ╔═╡ 1e522148-542a-4a2f-ad92-12421a6530dc
bt1 = @bind t1 TextField()

# ╔═╡ 1ac4abe2-5f06-42c6-b614-fb9a00e65386
bt1

# ╔═╡ 1d81db28-103b-4bde-9a9a-f3038ee9b10b
@bind t2 TextField(default=teststr)

# ╔═╡ e25a2ec1-5dab-461e-bc47-6b3f1fe19d30
bt2 = @bind t3 TextField((30,2), teststr)

# ╔═╡ be68f41c-0730-461c-8782-7e8d7a745509
bt2

# ╔═╡ 00145a3e-cb62-4c54-807b-8d2bce6a9fc9
t1, t2, t3

# ╔═╡ 970681ed-1c3a-4327-b636-8cb0cdd90dbb
bpe = @bind p1 PasswordField()

# ╔═╡ e6032ca6-03a5-4bda-95d2-dcd9ee6b5924
bpe

# ╔═╡ d4bf5249-6027-43c5-bd20-48ad95721e27
@bind p2 PasswordField(teststr)

# ╔═╡ d8c60294-0ca6-4cb0-b51d-9f6d6b370b28
@bind p3 PasswordField(default=teststr)

# ╔═╡ fbc6e4c1-4bd8-43a2-ac82-e6f76033fd8e
p1, p2, p3

# ╔═╡ 57a7d0c9-2f4a-44e6-9b7a-0bbd98611c9d
bse = @bind se1 Select(["a" => "default", teststr => teststr])

# ╔═╡ a58e383a-3837-4b4c-aa84-cf64436cd870
bse

# ╔═╡ 7f05f0b5-051e-4c75-b484-944daf8a274d
se1

# ╔═╡ 78473a2f-0a64-4aa5-a60a-94031a4167b8
bms = @bind ms1 MultiSelect(["a" => "default", teststr => teststr])

# ╔═╡ 43f86637-9f0b-480c-826a-bbf583e44646
bms

# ╔═╡ b6697df5-fd21-4553-9e90-1d33c0b51f70
ms1

# ╔═╡ a03af14a-e030-4ac1-b61a-0275c9956454
bf = @bind f1 FilePicker()

# ╔═╡ d4a0e98d-666c-4588-8499-f253a309a403
bf

# ╔═╡ 5ed47c49-9a31-4948-8473-0311b54eb146
f1

# ╔═╡ a95684ea-4612-45d6-b63f-41c051b53ed8
br1 = @bind r1 Radio(["a" => "default", teststr => teststr])

# ╔═╡ a5612030-0781-4cf1-b8f0-409bd3886154
br1

# ╔═╡ c2b3a7a4-8c9e-49cc-b5d0-85ad1c08fd72
r1

# ╔═╡ 69a94f6a-420a-4587-bbad-1219a390862d
push!(r1s, r1)

# ╔═╡ a1666896-baf6-466c-b680-5f3e3dffff68
bd = @bind d1 DateField()

# ╔═╡ b9300522-1b92-459c-87e2-20589d36dbb5
bd

# ╔═╡ 65bdad5e-a51b-4009-8b8e-ce93286ee5e4
d1

# ╔═╡ 4f1a909d-d21a-4e60-a615-8146ba249794
@bind d2 DateField(Dates.Date(2021, 09, 20))

# ╔═╡ d52cc4d9-cdb0-46b6-a59f-5eeaa1990f20
d2

# ╔═╡ 3aefce73-f133-43e0-8680-5c17b7f90979
bti = @bind ti3 TimeField()

# ╔═╡ d128f5ac-7304-486c-8258-f05f4bd18632
ti3

# ╔═╡ 9258586a-2612-48db-be31-cf74220002d4
bti

# ╔═╡ 7a377816-30ed-4f9f-b03f-08da4548e55f
ti3

# ╔═╡ a51dc258-1e80-4cd4-9337-b9f685db244c
@bind ti2 TimeField(Dates.Time(15, 45))

# ╔═╡ 3171441c-a98b-4a5a-aedd-09ad3b445b9e
ti2

# ╔═╡ b123275c-48fd-4e4a-8461-4875f7c18293
bco = @bind co1 ColorStringPicker()

# ╔═╡ 883673fb-b8d0-49fb-ab8c-32e972894ec2
bco

# ╔═╡ 78463563-4d1f-49f0-875f-8a30cf445a2d
co1

# ╔═╡ 1d95c38d-d336-436d-a62e-0a3786c321ca
ColorStringPicker("#ffffff")

# ╔═╡ 724125f3-7699-4103-a5d8-bc6a00fab0ff
ColorStringPicker(default="#abbaff")

# ╔═╡ 9ade9240-1fea-4cb7-a571-a98b13cc29b2
"""
Line break without creating a new paragraph. Useful inside the `md"` macro:

# Example
```julia
md"\""
Hello \$br world!
"\""
```
"""
const br = HTML("
")

# ╔═╡ 98d251ff-67e7-4b16-b2e0-3e2102918ca2
export Slider, NumberField, Button, LabelButton, CounterButton, CheckBox, TextField, PasswordField, Select, MultiSelect, Radio, FilePicker, DateField, TimeField, ColorStringPicker, br

# ╔═╡ Cell order:
# ╟─e8c5ba24-10e9-49e8-8c11-0add092637f8
# ╟─e1bbe1d7-68ef-4ee1-8174-d1ae1f822acb
# ╟─d738b448-387b-4942-af82-cc93042705a4
# ╟─81adbd39-5780-4cc6-a53f-a4472bacf1c0
# ╠═d8f907cd-2f89-4d54-a311-998dc8ee148e
# ╠═a0fb4f28-bfe4-4877-bf07-31acb9a56d2c
# ╠═ac542b84-dbc8-47e2-8835-9e43582b6ad7
# ╠═6da84fb9-a629-4e4c-819e-dd87a3e267ce
# ╠═98d251ff-67e7-4b16-b2e0-3e2102918ca2
# ╠═d088bcdb-d851-4ad7-b5a0-751c1f348995
# ╠═ec870eea-36a4-48b6-95d7-f7c083e29856
# ╠═b44f1128-32a5-4d1d-a00b-446143074056
# ╠═f6cd1201-da84-4dee-9e88-b65fa1ff749e
# ╠═05f6a603-b738-47b1-b335-acaaf480a240
# ╠═f59eef32-4732-46db-87b0-3564433ce43e
# ╠═b7c21c22-17f5-44b8-98de-a261d5c7192b
# ╠═7f8e4abf-e7e7-47bc-b1cc-514fa1af106c
# ╠═c6d68308-53e7-4c60-8649-8f0161f28d70
# ╠═c111da12-d0ca-4b9b-8ede-20f4303a1c4b
# ╠═3ae2351b-ac4a-4669-bb11-39a1c029b301
# ╠═548bda96-2461-48a3-a3ad-6d113337826e
# ╠═6135dca4-86f9-4675-8a45-fa16b3d2c3eb
# ╠═cd08b524-d778-4acd-9fac-851d90df7179
# ╠═76c3b77b-08aa-4899-bbdd-4f8faa8d1486
# ╠═6cb75589-5496-4edd-9b21-ea49d5c0e733
# ╠═bcee47b1-0f45-4649-8517-0e93fa92bfe5
# ╠═73656df8-ac9f-466d-a8d0-0a2e5dbdbd8c
# ╠═e89ee9a3-5c78-4ff8-81e9-f44f5150d5f6
# ╠═f81bb386-203b-4392-b974-a1e2146b1a08
# ╠═1e522148-542a-4a2f-ad92-12421a6530dc
# ╠═1ac4abe2-5f06-42c6-b614-fb9a00e65386
# ╠═1d81db28-103b-4bde-9a9a-f3038ee9b10b
# ╠═e25a2ec1-5dab-461e-bc47-6b3f1fe19d30
# ╠═be68f41c-0730-461c-8782-7e8d7a745509
# ╠═4363f31e-1d71-4ad8-bfe8-04403d2d3621
# ╠═00145a3e-cb62-4c54-807b-8d2bce6a9fc9
# ╠═c9614498-54a8-4925-9353-7a13d3303916
# ╠═970681ed-1c3a-4327-b636-8cb0cdd90dbb
# ╠═e6032ca6-03a5-4bda-95d2-dcd9ee6b5924
# ╠═d4bf5249-6027-43c5-bd20-48ad95721e27
# ╠═d8c60294-0ca6-4cb0-b51d-9f6d6b370b28
# ╠═fbc6e4c1-4bd8-43a2-ac82-e6f76033fd8e
# ╠═eb4e17fd-07ba-4031-a39f-0d9fccd3d886
# ╠═57a7d0c9-2f4a-44e6-9b7a-0bbd98611c9d
# ╠═a58e383a-3837-4b4c-aa84-cf64436cd870
# ╠═7f05f0b5-051e-4c75-b484-944daf8a274d
# ╠═d64bb805-b700-4fd6-8894-2980152ce250
# ╠═4f3ba840-28ce-4790-b929-ce6af8920189
# ╠═5bacf96d-f24b-4e8b-81c7-47140f286e27
# ╠═78473a2f-0a64-4aa5-a60a-94031a4167b8
# ╠═43f86637-9f0b-480c-826a-bbf583e44646
# ╠═b6697df5-fd21-4553-9e90-1d33c0b51f70
# ╠═998a3bd7-2d09-4b3f-8a41-50736b666dea
# ╠═e058076f-46fc-4435-ab45-530e27c95478
# ╠═a03af14a-e030-4ac1-b61a-0275c9956454
# ╠═d4a0e98d-666c-4588-8499-f253a309a403
# ╠═5ed47c49-9a31-4948-8473-0311b54eb146
# ╠═db65293b-891a-43a3-8a42-b23bf542755f
# ╠═42e9e5ab-7d34-4300-a6c0-47f5cde658d8
# ╠═57232d88-b74f-4823-be61-8db450c93f5c
# ╟─7c4303a1-19be-41a2-a6c7-90146e01401d
# ╠═a95684ea-4612-45d6-b63f-41c051b53ed8
# ╠═a5612030-0781-4cf1-b8f0-409bd3886154
# ╠═c2b3a7a4-8c9e-49cc-b5d0-85ad1c08fd72
# ╠═69a94f6a-420a-4587-bbad-1219a390862d
# ╠═d9522557-07e6-4a51-ae92-3abe7a7d2732
# ╠═d611e6f7-c574-4f0f-a46f-48ec8cf4b5aa
# ╠═a1666896-baf6-466c-b680-5f3e3dffff68
# ╠═b9300522-1b92-459c-87e2-20589d36dbb5
# ╠═65bdad5e-a51b-4009-8b8e-ce93286ee5e4
# ╠═4f1a909d-d21a-4e60-a615-8146ba249794
# ╠═d52cc4d9-cdb0-46b6-a59f-5eeaa1990f20
# ╠═ea7c4d05-c516-4f07-9d48-7df9ce997939
# ╠═3aefce73-f133-43e0-8680-5c17b7f90979
# ╠═d128f5ac-7304-486c-8258-f05f4bd18632
# ╠═9258586a-2612-48db-be31-cf74220002d4
# ╠═4c9c1e24-235f-44f6-83f3-9f985f7fb536
# ╠═7a377816-30ed-4f9f-b03f-08da4548e55f
# ╠═a51dc258-1e80-4cd4-9337-b9f685db244c
# ╠═3171441c-a98b-4a5a-aedd-09ad3b445b9e
# ╠═e9feb20c-3667-4ea9-9278-6b68ece1de6c
# ╠═b123275c-48fd-4e4a-8461-4875f7c18293
# ╠═883673fb-b8d0-49fb-ab8c-32e972894ec2
# ╠═78463563-4d1f-49f0-875f-8a30cf445a2d
# ╠═1d95c38d-d336-436d-a62e-0a3786c321ca
# ╠═724125f3-7699-4103-a5d8-bc6a00fab0ff
# ╠═9ade9240-1fea-4cb7-a571-a98b13cc29b2

ext: jl


text:
# run_random_set
fname = "../poets/random_set_generator.jl"
include(fname)

start_random = true # false
global HOLD=0
fname = "../poets/emt_grn_model_objective_function.jl"
include(fname)

# Set parameters and pointers

initial_state = Array{Float64,1}(parameter_array)

# Execute the beast
println(now())
EC = generate_random_set(objective_function,deepcopy(parameter_array),"../poets/results_poets/random_set/EC_full.dat",
10.0,100)
println(now())
# Save output

outdir= "../poets/results_poets/random_set"
writedlm("$outdir/EC_full.dat", EC)
#writedlm("$outdir/PC.dat", PC)
#writedlm("$outdir/RA.dat", RA)


text:
primitive type Infinity <: Number 8 end

Infinity(x::Real) = x<0 ? reinterpret(Infinity, Int8(-1)) : x>0 ? reinterpret(Infinity, Int8(1)) : throw(DomainError("Value must not be 0"))

function show(io::IO, z::Infinity)
    if z == Infinity(1)
        inf = "∞"
    else
        inf = "-∞"
    end
    print(io, inf)
end

const ∞ = Infinity(1)

+(x::Infinity) = x
-(x::Infinity) = x == ∞ ? Infinity(-1) : ∞
inv(x::Infinity) = x

Finite = Union{Integer,PrimeField}

==(::Infinity,::Finite) = false
==(::Finite,::Infinity) = false

+(x::Infinity,::Integer...) = x
-(x::Infinity,::Integer...) = x
+(x::Infinity,y::Infinity) = x == y ? x : NaN
*(n::Signed,x::Infinity) = n == 0 ? 0 : n < 0 ? -x : x
^(x::Infinity,n::Integer) = x


text:
#
#  Functions for bringing and MPO into left or right canonical form
#
function orthogonalize!(W1::ITensor,W2::ITensor,ul::reg_form,kwargs...)
    W1,Lplus=block_qx(W1,ul;kwargs...)
    W2=Lplus*W2
    @assert order(W2)<=4 #make sure there was something to contract.

    iq=filterinds(inds(Lplus),tags="qx")[1]
    il=noncommonind(Lplus,iq)
    #pprint(iq,Lplus,il,1e-14)
    il=Index(dim(iq),tags(il))
    replaceind!(W1,iq,il)
    replaceind!(W2,iq,il)
    ITensors.@debug_check begin
        @assert is_regular_form(W1,ul,1e-14)
        @assert is_regular_form(W2,ul,1e-14)
    end
    return W1,W2 #We should not need to return these if W1 and W2 were truely passed by reference.
end

function orthogonalize!(H::MPO,ul::reg_form;kwargs...)
    lr::orth_type=get(kwargs, :orth, left)
    N=length(H)
    if lr==left
        rng=1:1:N-1 #sweep left to right
    else #right
        rng=N:-1:2 #sweep right to left
    end
    for n in rng
        nn=n+rng.step #index to neighbour
        #@show n,nn,nl
        H[n],H[nn]=orthogonalize!(H[n],H[nn],ul,kwargs...)
    end
end

@doc """
    orthogonalize!(H::MPO)

Bring an MPO into left or right canonical form using block respecting QR decomposition
 as described in:
> Daniel E. Parker, Xiangyu Cao, and Michael P. Zaletel Phys. Rev. B 102, 035147

# Keywords
- `orth::orth_type = left` : choose `left` or `right` canonical form
- `sweeps::Int64` : number of sweeps to perform. If sweeps is zero or not set then sweeps
   continue until there is no change in the internal dimensions from rank revealing QR.
- `epsrr::Float64 = 1e-14` : cutoff for rank revealing QX which removes zero pivot rows and columns.
   All rows with max(abs(R[r,:]))<epsrr are considered zero and removed.

# Examples
```julia
julia> using ITensors
julia> using ITensorMPOCompression
julia> N=10; #10 sites
julia> NNN=7; #Include up to 7th nearest neighbour interactions
julia> sites = siteinds("S=1/2",N);
#
# This makes H directly, bypassing autoMPO.  (AutoMPO is too smart for this
# demo, it makes maximally reduced MPOs right out of the box!)
#
julia> H=make_transIsing_MPO(sites,NNN);
#
#  Make sure we have a regular form or orhtogonalize! won't work.
#
julia> is_lower_regular_form(H)==true
true
#
#  Let's see what the second site for the MPO looks like.
#  I = unit operator, and S = any other operator
#
julia> pprint(H[2])
I 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
S 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
.
.
.
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 I 0 0
0 S 0 S 0 0 S 0 0 0 S 0 0 0 0 S 0 0 0 0 0 S 0 0 0 0 0 0 S I
#
#  Now we can orthogonalize or bring it into canonical form.
#  Defaults are left orthogonal with rank reduction.
#
julia> orthogonalize!(H)
#
#  Wahoo .. rank reduction knocked the size of H way down, and we haven't
#  tried compressing yet!
#
julia> pprint(H[2])
I 0 0 0 0
S S S 0 0
0 0 0 S I
#
#  What do all the bond dimensions of H look like?  We will need compression
#  (truncation) in order to further bang down the size of H
#
julia> get_Dw(H)
9-element Vector{Int64}: 3 5 9 13 12 9 6 4 3
#
#  wrap up with two more checks on the structure of H
#
julia> is_lower_regular_form(H)==true
true
julia> is_orthogonal(H,left)==true
true

```

"""
function orthogonalize!(H::MPO;kwargs...)
    (bl,bu)=detect_regular_form(H,1e-14)
    if !(bl || bu)
        throw(ErrorException("orthogonalize!(H::MPO), H must be in either lower or upper regular form"))
    end
    @assert !(bl && bu)
    ul::reg_form = bl ? lower : upper #if both bl and bu are true then something is seriously wrong
    nsweep=get(kwargs,:sweeps,0)
    if length(kwargs)>0
        kwargs=Dict(kwargs) #this allows us to set the dir elements
    else
        kwargs=Dict{Symbol, Any}(:orth => left)
    end
    lr=get(kwargs,:orth,left)
    lrm=mirror(lr)
    if nsweep>0
        for isweep in 1:nsweep
            kwargs[:orth]=lrm
            orthogonalize!(H,ul;kwargs...)
            kwargs[:orth]=lr
            orthogonalize!(H,ul;kwargs...)
        end
    else
        Dws=get_Dw(H)
        if !haskey(kwargs,:orth)
            @show kwargs
            get!(kwargs,:orth,lr)
        end
        while true
            kwargs[:orth]=lrm
            orthogonalize!(H,ul;kwargs...)
            kwargs[:orth]=lr
            orthogonalize!(H,ul;kwargs...)
            new_Dws=get_Dw(H)
            if new_Dws==Dws break end
            Dws=new_Dws
        end
    end
end


text:
# ---
# title: 1184. Distance Between Bus Stops
# id: problem1184
# author: Tian Jun
# date: 2020-10-31
# difficulty: Easy
# categories: Array
# link: <https://leetcode.com/problems/distance-between-bus-stops/description/>
# hidden: true
# ---
#
# A bus has `n` stops numbered from `0` to `n - 1` that form a circle. We know
# the distance between all pairs of neighboring stops where `distance[i]` is the
# distance between the stops number `i` and `(i + 1) % n`.
#
# The bus goes along both directions i.e. clockwise and counterclockwise.
#
# Return the shortest distance between the given `start` and `destination`
# stops.
#
#
#
# **Example 1:**
#
# ![](https://assets.leetcode.com/uploads/2019/09/03/untitled-diagram-1.jpg)
#
#
#
#     Input: distance = [1,2,3,4], start = 0, destination = 1
#     Output: 1
#     Explanation: Distance between 0 and 1 is 1 or 9, minimum is 1.
#
#
#
# **Example 2:**
#
# ![](https://assets.leetcode.com/uploads/2019/09/03/untitled-diagram-1-1.jpg)
#
#
#
#     Input: distance = [1,2,3,4], start = 0, destination = 2
#     Output: 3
#     Explanation: Distance between 0 and 2 is 3 or 7, minimum is 3.
#
#
#
#
# **Example 3:**
#
# ![](https://assets.leetcode.com/uploads/2019/09/03/untitled-diagram-1-2.jpg)
#
#
#
#     Input: distance = [1,2,3,4], start = 0, destination = 3
#     Output: 4
#     Explanation: Distance between 0 and 3 is 6 or 4, minimum is 4.
#
#
#
#
# **Constraints:**
#
#   * `1 <= n <= 10^4`
#   * `distance.length == n`
#   * `0 <= start, destination < n`
#   * `0 <= distance[i] <= 10^4`
#
#
## @lc code=start
using LeetCode

## add your code here:
## @lc code=end


text:
function zero_halo_regions!(fields::Tuple, grid)
  for field in fields
      zero_halo_regions!(field, grid)
  end
  return nothing
end

function zero_halo_regions!(c::AbstractArray, grid)
    zero_west_halo!(c, grid.Hx, grid.Nx)
    zero_east_halo!(c, grid.Hx, grid.Nx)
   zero_south_halo!(c, grid.Hy, grid.Ny)
   zero_north_halo!(c, grid.Hy, grid.Ny)
     zero_top_halo!(c, grid.Hz, grid.Nz)
  zero_bottom_halo!(c, grid.Hz, grid.Nz)
  return nothing
end

  zero_west_halo!(c, H, N) = @views @. c[1:H, :, :] = 0
 zero_south_halo!(c, H, N) = @views @. c[:, 1:H, :] = 0
zero_bottom_halo!(c, H, N) = @views @. c[:, :, 1:H] = 0

 zero_east_halo!(c, H, N) = @views @. c[N+H+1:N+2H, :, :] = 0
zero_north_halo!(c, H, N) = @views @. c[:, N+H+1:N+2H, :] = 0
  zero_top_halo!(c, H, N) = @views @. c[:, :, N+H+1:N+2H] = 0


text:
## target

export Target,
       name, description,
       hasjit, hastargetmachine, hasasmparser

@checked struct Target
    ref::API.LLVMTargetRef
end
reftype(::Type{Target}) = API.LLVMTargetRef

function Target(triple::String)
    out_ref = Ref{API.LLVMTargetRef}()
    out_error = Ref{Cstring}()
    status = convert(Core.Bool, API.LLVMGetTargetFromTriple(triple, out_ref, out_error))

    if status
        error = unsafe_string(out_error[])
        API.LLVMDisposeMessage(out_error[])
        throw(LLVMException(error))
    end

    return Target(out_ref[])
end

name(t::Target) = unsafe_string(API.LLVMGetTargetName(ref(t)))

description(t::Target) = unsafe_string(API.LLVMGetTargetDescription(ref(t)))

hasjit(t::Target) = convert(Core.Bool, API.LLVMTargetHasJIT(ref(t)))
hastargetmachine(t::Target) = convert(Core.Bool, API.LLVMTargetHasTargetMachine(ref(t)))
hasasmparser(t::Target) = convert(Core.Bool, API.LLVMTargetHasAsmBackend(ref(t)))

# target iteration

export targets

struct TargetSet end

targets() = TargetSet()

Base.eltype(::TargetSet) = Target

function Base.haskey(::TargetSet, name::String)
    return API.LLVMGetTargetFromName(name) != C_NULL
end

function Base.get(::TargetSet, name::String, default)
    objref = API.LLVMGetTargetFromName(name)
    return objref == C_NULL ? default : Target(objref)
end

function Base.getindex(targetset::TargetSet, name::String)
    f = get(targetset, name, nothing)
    return f == nothing ? throw(KeyError(name)) : f
end

function Base.iterate(iter::TargetSet, state=API.LLVMGetFirstTarget())
    state == C_NULL ? nothing : (Target(state), API.LLVMGetNextTarget(state))
end

Base.IteratorSize(::TargetSet) = Base.SizeUnknown()


text:
"""
    SigmoidDerivative(x)

Derivative of the Sigmoid activation function.

    Usage:
```julia-repl
SigmoidDerivative(x)
```
Arguments:
- `x` : Input value.
"""
function SigmoidDerivative(x::Float64)
    x₁ = x * (1.0 - x)
    return x₁
end


text:
function trace_boundary(t::MooreInner, labels::AbstractArray, N::Int = 0)
    N = N == 0 ? maximum(labels) : N
    boundary = [Vector{CartesianIndex{2}}(undef, 0) for n = 1:N]
    # By padding we will avoid having to do out-of-bounds checking when we
    # consider a pixel's neighbourhood.
    labels_padded = padarray(labels, Fill(0, (1,1)))
    # Labeled neighbourhood used by the contour-tracking algorithm which follows
    # the Freeman chaincode convention.
    # 3 2 1
    # 4 P 0
    # 5 6 7
    N₈ = OffsetVector(CartesianIndex.([(0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1), (1, 0), (1, 1)]), 0:7)
    stroke_direction = OffsetVector([6, 6, 0, 0, 2, 2, 4, 4], 0:7)
    isfirst = fill(true, N)
    # CartesianIndices(labels) will loop over the "interior" of labels_padded.
    for p in CartesianIndices(labels)
        l = labels_padded[p]
        l₄ = labels_padded[p + N₈[4]]
        if l != 0 &&  l₄ == 0 && isfirst[l]
            isfirst[l] = false
            # We will pretend that the second contour pixel is actually the first
            # one that we have found. This pretence will help in implementing
            # Jacobs stopping criteria. Once we trace around the contour we
            # will have included the true "first" boundary point anyway.
            p₁, direction₁  = find_second_inner(p, N₈, labels_padded, l, stroke_direction)
            # In this instance the component must just be a single pixel so there is nothing to trace.
            if p₁ == p
                push!(boundary[l], p₁)
                continue
            end

            push!(boundary[l], p₁)
            # Jacobs stopping criteria means we stop if we enter the starting
            # boundary pixel in the same manner in which we entered it initially.
            # Conceptually, when tracing a moore neighbourhood
            # as a "circle" we will stop at a pixel either on an "up", "down", "left" or
            # "right" stroke.

            pₙ₊₁, directionₙ₊₁ = find_next_inner(p₁, direction₁, N₈, labels_padded, l, stroke_direction)
            while !(pₙ₊₁ == p₁ && directionₙ₊₁ == direction₁)
                push!(boundary[l], pₙ₊₁)
                directionₙ = directionₙ₊₁
                pₙ₊₁, directionₙ₊₁ = find_next_inner(pₙ₊₁, directionₙ, N₈, labels_padded, l, stroke_direction)
            end
        end
    end
    unique!.(boundary)
end

function find_second_inner(p, N₈, labels, l, stroke_direction)
    pₙ₊₁ = p
    current = 4
    for r = current:12
        if labels[p + N₈[mod(r, 8)]] == l
            pₙ₊₁ = p + N₈[mod(r, 8)]
            current = mod(r, 8)
            break
        end
    end
    pₙ₊₁, stroke_direction[current]
end

function find_next_inner(p, previous, N₈, labels, l, stroke_direction)
    # These initial values will be overwritten in the loop.
    pₙ₊₁ = p
    current = previous
    for r = 0:7
        dₜ =  mod(previous + r, 8)
        pₜ = p + N₈[dₜ]
        if labels[pₜ] == l
            pₙ₊₁ =  pₜ
            current = dₜ
            break
        end
    end
    pₙ₊₁, stroke_direction[current]
end


text:
mutable struct VariableSelector
    vars::Dict{Symbol, UnitRange{Int}}
    num_vars::Int

    function VariableSelector()
        new(Dict{Symbol, UnitRange{Int}}(), 0)
    end
end

(vs::VariableSelector)(name::Symbol) = vs.vars[name]
(vs::VariableSelector)(x::AbstractArray{T}, name::Symbol) where T = x[vs.vars[name]]

function add_var!(selector::VariableSelector, name::Symbol, size::Int)
    if haskey(selector.vars, name)
        throw(ArgumentError("Variable name '$name' already exists"))
    end
    if size < 1
        throw(ArgumentError("Variable size must be greater than 0"))
    end
    selector.vars[name] = selector.num_vars .+ (1:size)
    selector.num_vars += size

    selector.num_vars
end

mutable struct ConstraintSelector
    cons::Dict{Symbol, UnitRange{Int}}
    eqs::Vector{Int}
    ineqs::Vector{Int}
    num_cons::Int
    num_eqs::Int
    num_ineqs::Int

    function ConstraintSelector()
        new(Dict{Symbol, UnitRange{Int}}(), [], [], 0, 0, 0)
    end
end

function add_eq!(selector::ConstraintSelector, name::Symbol, size::Int)
    if haskey(selector.cons, name)
        throw(ArgumentError("Constraint name '$name' already exists"))
    end
    if size < 1
        throw(ArgumentError("Constraint size must be greater than 0"))
    end

    selector.cons[name] = selector.num_cons .+ (1:size)
    push!(selector.eqs, collect(selector.cons[name])...)

    selector.num_cons += size
    selector.num_eqs += size

    selector.num_eqs
end

function add_ineq!(selector::ConstraintSelector, name::Symbol, size::Int)
    if haskey(selector.cons, name)
        throw(ArgumentError("Constraint name '$name' already exists"))
    end
    if size < 1
        throw(ArgumentError("Constraint size must be greater than 0"))
    end

    selector.cons[name] = selector.num_cons .+ (1:size)
    push!(selector.ineqs, collect(selector.cons[name])...)

    selector.num_cons += size
    selector.num_ineqs += size

    selector.num_ineqs
end

(cs::ConstraintSelector)(name::Symbol) = cs.cons[name]


text:
module DitherImage

export ditherimage

function ditherimage(img::Array{Float64,2}, t::Task)
    width = size(img, 1)
    height = size(img, 2)
    tmp = copy(img)
    out = zeros(Float64, width, height)

    for i = 1:height
        for j = 1:width
            weights = consume(t)
            weights_sum = sum(weights)

            if tmp[j, i] >= 0.5
                out[j, i] = 1.0
            else
                out[j, i] = 0.0
            end

            diff = tmp[j, i] - out[j, i]

            if j < width
                tmp[j + 1, i] += diff * weights[1] / weights_sum
            end

            if i < height
                if j > 1
                    tmp[j - 1, i + 1] += diff * weights[2] / weights_sum
                end

                tmp[j, i + 1] += diff * weights[3] / weights_sum

                if j < width
                    tmp[j + 1, i + 1] += diff * weights[4] / weights_sum
                end
            end
        end
    end

    out
end

function ditherimage(img::Array{Float64,2})
    ditherimage(img, @task begin
        while true
            produce([7, 3, 5, 1])
        end
    end)
end

end #module


text:
struct ArcticDataCenter <: KNB
end

function pub_date(repo::ArcticDataCenter, mainpage)
    date_ele = eachmatch(sel"pubDate", mainpage.root)
    Dates.Date(text_only(first(date_ele)), "yyyy-mm-dd")
end


text:
function global_update_backup_swap!(mc::AbstractDQMC)
  # swap current stack and greens to backup stack and greens (more efficient than copying)
  mc.s.gb_u_stack, mc.s.u_stack = mc.s.u_stack, mc.s.gb_u_stack
  mc.s.gb_d_stack, mc.s.d_stack = mc.s.d_stack, mc.s.gb_d_stack
  mc.s.gb_t_stack, mc.s.t_stack = mc.s.t_stack, mc.s.gb_t_stack
  mc.s.gb_greens, mc.s.greens = mc.s.greens, mc.s.gb_greens # this is greens at time slice == p.slices
  mc.s.gb_log_det, mc.s.log_det = mc.s.log_det, mc.s.gb_log_det # this is logdet of greens at time slice == p.slices + 1
end

@inline function global_update_perform_shift!(mc::AbstractDQMC)
    @inbounds @views begin
      @simd for k in 1:mc.p.opdim
        mc.p.hsfield[k,:,:] .+= randuniform(mc.p.box_global)
      end
    end
end

function global_update(mc::AbstractDQMC)
  p = mc.p
  s = mc.s

  @assert (s.current_slice == p.slices) && (s.direction == -1)

  S_old = p.boson_action
  # if p.all_checks && !isapprox(S_old,calc_boson_action(p, l)) warn("Incorrect boson action found during attempt to do global update.") end

  global_update_backup_swap!(mc) # save current stack etc.
  s.gb_hsfield = copy(p.hsfield)

  global_update_perform_shift!(mc)
  build_stack(mc)
  propagate(mc)
  # now we have s.greens = G_{p.slices} (up to one down-wrap) and s.log_det = logdet of G_{p.slices + 1} for new globally shifted conf

  p.boson_action = calc_boson_action(mc)

  p_boson = exp(-(p.boson_action - S_old)) # exp_delta_S_boson

  # calculate detratio = fermion accept. prob.
  p_fermion = exp(s.gb_log_det - s.log_det)

  p_acc = p_boson * real(p_fermion)

  # @printf("p_boson %.2e\n",abs.(p_boson))
  # @printf("p_fermion %.2e\n",abs.(p_fermion))
  # @printf("p_acc %.2e\n",abs.(p_acc))
  # println("")

  if p_acc > 1.0 || rand() < p_acc
    return 1
  else
    # undo global move
    p.boson_action = S_old
    p.hsfield = s.gb_hsfield
    global_update_backup_swap!(mc)
    return 0
  end

end

max_stars_repo_name: crstnbr/dqmc

max_issues_repo_name: crstnbr/dqmc

max_forks_repo_name: crstnbr/dqmc


text:
# # [How to create a cancellable blocking API](@id ex-cancellablecontainers)

using Reagents: Block, CAS, Computed, Map, Read, Reagents, Return

# As demonstrated in the examples [Treiber stack](@ref ex-treiberstack) and
# [Michael and Scott queue](@ref ex-msqueue), reagents can be used for defining
# nonblocking data structures. However, reagents can also be used for
# constructing complex synchronization APIs.

# ## [Blocking containers](@id ex-blockingcontainers)
#
# When a value is not available in a nonblocking container, it is very useful to
# wait (*block*) until the value is available (as in
# [`Base.Channel`](https://docs.julialang.org/en/v1/base/parallel/#Base.Channel)).
# Using [`Reagents.channel`](@ref) (which we use here like an unbuffered
# `Base.Channel`), we can *mechanically* transform a nonblocking concurrent
# data container to a waitable data structure.
#
# To this end, let us define a simple wrapper type that wraps an underlying
# nonblocking data collection (`.data`) and the channel (`.send` and
# `.receive`):

struct Blocking{T,Data,Send,Receive}
    eltype::Val{T}
    data::Data          # holds value of type T
    send::Send          # swaps value::T -> nothing
    receive::Receive    # swaps nothing -> value::T
end

function Blocking(data)
    send, receive = Reagents.channel(eltype(data), Nothing)
    return Blocking(Val(eltype(data)), data, send, receive)
end

Base.eltype(::Type{<:Blocking{T}}) where {T} = T

# The idea is to try sending or receiving the item via the channel and *"then"*
# try to manipulate the data collection. We can do this *atomically* by using
# the choice reagent [`|`](@ref Reagents.:|). Note that the order of this
# operation is important. For example, when invoking `putting(b)`, it tries
# `b.send` first and this "attempt" is still active even during
# `putting(b.data)`. Since this attempt to `b.send` is atomically withdrawn when
# committing the reaction, the item is added to the data collection if and only
# if there is no other tasks invoking `taking(b)`.

putting(b::Blocking) = b.send | putting(b.data)
taking(b::Blocking) = b.receive | taking(b.data)

Base.put!(b::Blocking, x) = putting(b)(convert(eltype(b), x))
Base.take!(b::Blocking) = taking(b)()

# This `Blocking` wrapper can be used to extend existing nonblocking data
# structures such as [Treiber stack](@ref ex-treiberstack) and [Michael and
# Scott queue](@ref ex-msqueue) that we have already defined.

include("treiberstack.jl")
include("msqueue.jl")

# To this end, we need to transform `trypopping` and `trypoppingfirst` to a
# reagent that blocks when the item is not ready. This can be done by
# a simple helper reagent that blocks when the input is `nothing`:

blocknothing() = Map(x -> x === nothing ? Block() : something(x))

# Then, it is straightforward to define the `taking` and `putting` functions
# required by the `Blocking` wrapper:

putting(c::TreiberStack) = pushing(c)
taking(c::TreiberStack) = trypopping(c) ⨟ blocknothing()

putting(c::MSQueue) = pushing(c)
taking(c::MSQueue) = trypoppingfirst(c) ⨟ blocknothing()

# ### Test blocking containers

using Test

function test_put_take_queue()
    #=
    When there are enough items in the data container,
    `Blocking(MSQueue{Int}())` behaves like `MSQueue{Int}()`:
    =#
    items = Blocking(MSQueue{Int}())
    put!(items, 111)
    put!(items, 222)
    @test take!(items) == 111
    @test take!(items) == 222

    #=
    However, when `take!` is invoked on an empty collection (which is enforced
    by the "unfair scheduling" `yield(t)`), it blocks until the
    corresponding `put!` is invoked:
    =#
    t = @task take!(items)
    yield(t)
    put!(items, 333)
    @test fetch(t) === 333
end

# It works with `TreiberStack`, too:

function test_put_take_stack()
    items = Blocking(TreiberStack{Int}())
    put!(items, 111)
    put!(items, 222)
    @test take!(items) == 222
    @test take!(items) == 111

    t = @task take!(items)
    yield(t)
    put!(items, 333)
    @test fetch(t) === 333
end

# ## Generic cancellable operations
#
# It is often useful to cancel a blocking operation safely. This can be
# expressed quite naturally using reagents — we'll create a CancellationToken
# which can be composed with any blocking operation. The pattern is similar to
# [the Go idiom of listening to a `Done` channel](https://pkg.go.dev/context)
# as one of the blocking operations in a `select` statement.
#
# First, let us define a singleton sentinel value for indicating a given
# reaction is cancelled:

struct Cancelled end

# To illustrate the idea, let us again use a `Blocking(MSQueue{Int}())`:

function test_cancellation_idea()
    items = Blocking(MSQueue{Int}())

    #=
    We use an additional channel for sending the cancellation signal:
    =#
    send, receive = Reagents.channel(Cancelled, Nothing)

    #=
    The idea is to "listen to" the cancellation signal and then try to invoke a
    blocking reaction. If there is no cancellation signal, it behaves like the
    reagent without the cancellation:
    =#
    t = @task (receive | taking(items))()
    yield(t)
    put!(items, 111)
    @test fetch(t) == 111

    #=
    If the cancellation signal is fired before the corresponding `put!`, the
    result of the reaction is the sentinel `Cancelled()`.
    =#
    t = @task (receive | taking(items))()
    yield(t)
    send(Cancelled())
    @test fetch(t) isa Cancelled
end

# Note that the above idea is still hard to use directly, since
# `send(Cancelled())` only triggers the reactions that are happening
# simultaneously. We can introduce a `Reagents.Ref{Bool}` to make the
# cancellation permanent.
#
# Let us wrap this idea in a single object:

struct CancellationToken
    iscancelled::typeof(Reagents.Ref{Bool}())
    send::typeof(Reagents.channel(Cancelled, Nothing)[1])
    receive::typeof(Reagents.channel(Cancelled, Nothing)[2])
end

function CancellationToken()
    iscancelled = Reagents.Ref{Bool}(false)
    send, receive = Reagents.channel(Cancelled, Nothing)
    return CancellationToken(iscancelled, send, receive)
end

# We can then transform an arbitrary reagent to a reagent that can be cancelled
# via a "signal" through `CancellationToken` (defined in `cancel!` below). The
# resulting reagent is the composition of three components: `listener`,
# `checker`, and the original `reagent`:

function cancellable(reagent::Reagents.Reagent, token::CancellationToken)
    listener = Return(nothing) ⨟ token.receive
    checker = Read(token.iscancelled) ⨟ Map(x -> x ? Cancelled() : Block())
    return listener | checker | reagent
end

# The `listener` reagent is essentially equivalent to the idea demonstrated
# above.  It is prefixed with the `Return(nothing)` reagent to make sure we
# always invoke the `token.receive` swap point with the valid input `nothing`.
#
# The `checker` reagent checks `token.iscancelled`; if it is already `true`, it
# ends the reaction with the value `Cancelled()`.  Otherwise, it indicates that
# the next reagent should be tried by returning the `Block` failure value.
#
# Finally, if both `listener` and `checker` are blocked, the original `reagent`
# is invoked. When this `reagent` is blocked, the first reagent between
# `listener` and `reagent` that is awaken determines the result value of this
# reaction.
#
# We can then use `cancellable` combinator to define a `cancellable_take!`
# function:

cancellable_take!(b::Blocking, token::CancellationToken) = cancellable(taking(b), token)()

# To `cancel!` a `token`, we first set `iscancelled[]`. This way, all
# future `cancellable_take!` returns `Cancelled` due to the `checker` reagent
# defined above. We then clear out any existing peers listening to the
# `token.receive` swap endpoint.

function cancel!(token::CancellationToken)
    token.iscancelled[] = true
    while Reagents.trysync!(token.send, Cancelled()) !== nothing
    end
end

# ### Test generic cancellable operations

function test_cancellation_token()
    items = Blocking(MSQueue{Int}())
    token = CancellationToken()

    #=
    Before cancellation, `cancellable_take!` works like normal `take!`:
    =#

    t = @task cancellable_take!(items, token)
    yield(t)
    put!(items, 111)
    @test fetch(t) == 111

    #=
    Calling `cancel!(token)` cancels all `cancellable_take!(items, token)`
    calls that are already happening (waiting for an item) and also the calls
    happening after the cancellation.
    =#

    t = @task cancellable_take!(items, token)
    yield(t)
    cancel!(token)
    @test fetch(t) isa Cancelled
    @test cancellable_take!(items, token) isa Cancelled

    #=
    Note that the cancellation mechanism is introduced *outside* the
    `Blocking` container.  It is different from, e.g., cancelling
    `put!(::Base.Channel)` via closing the `Base.Channel`. Thus, the container
    itself still works:
    =#
    put!(items, 222)
    @test take!(items) == 222
end


text:
import Base.show

mutable struct ParameterSet
    arg_names::Vector{Symbol}
    arg_defaults::Vector
    arg_ranges::Vector
    arg_types::Vector{<:Type}
    n_args::Int
    #TODO: parameter constraints (e.g. ensure one parameter always greater than another)
    #TODO: refactor out the arg_ prefix (its redundant if they all start with it)
    function ParameterSet(arg_names::Vector{Symbol},
                          arg_defaults::Vector,
                          arg_ranges::Vector=[x:x for x in arg_defaults])
        @assert length(arg_names) == length(arg_defaults) == length(arg_ranges)
        @assert eltype.(arg_defaults) == eltype.(arg_ranges)
        arg_types::Vector{<:Type} = eltype.(arg_defaults)
        return new(arg_names, arg_defaults, arg_ranges, arg_types, length(arg_names))
    end
end

function get_n_runs(ps::ParameterSet)::Int
    n_runs = 1
    @inbounds for i in 1:ps.n_args
        n_runs *= length(ps.arg_ranges[i])
    end
    return n_runs
end

function get_param_combos(ps::ParameterSet; n_runs::Int=get_n_runs(ps))::Matrix
    combos = Matrix{Any}(n_runs, ps.n_args)
    P = 1
    for j in 1:ps.n_args
        n_vals = length(ps.arg_ranges[j])
        n_reps = ceil(Int, n_runs/(n_vals*P))
        for i in 1:n_vals
            first_row = ceil(Int, n_vals/P)*(i-1)+1
            step_by = ceil(Int, n_runs/(n_vals*n_reps))
            last_row = first_row + n_vals*step_by - 1
            rows = first_row:step_by:last_row
            arg_val = ps.arg_ranges[j][i]
            combos[rows,j] = arg_val
        end
        P *= n_vals
    end
    return combos
end

function get_run_params(ps::ParameterSet; n_runs::Int=get_n_runs(ps))::Vector{Dict{Symbol,Any}}
    n_runs = get_n_runs(ps)
    combos::Matrix{Any} = get_param_combos(ps, n_runs=n_runs)
    arg_dicts = Vector{Dict{Symbol,Any}}(n_runs)
    for i in 1:size(combos,1)
        tmp_dict = Dict{Symbol,Any}()
        for j in 1:size(combos,2)
            tmp_dict[ps.arg_names[j]] = combos[i,j]
        end
        arg_dicts[i] = tmp_dict
    end
    return arg_dicts
end

function generate_dict(ps::ParameterSet; arg_values::Vector=ps.arg_defaults)::Dict{Symbol,Any}
    out_dict = Dict{Symbol,Any}()
    for j in 1:ps.n_args
        out_dict[ps.arg_names[j]] = arg_values[j]
    end
    return out_dict
end

function show(io::IO, ps::ParameterSet)::Void
    print("Parameters:")
    @inbounds for i in 1:ps.n_args
        print("\n    ($i) $(ps.arg_names[i])  →  $(ps.arg_defaults[i])  ∈  {$(string(ps.arg_ranges[i]))} :: $(ps.arg_types[i])")
    end
end


text:
using StagedFilters
using Test
using PyCall
using BenchmarkTools;

@testset "StagedFilters.jl" begin
    N = 1_000_000
    data = convert.(Float64, collect(range(1, N , length = N)));
    smoothed = zeros(eltype(data), length(data)); # <--- wholesome, type stable code.
    savgol = pyimport("scipy.signal")."savgol_filter";
    x = PyObject(data);

    @info "Julia Float64"
    benchjl64 = @btime smooth!(SavitzkyGolayFilter{2,2}, $data, $smoothed);

    @info "Python Float64"
    benchpy64 = @btime $savgol($x,5,2,mode="wrap");

    data = convert.(Float32, collect(range(1, N, length = N)));
    smoothed = zeros(eltype(data), length(data)); # <--- wholesome, type stable$
    #savgol = pyimport("scipy.signal")."savgol_filter";
    x = PyObject(data);

    @info "Julia Float32"
    benchjl32 = @btime smooth!(SavitzkyGolayFilter{2,2}, $data, $smoothed);

    @info "Python Float32"
    benchpy32 = @btime $savgol($x,5,2,mode="wrap");

    @test benchpy64 ≈ benchjl64
    @test benchpy32 ≈ benchjl32
end


text:
struct NormalPeakUvD{T} <: UvSpectrumDensity{T}
    # Signal (Normal distribution with area A)
    A::T # Peak area
    UvNormal::Normal{T} # Normal distribution of the peak
    # background (Polynomial of order N)
    bg_poly::Polynomial{2,T}
    bgxl::T # x-value of the left background level
    bgxr::T # x-value of the right background level
    bgll::T # left background level
    bglr::T # right background level
end

function evaluate(d::NormalPeakUvD{T}, x::Real) where {T}
    return d.A * pdf(d.UvNormal, x) + d.bg_poly(x)
end

function NormalPeakUvD(nt::NamedTuple{(:A,:μ,:σ,:bgxl,:bgxr,:bgll,:bglr)})
    T = promote_type(typeof.(values(nt))...)
    poly_coeffs = poly_coeffs_from_levels(T(nt.bgxl), T(nt.bgxr), T(nt.bgll), T(nt.bglr))
    NormalPeakUvD(T(nt.A), Normal(T(nt.μ), T(nt.σ)), Polynomial(poly_coeffs), T(nt.bgxl), T(nt.bgxr), T(nt.bgll), T(nt.bglr))
end

function poly_coeffs_from_levels(bgxl, bgxr, bgll, bglr)
    slope = (bglr - bgll) / (bgxr - bgxl) # linear slope
    mid_offset = bgll + slope * 0.5*(bgxr - bgxl) # offset
    offset = mid_offset - (bgxr + bgxl)/2 * slope
    offset, slope
end

function initial_parameter_guess(d::Type{NormalPeakUvD}, h::StatsBase.Histogram{<:Any, 1}, ::Type{T} = Float64) where {T}
    nh = normalize(h)
    # estimate background parameters through side windows
    bgxl = T(h.edges[1][1])
    bgxr = T(h.edges[1][end])
    Δx_side = (bgxr - bgxl) / 8
    bgll = zero(T)
    bglr = zero(T)
    widths = diff(h.edges[1])
    inv_widths = inv.(widths)
    bgwl = zero(T)
    bgwr = zero(T)
    for i in 1:StatsBase.binindex(h, bgxl + Δx_side)
        bgll += h.weights[i] * inv_widths[i]
        bgwl += widths[i]
    end
    for i in StatsBase.binindex(h, bgxr - Δx_side):length(h.weights)
        bglr += h.weights[i] * inv_widths[i]
        bgwr += widths[i]
    end
    # estimate peak parameters
    μ::T = EmpiricalDistributions._mean(nh)[1]
    σ::T = sqrt(EmpiricalDistributions._var(nh, (μ,))[1])
    A::T = sum(h.weights) - (bgll*bgwl + bglr*bglr)/2
    if A < 0 A = sum(h.weights) end

    parshape = NamedTupleShape(
        A = ScalarShape{T}(),
        μ = ScalarShape{T}(),
        σ = ScalarShape{T}(),
        bgxl = ConstValueShape(bgxl),
        bgxr = ConstValueShape(bgxr),
        bgll = ScalarShape{T}(),
        bglr = ScalarShape{T}()
    )
    p0 = (
        A = A,
        μ = μ,
        σ = σ,
        bgxl = bgxl,
        bgxr = bgxr,
        bgll = bgll,
        bglr = bglr
    )
    lower_bounds = (
        A = T(0),
        μ = μ - σ,
        σ = T(σ/10),
        bgxl = T(bgxl - minimum(widths)),
        bgxr = T(bgxr - minimum(widths)),
        bgll = T(0),
        bglr = T(0)
    )
    upper_bounds = (
        A = T(2*sum(h.weights)),
        μ = μ + σ,
        σ = 3σ,
        bgxl = T(bgxl + minimum(widths)),
        bgxr = T(bgxr + minimum(widths)),
        bgll = T(2bgll),
        bglr = T(2bglr)
    )
    bounds = (
        A = lower_bounds.A..upper_bounds.A,
        μ = lower_bounds.μ..upper_bounds.μ,
        σ = lower_bounds.σ..upper_bounds.σ,
        bgxl = ConstValueDist(bgxl),
        bgxr = ConstValueDist(bgxr),
        bgll = lower_bounds.bgll..upper_bounds.bgll,
        bglr = lower_bounds.bglr..upper_bounds.bglr
    )
    p0, lower_bounds, upper_bounds, parshape, bounds
end

opt_fit(::Type{NormalPeakUvD}, h::Histogram{<:Any, 1}, ::Type{T} = Float64) where {T} =
    opt_fit(RadiationSpectra.NormalPeakUvD, h, initial_parameter_guess(RadiationSpectra.NormalPeakUvD, h, T)[1:4]...)


text:
module System # Bukdu

import ..Bukdu: ApplicationController, Conn, Route, Deps, Plug, render
import Documenter.Utilities.DOM: @tags

struct HaltedError <: Exception
    msg
end

struct NotApplicableError <: Exception
    msg
end

struct InternalError <: Exception
    exception
    stackframes
end

struct SystemController <: ApplicationController
    conn::Conn
    err
end

struct MissingController <: ApplicationController
    conn::Conn
end

"""
    halted_error(c::SystemController)
"""
function halted_error(c::SystemController)
    @tags h3 p
    # set the status code when halted on Plug
    render(HTML, string(
        h3(string(HaltedError)),
        p(string(c.err.msg)),
    ))
end

"""
    not_applicable(c::SystemController)
"""
function not_applicable(c::SystemController)
    @tags h3 p
    c.conn.request.response.status = 500 # 500 Internal Server Error
    render(HTML, string(
        h3(string(NotApplicableError)),
        p(string(c.err.msg)),
    ))
end

"""
    internal_error(c::SystemController)
"""
function internal_error(c::SystemController)
    @tags h3 p
    c.conn.request.response.status = 500 # 500 Internal Server Error
    @error Symbol(:System_, :internal_error) c.err.exception string("\n    ", join(c.err.stackframes, "\n    "))
    render(HTML, string(
        h3(string(InternalError)),
        p(string(c.err.exception)),
        (p ∘ string).(c.err.stackframes)...
    ))
end

"""
    not_found(c::MissingController)
"""
function not_found(c::MissingController)
    @tags h3
    c.conn.request.response.status = 404 # 404 Not Found
    render(HTML, string(
        h3("Not Found"),
    ))
end

# info

const controller_rpad  = 20
const action_rpad      = 16
const target_path_rpad = 28

function _regularize_text(str::String, padding::Int)::String
    s = escape_string(str)
    if textwidth(s) < padding
        padded_str = rpad(s, padding)
        if textwidth(padded_str) > padding
        else
            return s
        end
    end
    n = 0
    a = []
    for (idx, x) in enumerate(s)
        n += textwidth(x)
        push!(a, x)
        if n > padding - 1
            break
        end
    end
    newstr = join(a)
    newdiff = textwidth(s) - textwidth(newstr)
    if length(s) == length(a)
        news = newstr
        npad = padding - textwidth(newstr)
    else
        if newdiff > 0 && length(a) >= 2
            newstr = join(a[1:end-2])
            newpad = padding - textwidth(newstr)
            news = string(newstr, fill('.', newpad)...)
        else
            news = newstr
        end
        npad = padding - textwidth(news)
    end
    news
end

function _unescape_req_target(req)
    str = req.target
    try
        str = Deps.HTTP.URIs.unescapeuri(req.target)
    catch
    end
    _regularize_text(str, target_path_rpad)
end

const style_request_action_others  = :red
const style_request_action = Dict{String,Symbol}(
    "GET"    => :normal,
    "POST"   => :yellow,
    "DELETE" => :magenta,
    "PATCH"  => :blue,
    "PUT"    => :cyan,
)

const style_response_status_others = :red
const style_response_status = Dict{Int,Symbol}(
    200 => :normal,     # 200 OK
    401 => :magenta,    # 401 Unauthorized
    404 => :light_blue, # 404 Not Found
    500 => :red,        # 500 Internal Server Error
)

function req_method_style(method::String)
    (color=get(style_request_action, method, style_request_action_others),)
end

function resp_status_style(status::Int16)
    (color=get(style_response_status, status, style_response_status_others),)
end

function info_response(route::Route, req, response)
    logger = Base.global_logger()
    buf = IOBuffer()
    iocontext = IOContext(buf, logger.stream)
    iob = IOContext(iocontext, :color => true)
    printstyled(iob, "INFO:", color=:cyan)
    logger isa Plug.Logger && logger.formatter(iob)
    printstyled(iob, ' ')
    printstyled(iob, rpad(req.method, 6); req_method_style(req.method)...)
    printstyled(iob, ' ')
    controller_name = String(nameof(route.C))
    if endswith(controller_name, "Controller")
        printstyled(iob, controller_name[1:end-10])
        printstyled(iob, rpad("Controller", controller_rpad-(length(controller_name)-10)), color=248)
    else
        printstyled(iob, rpad(controller_name, controller_rpad))
    end
    printstyled(iob, rpad(nameof(route.action), action_rpad))
    printstyled(iob, response.status; resp_status_style(response.status)...)
    printstyled(iob, ' ', _unescape_req_target(req))
    println(iob)
    print(logger.stream, String(take!(buf)))
    flush(logger.stream)
end

"""
    Bukdu.System.catch_request(route::Bukdu.Route, req)
"""
function catch_request
end

"""
    Bukdu.System.catch_response(route::Bukdu.Route, resp)
"""
function catch_response
end

end # module Bukdu.System

function Bukdu.System.catch_request(route::Bukdu.Route, req)
#    @debug "REQ " req.headers
end

function Bukdu.System.catch_response(route::Bukdu.Route, resp)
#    @debug "RESP" resp.headers resp.status
end

max_stars_repo_name: wookay/TestBukdu

max_issues_repo_name: wookay/TestBukdu

max_forks_repo_name: wookay/TestBukdu