text:
# -*- encoding: utf-8 -*-

import Healpix
using Test

const eps = 1e-10

@test Healpix.ilog2(1) == 0
@test Healpix.ilog2(6) == 2
@test Healpix.ilog2(1023) == 9
@test Healpix.ilog2(1024) == 10
@test Healpix.ilog2(8194) == 13
@test Healpix.ilog2(131124) == 17

# nsideok, nside2pixarea, nside2resol, nside2npix, npix2nside

@test Healpix.nsideok(16)
@test Healpix.nsideok(1024)
@test !Healpix.nsideok(17)
@test !Healpix.nsideok(-4)

@test Healpix.nside2pixarea(128) ≈ 6.391586616190171e-5
@test Healpix.nside2resol(128) ≈ 0.007994739905831941
@test_throws DomainError(-1, "`NSIDE` is not a positive number") Healpix.nside2pixarea(-1)
@test_throws DomainError(-1, "`NSIDE` is not a positive number") Healpix.nside2resol(-1)
@test_throws DomainError(513, "`NSIDE` is not an integer power of two") Healpix.nside2pixarea(513)
@test_throws DomainError(513, "`NSIDE` is not an integer power of two") Healpix.nside2resol(513)

@test Healpix.nside2npix(4) == 192
@test Healpix.npix2nside(192) == 4
@test_throws DomainError(15, "`NSIDE` is not an integer power of two") Healpix.nside2npix(15)
@test_throws DomainError(7, "Invalid number of pixels") Healpix.npix2nside(7)
@test_throws DomainError(12 * 8 * 9, "Invalid number of pixels") Healpix.npix2nside(12 * 8 * 9)

# ang2vec

x, y, z = Healpix.ang2vec(2.556481306546430, 1.573953117024192)
@test x ≈ -0.001743467757429 atol = eps
@test y ≈ 0.552289458399410 atol = eps
@test z ≈ -0.833650594950345 atol = eps

x, y, z = Healpix.ang2vec(0.140282766372135, 0.233893209450599)
@test x ≈ 0.136015928900898 atol = eps
@test y ≈ 0.032406308842171 atol = eps
@test z ≈ 0.990176498525617 atol = eps

x, y, z = Healpix.ang2vec(0.441131335644146, 3.464317397342697)
@test x ≈ -0.404920724073465 atol = eps
@test y ≈ -0.135412016604473 atol = eps
@test z ≈ 0.904269203818714 atol = eps

x, y, z = Healpix.ang2vec(2.339362129743034, 2.415312683457592)
@test x ≈ -0.537491821098482 atol = eps
@test y ≈ 0.477421955393414 atol = eps
@test z ≈ -0.695104897666939 atol = eps

x, y, z = Healpix.ang2vec(2.012884650691451, 0.429579124174392)
@test x ≈ 0.821736466784090 atol = eps
@test y ≈ 0.376447107630774 atol = eps
@test z ≈ -0.427827949430170 atol = eps

x, y, z = Healpix.ang2vec(0.698567538240779, 2.951569899700352)
@test x ≈ -0.631545193788522 atol = eps
@test y ≈ 0.121473570759142 atol = eps
@test z ≈ 0.765764219462911 atol = eps

x, y, z = Healpix.ang2vec(0.602746245881256, 2.363106505915441)
@test x ≈ -0.403624903017147 atol = eps
@test y ≈ 0.398083394409416 atol = eps
@test z ≈ 0.823781857508331 atol = eps

x, y, z = Healpix.ang2vec(3.106081268871312, 4.592838732778776)
@test x ≈ -0.004234399242699 atol = eps
@test y ≈ -0.035250507901764 atol = eps
@test z ≈ -0.999369537036086 atol = eps

x, y, z = Healpix.ang2vec(1.906789620733219, 4.322731382956660)
@test x ≈ -0.358630521788042 atol = eps
@test y ≈ -0.873314025552965 atol = eps
@test z ≈ -0.329707084568277 atol = eps

x, y, z = Healpix.ang2vec(0.637907993514304, 4.877925523463614)
@test x ≈ 0.098130081527976 atol = eps
@test y ≈ -0.587375491097860 atol = eps
@test z ≈ 0.803343338527719 atol = eps

# vec2ang

theta, phi = Healpix.vec2ang(2.479973695958578, 2.540405094768749, 1.360043653263107)
@test theta ≈ 1.204952691410965 atol = eps
@test phi ≈ 0.797434801040588 atol = eps

theta, phi = Healpix.vec2ang(1.095479074939707, 0.898675220740957, 0.147081790022168)
@test theta ≈ 1.467363643308421 atol = eps
@test phi ≈ 0.687026327338059 atol = eps

theta, phi = Healpix.vec2ang(0.576316747680224, 0.592397935683216, 0.829922061194829)
@test theta ≈ 0.783322736466122 atol = eps
@test phi ≈ 0.799157016147229 atol = eps

theta, phi = Healpix.vec2ang(2.502045018710797, 1.228308248258689, 0.292075568023260)
@test theta ≈ 1.466388897914957 atol = eps
@test phi ≈ 0.456358646456269 atol = eps

theta, phi = Healpix.vec2ang(0.784144561032690, 2.203400212521606, 2.645182960828146)
@test theta ≈ 0.723995999159878 atol = eps
@test phi ≈ 1.228893440982002 atol = eps

theta, phi = Healpix.vec2ang(2.313385295284291, 2.310829312494675, 0.909839585819006)
@test theta ≈ 1.299407206361556 atol = eps
@test phi ≈ 0.784845424663175 atol = eps

theta, phi = Healpix.vec2ang(2.028549527136607, 2.806016077249088, 0.732470589106458)
@test theta ≈ 1.362324539502480 atol = eps
@test phi ≈ 0.944847150958497 atol = eps

theta, phi = Healpix.vec2ang(2.806692561465244, 1.750787884540839, 1.617079425838591)
@test theta ≈ 1.116115824440890 atol = eps
@test phi ≈ 0.557729020009978 atol = eps

theta, phi = Healpix.vec2ang(1.973555660995911, 1.086043406239103, 2.959437359715485)
@test theta ≈ 0.650613947401187 atol = eps
@test phi ≈ 0.503071845787347 atol = eps

theta, phi = Healpix.vec2ang(2.922856075911509, 2.304551510739625, 0.874687489108078)
@test theta ≈ 1.339986032596264 atol = eps
@test phi ≈ 0.667663882320130 atol = eps

# ang2pixNest

@test_throws DomainError(0) Healpix.Resolution(0)
@test_throws DomainError(100000000) Healpix.Resolution(100000000)
lowresol = Healpix.Resolution(2)
resol = Healpix.Resolution(256)

@test Healpix.ang2pixNest(resol, 0.0000000000000000, 0.0000000000000000) ==  65536
@test Healpix.ang2pixNest(resol, 0.0000000000000000, 1.2566370614359172) ==  65536
@test Healpix.ang2pixNest(resol, 0.0000000000000000, 2.5132741228718345) == 131072
@test Healpix.ang2pixNest(resol, 0.0000000000000000, 3.7699111843077517) == 196608
@test Healpix.ang2pixNest(resol, 0.0000000000000000, 5.0265482457436690) == 262144
@test Healpix.ang2pixNest(resol, 0.0000000000000000, 6.2831853071795862) == 262144

@test Healpix.ang2pixNest(resol, 0.6283185307179586, 0.0000000000000000) ==  45055
@test Healpix.ang2pixNest(resol, 0.6283185307179586, 1.2566370614359172) ==  31074
@test Healpix.ang2pixNest(resol, 0.6283185307179586, 2.5132741228718345) == 116111
@test Healpix.ang2pixNest(resol, 0.6283185307179586, 3.7699111843077517) == 182862
@test Healpix.ang2pixNest(resol, 0.6283185307179586, 5.0265482457436690) == 243347
@test Healpix.ang2pixNest(resol, 0.6283185307179586, 6.2831853071795862) == 221182

@test Healpix.ang2pixNest(resol, 1.2566370614359172, 0.0000000000000000) == 315344
@test Healpix.ang2pixNest(resol, 1.2566370614359172, 1.2566370614359172) == 387305
@test Healpix.ang2pixNest(resol, 1.2566370614359172, 2.5132741228718345) ==  71955
@test Healpix.ang2pixNest(resol, 1.2566370614359172, 3.7699111843077517) == 140834
@test Healpix.ang2pixNest(resol, 1.2566370614359172, 5.0265482457436690) == 513237
@test Healpix.ang2pixNest(resol, 1.2566370614359172, 6.2831853071795862) == 315344

@test Healpix.ang2pixNest(resol, 1.8849555921538759, 0.0000000000000000) == 274481
@test Healpix.ang2pixNest(resol, 1.8849555921538759, 1.2566370614359172) == 338732
@test Healpix.ang2pixNest(resol, 1.8849555921538759, 2.5132741228718345) == 645599
@test Healpix.ang2pixNest(resol, 1.8849555921538759, 3.7699111843077517) == 714478
@test Healpix.ang2pixNest(resol, 1.8849555921538759, 5.0265482457436690) == 464664
@test Healpix.ang2pixNest(resol, 1.8849555921538759, 6.2831853071795862) == 274481

@test Healpix.ang2pixNest(resol, 2.5132741228718345, 0.0000000000000000) == 565251
@test Healpix.ang2pixNest(resol, 2.5132741228718345, 1.2566370614359172) == 543086
@test Healpix.ang2pixNest(resol, 2.5132741228718345, 2.5132741228718345) == 603571
@test Healpix.ang2pixNest(resol, 2.5132741228718345, 3.7699111843077517) == 670322
@test Healpix.ang2pixNest(resol, 2.5132741228718345, 5.0265482457436690) == 755359
@test Healpix.ang2pixNest(resol, 2.5132741228718345, 6.2831853071795862) == 741378

@test Healpix.ang2pixNest(resol, 3.1415926535897931, 0.0000000000000000) == 524289
@test Healpix.ang2pixNest(resol, 3.1415926535897931, 1.2566370614359172) == 524289
@test Healpix.ang2pixNest(resol, 3.1415926535897931, 2.5132741228718345) == 589825
@test Healpix.ang2pixNest(resol, 3.1415926535897931, 3.7699111843077517) == 655361
@test Healpix.ang2pixNest(resol, 3.1415926535897931, 5.0265482457436690) == 720897
@test Healpix.ang2pixNest(resol, 3.1415926535897931, 6.2831853071795862) == 720897

# ang2pixRing

@test Healpix.ang2pixRing(resol, 0.0000000000000000, 0.0000000000000000) ==      1
@test Healpix.ang2pixRing(resol, 0.0000000000000000, 1.2566370614359172) ==      1
@test Healpix.ang2pixRing(resol, 0.0000000000000000, 2.5132741228718345) ==      2
@test Healpix.ang2pixRing(resol, 0.0000000000000000, 3.7699111843077517) ==      3
@test Healpix.ang2pixRing(resol, 0.0000000000000000, 5.0265482457436690) ==      4
@test Healpix.ang2pixRing(resol, 0.0000000000000000, 6.2831853071795862) ==      1
@test Healpix.ang2pixRing(resol, 0.6283185307179586, 0.0000000000000000) ==  74885
@test Healpix.ang2pixRing(resol, 0.6283185307179586, 1.2566370614359172) ==  75040
@test Healpix.ang2pixRing(resol, 0.6283185307179586, 2.5132741228718345) ==  75195
@test Healpix.ang2pixRing(resol, 0.6283185307179586, 3.7699111843077517) ==  75350
@test Healpix.ang2pixRing(resol, 0.6283185307179586, 5.0265482457436690) ==  75505
@test Healpix.ang2pixRing(resol, 0.6283185307179586, 6.2831853071795862) ==  74885
@test Healpix.ang2pixRing(resol, 1.2566370614359172, 0.0000000000000000) == 270849
@test Healpix.ang2pixRing(resol, 1.2566370614359172, 1.2566370614359172) == 271054
@test Healpix.ang2pixRing(resol, 1.2566370614359172, 2.5132741228718345) == 272282
@test Healpix.ang2pixRing(resol, 1.2566370614359172, 3.7699111843077517) == 272487
@test Healpix.ang2pixRing(resol, 1.2566370614359172, 5.0265482457436690) == 271668
@test Healpix.ang2pixRing(resol, 1.2566370614359172, 6.2831853071795862) == 270849
@test Healpix.ang2pixRing(resol, 1.8849555921538759, 0.0000000000000000) == 514561
@test Healpix.ang2pixRing(resol, 1.8849555921538759, 1.2566370614359172) == 514766
@test Healpix.ang2pixRing(resol, 1.8849555921538759, 2.5132741228718345) == 513946
@test Healpix.ang2pixRing(resol, 1.8849555921538759, 3.7699111843077517) == 514151
@test Healpix.ang2pixRing(resol, 1.8849555921538759, 5.0265482457436690) == 515380
@test Healpix.ang2pixRing(resol, 1.8849555921538759, 6.2831853071795862) == 514561
@test Healpix.ang2pixRing(resol, 2.5132741228718345, 0.0000000000000000) == 710773
@test Healpix.ang2pixRing(resol, 2.5132741228718345, 1.2566370614359172) == 710928
@test Healpix.ang2pixRing(resol, 2.5132741228718345, 2.5132741228718345) == 711083
@test Healpix.ang2pixRing(resol, 2.5132741228718345, 3.7699111843077517) == 711238
@test Healpix.ang2pixRing(resol, 2.5132741228718345, 5.0265482457436690) == 711393
@test Healpix.ang2pixRing(resol, 2.5132741228718345, 6.2831853071795862) == 710773
@test Healpix.ang2pixRing(resol, 3.1415926535897931, 0.0000000000000000) == 786429
@test Healpix.ang2pixRing(resol, 3.1415926535897931, 1.2566370614359172) == 786429
@test Healpix.ang2pixRing(resol, 3.1415926535897931, 2.5132741228718345) == 786430
@test Healpix.ang2pixRing(resol, 3.1415926535897931, 3.7699111843077517) == 786431
@test Healpix.ang2pixRing(resol, 3.1415926535897931, 5.0265482457436690) == 786432
@test Healpix.ang2pixRing(resol, 3.1415926535897931, 6.2831853071795862) == 786429

# pix2angNest

@test Healpix.pix2angNest(lowresol,  1)[1] ≈ 1.230959417340775 atol = eps
@test Healpix.pix2angNest(lowresol,  1)[2] ≈ 0.785398163397448 atol = eps
@test Healpix.pix2angNest(lowresol,  2)[1] ≈ 0.841068670567930 atol = eps
@test Healpix.pix2angNest(lowresol,  2)[2] ≈ 1.178097245096172 atol = eps
@test Healpix.pix2angNest(lowresol,  3)[1] ≈ 0.841068670567930 atol = eps
@test Healpix.pix2angNest(lowresol,  3)[2] ≈ 0.392699081698724 atol = eps
@test Healpix.pix2angNest(lowresol,  4)[1] ≈ 0.411137862322348 atol = eps
@test Healpix.pix2angNest(lowresol,  4)[2] ≈ 0.785398163397448 atol = eps
@test Healpix.pix2angNest(lowresol,  5)[1] ≈ 1.230959417340775 atol = eps
@test Healpix.pix2angNest(lowresol,  5)[2] ≈ 2.356194490192345 atol = eps
@test Healpix.pix2angNest(lowresol,  6)[1] ≈ 0.841068670567930 atol = eps
@test Healpix.pix2angNest(lowresol,  6)[2] ≈ 2.748893571891069 atol = eps
@test Healpix.pix2angNest(lowresol,  7)[1] ≈ 0.841068670567930 atol = eps
@test Healpix.pix2angNest(lowresol,  7)[2] ≈ 1.963495408493621 atol = eps
@test Healpix.pix2angNest(lowresol,  8)[1] ≈ 0.411137862322348 atol = eps
@test Healpix.pix2angNest(lowresol,  8)[2] ≈ 2.356194490192345 atol = eps
@test Healpix.pix2angNest(lowresol,  9)[1] ≈ 1.230959417340775 atol = eps
@test Healpix.pix2angNest(lowresol,  9)[2] ≈ 3.926990816987241 atol = eps
@test Healpix.pix2angNest(lowresol, 10)[1] ≈ 0.841068670567930 atol = eps
@test Healpix.pix2angNest(lowresol, 10)[2] ≈ 4.319689898685965 atol = eps
@test Healpix.pix2angNest(lowresol, 11)[1] ≈ 0.841068670567930 atol = eps
@test Healpix.pix2angNest(lowresol, 11)[2] ≈ 3.534291735288517 atol = eps
@test Healpix.pix2angNest(lowresol, 12)[1] ≈ 0.411137862322348 atol = eps
@test Healpix.pix2angNest(lowresol, 12)[2] ≈ 3.926990816987241 atol = eps
@test Healpix.pix2angNest(lowresol, 13)[1] ≈ 1.230959417340775 atol = eps
@test Healpix.pix2angNest(lowresol, 13)[2] ≈ 5.497787143782138 atol = eps
@test Healpix.pix2angNest(lowresol, 14)[1] ≈ 0.841068670567930 atol = eps
@test Healpix.pix2angNest(lowresol, 14)[2] ≈ 5.890486225480862 atol = eps
@test Healpix.pix2angNest(lowresol, 15)[1] ≈ 0.841068670567930 atol = eps
@test Healpix.pix2angNest(lowresol, 15)[2] ≈ 5.105088062083414 atol = eps
@test Healpix.pix2angNest(lowresol, 16)[1] ≈ 0.411137862322348 atol = eps
@test Healpix.pix2angNest(lowresol, 16)[2] ≈ 5.497787143782138 atol = eps
@test Healpix.pix2angNest(lowresol, 17)[1] ≈ 1.910633236249019 atol = eps
@test Healpix.pix2angNest(lowresol, 17)[2] ≈ 0.000000000000000 atol = eps
@test Healpix.pix2angNest(lowresol, 18)[1] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angNest(lowresol, 18)[2] ≈ 0.392699081698724 atol = eps
@test Healpix.pix2angNest(lowresol, 19)[1] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angNest(lowresol, 19)[2] ≈ 5.890486225480862 atol = eps
@test Healpix.pix2angNest(lowresol, 20)[1] ≈ 1.230959417340775 atol = eps
@test Healpix.pix2angNest(lowresol, 20)[2] ≈ 0.000000000000000 atol = eps
@test Healpix.pix2angNest(lowresol, 21)[1] ≈ 1.910633236249019 atol = eps
@test Healpix.pix2angNest(lowresol, 21)[2] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angNest(lowresol, 22)[1] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angNest(lowresol, 22)[2] ≈ 1.963495408493621 atol = eps
@test Healpix.pix2angNest(lowresol, 23)[1] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angNest(lowresol, 23)[2] ≈ 1.178097245096172 atol = eps
@test Healpix.pix2angNest(lowresol, 24)[1] ≈ 1.230959417340775 atol = eps
@test Healpix.pix2angNest(lowresol, 24)[2] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angNest(lowresol, 25)[1] ≈ 1.910633236249019 atol = eps
@test Healpix.pix2angNest(lowresol, 25)[2] ≈ 3.141592653589793 atol = eps
@test Healpix.pix2angNest(lowresol, 26)[1] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angNest(lowresol, 26)[2] ≈ 3.534291735288517 atol = eps
@test Healpix.pix2angNest(lowresol, 27)[1] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angNest(lowresol, 27)[2] ≈ 2.748893571891069 atol = eps
@test Healpix.pix2angNest(lowresol, 28)[1] ≈ 1.230959417340775 atol = eps
@test Healpix.pix2angNest(lowresol, 28)[2] ≈ 3.141592653589793 atol = eps
@test Healpix.pix2angNest(lowresol, 29)[1] ≈ 1.910633236249019 atol = eps
@test Healpix.pix2angNest(lowresol, 29)[2] ≈ 4.712388980384690 atol = eps
@test Healpix.pix2angNest(lowresol, 30)[1] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angNest(lowresol, 30)[2] ≈ 5.105088062083414 atol = eps
@test Healpix.pix2angNest(lowresol, 31)[1] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angNest(lowresol, 31)[2] ≈ 4.319689898685965 atol = eps
@test Healpix.pix2angNest(lowresol, 32)[1] ≈ 1.230959417340775 atol = eps
@test Healpix.pix2angNest(lowresol, 32)[2] ≈ 4.712388980384690 atol = eps
@test Healpix.pix2angNest(lowresol, 33)[1] ≈ 2.730454791267445 atol = eps
@test Healpix.pix2angNest(lowresol, 33)[2] ≈ 0.785398163397448 atol = eps
@test Healpix.pix2angNest(lowresol, 34)[1] ≈ 2.300523983021863 atol = eps
@test Healpix.pix2angNest(lowresol, 34)[2] ≈ 1.178097245096172 atol = eps
@test Healpix.pix2angNest(lowresol, 35)[1] ≈ 2.300523983021863 atol = eps
@test Healpix.pix2angNest(lowresol, 35)[2] ≈ 0.392699081698724 atol = eps
@test Healpix.pix2angNest(lowresol, 36)[1] ≈ 1.910633236249019 atol = eps
@test Healpix.pix2angNest(lowresol, 36)[2] ≈ 0.785398163397448 atol = eps
@test Healpix.pix2angNest(lowresol, 37)[1] ≈ 2.730454791267445 atol = eps
@test Healpix.pix2angNest(lowresol, 37)[2] ≈ 2.356194490192345 atol = eps
@test Healpix.pix2angNest(lowresol, 38)[1] ≈ 2.300523983021863 atol = eps
@test Healpix.pix2angNest(lowresol, 38)[2] ≈ 2.748893571891069 atol = eps
@test Healpix.pix2angNest(lowresol, 39)[1] ≈ 2.300523983021863 atol = eps
@test Healpix.pix2angNest(lowresol, 39)[2] ≈ 1.963495408493621 atol = eps
@test Healpix.pix2angNest(lowresol, 40)[1] ≈ 1.910633236249019 atol = eps
@test Healpix.pix2angNest(lowresol, 40)[2] ≈ 2.356194490192345 atol = eps
@test Healpix.pix2angNest(lowresol, 41)[1] ≈ 2.730454791267445 atol = eps
@test Healpix.pix2angNest(lowresol, 41)[2] ≈ 3.926990816987241 atol = eps
@test Healpix.pix2angNest(lowresol, 42)[1] ≈ 2.300523983021863 atol = eps
@test Healpix.pix2angNest(lowresol, 42)[2] ≈ 4.319689898685965 atol = eps
@test Healpix.pix2angNest(lowresol, 43)[1] ≈ 2.300523983021863 atol = eps
@test Healpix.pix2angNest(lowresol, 43)[2] ≈ 3.534291735288517 atol = eps
@test Healpix.pix2angNest(lowresol, 44)[1] ≈ 1.910633236249019 atol = eps
@test Healpix.pix2angNest(lowresol, 44)[2] ≈ 3.926990816987241 atol = eps
@test Healpix.pix2angNest(lowresol, 45)[1] ≈ 2.730454791267445 atol = eps
@test Healpix.pix2angNest(lowresol, 45)[2] ≈ 5.497787143782138 atol = eps
@test Healpix.pix2angNest(lowresol, 46)[1] ≈ 2.300523983021863 atol = eps
@test Healpix.pix2angNest(lowresol, 46)[2] ≈ 5.890486225480862 atol = eps
@test Healpix.pix2angNest(lowresol, 47)[1] ≈ 2.300523983021863 atol = eps
@test Healpix.pix2angNest(lowresol, 47)[2] ≈ 5.105088062083414 atol = eps

@test Healpix.pix2angNest(resol,      1)[1] ≈ 1.5681921571847817 atol = eps
@test Healpix.pix2angNest(resol,      1)[2] ≈ 0.7853981633974483 atol = eps
@test Healpix.pix2angNest(resol,      2)[1] ≈ 1.5655879699137618 atol = eps
@test Healpix.pix2angNest(resol,      2)[2] ≈ 0.7884661249732196 atol = eps
@test Healpix.pix2angNest(resol,      3)[1] ≈ 1.5655879699137618 atol = eps
@test Healpix.pix2angNest(resol,      3)[2] ≈ 0.7823302018216770 atol = eps
@test Healpix.pix2angNest(resol,      4)[1] ≈ 1.5629837473198540 atol = eps
@test Healpix.pix2angNest(resol,      4)[2] ≈ 0.7853981633974483 atol = eps
@test Healpix.pix2angNest(resol,  74885)[1] ≈ 1.2884125182769750 atol = eps
@test Healpix.pix2angNest(resol,  74885)[2] ≈ 2.2396119503130363 atol = eps
@test Healpix.pix2angNest(resol,  75040)[1] ≈ 1.2447369771100412 atol = eps
@test Healpix.pix2angNest(resol,  75040)[2] ≈ 2.3193789512830896 atol = eps
@test Healpix.pix2angNest(resol,  75195)[1] ≈ 1.2198889832038156 atol = eps
@test Healpix.pix2angNest(resol,  75195)[2] ≈ 2.2733595276465204 atol = eps
@test Healpix.pix2angNest(resol,  75350)[1] ≈ 1.2309594173407747 atol = eps
@test Healpix.pix2angNest(resol,  75350)[2] ≈ 2.2549517581918925 atol = eps
@test Healpix.pix2angNest(resol,  75505)[1] ≈ 1.2059873663963379 atol = eps
@test Healpix.pix2angNest(resol,  75505)[2] ≈ 2.2089323345553233 atol = eps
@test Healpix.pix2angNest(resol, 270849)[1] ≈ 2.0439875486296080 atol = eps
@test Healpix.pix2angNest(resol, 270849)[2] ≈ 6.0377483811178836 atol = eps
@test Healpix.pix2angNest(resol, 271054)[1] ≈ 1.9834500066417189 atol = eps
@test Healpix.pix2angNest(resol, 271054)[2] ≈ 6.0408163426936552 atol = eps
@test Healpix.pix2angNest(resol, 272282)[1] ≈ 1.8667651301538279 atol = eps
@test Healpix.pix2angNest(resol, 272282)[2] ≈ 6.1696707288760484 atol = eps
@test Healpix.pix2angNest(resol, 272487)[1] ≈ 1.9551931012905357 atol = eps
@test Healpix.pix2angNest(resol, 272487)[2] ≈ 6.0040008037843995 atol = eps
@test Healpix.pix2angNest(resol, 271668)[1] ≈ 1.9244782426347979 atol = eps
@test Healpix.pix2angNest(resol, 271668)[2] ≈ 6.2340979219672459 atol = eps
@test Healpix.pix2angNest(resol, 514561)[1] ≈ 1.2721038462777619 atol = eps
@test Healpix.pix2angNest(resol, 514561)[2] ≈ 4.7614763655970300 atol = eps
@test Healpix.pix2angNest(resol, 514766)[1] ≈ 1.2143369935354960 atol = eps
@test Healpix.pix2angNest(resol, 514766)[2] ≈ 4.7645443271728016 atol = eps
@test Healpix.pix2angNest(resol, 513946)[1] ≈ 1.1863995522992576 atol = eps
@test Healpix.pix2angNest(resol, 513946)[2] ≈ 4.9915734837798764 atol = eps
@test Healpix.pix2angNest(resol, 514151)[1] ≈ 1.2748275234359654 atol = eps
@test Healpix.pix2angNest(resol, 514151)[2] ≈ 4.8259035586882275 atol = eps
@test Healpix.pix2angNest(resol, 515380)[1] ≈ 1.1552980808319346 atol = eps
@test Healpix.pix2angNest(resol, 515380)[2] ≈ 4.9578259064463923 atol = eps
@test Healpix.pix2angNest(resol, 710773)[1] ≈ 1.9467798202990929 atol = eps
@test Healpix.pix2angNest(resol, 710773)[2] ≈ 4.0558452031696355 atol = eps
@test Healpix.pix2angNest(resol, 710928)[1] ≈ 1.9356052871934553 atol = eps
@test Healpix.pix2angNest(resol, 710928)[2] ≈ 4.0742529726242633 atol = eps
@test Healpix.pix2angNest(resol, 711083)[1] ≈ 1.9106332362490186 atol = eps
@test Healpix.pix2angNest(resol, 711083)[2] ≈ 4.0282335489876937 atol = eps
@test Healpix.pix2angNest(resol, 711238)[1] ≈ 1.9217036703859778 atol = eps
@test Healpix.pix2angNest(resol, 711238)[2] ≈ 4.0098257795330658 atol = eps
@test Healpix.pix2angNest(resol, 711393)[1] ≈ 1.8968556764797520 atol = eps
@test Healpix.pix2angNest(resol, 711393)[2] ≈ 3.9638063558964967 atol = eps
@test Healpix.pix2angNest(resol, 710773)[1] ≈ 1.9467798202990929 atol = eps
@test Healpix.pix2angNest(resol, 710773)[2] ≈ 4.0558452031696355 atol = eps
@test Healpix.pix2angNest(resol, 786429)[1] ≈ 1.5786089062699391 atol = eps
@test Healpix.pix2angNest(resol, 786429)[2] ≈ 5.4977871437821380 atol = eps
@test Healpix.pix2angNest(resol, 786429)[1] ≈ 1.5786089062699391 atol = eps
@test Healpix.pix2angNest(resol, 786429)[2] ≈ 5.4977871437821380 atol = eps
@test Healpix.pix2angNest(resol, 786430)[1] ≈ 1.5760046836760313 atol = eps
@test Healpix.pix2angNest(resol, 786430)[2] ≈ 5.5008551053579096 atol = eps
@test Healpix.pix2angNest(resol, 786431)[1] ≈ 1.5760046836760313 atol = eps
@test Healpix.pix2angNest(resol, 786431)[2] ≈ 5.4947191822063663 atol = eps
@test Healpix.pix2angNest(resol, 786432)[1] ≈ 1.5734004964050115 atol = eps
@test Healpix.pix2angNest(resol, 786432)[2] ≈ 5.4977871437821380 atol = eps

# pix2angRing

@test Healpix.pix2angRing(lowresol,  1)[1] ≈ 0.411137862322348 atol = eps
@test Healpix.pix2angRing(lowresol,  1)[2] ≈ 0.785398163397448 atol = eps
@test Healpix.pix2angRing(lowresol,  2)[1] ≈ 0.411137862322348 atol = eps
@test Healpix.pix2angRing(lowresol,  2)[2] ≈ 2.356194490192345 atol = eps
@test Healpix.pix2angRing(lowresol,  3)[1] ≈ 0.411137862322348 atol = eps
@test Healpix.pix2angRing(lowresol,  3)[2] ≈ 3.926990816987241 atol = eps
@test Healpix.pix2angRing(lowresol,  4)[1] ≈ 0.411137862322348 atol = eps
@test Healpix.pix2angRing(lowresol,  4)[2] ≈ 5.497787143782138 atol = eps
@test Healpix.pix2angRing(lowresol,  5)[1] ≈ 0.841068670567930 atol = eps
@test Healpix.pix2angRing(lowresol,  5)[2] ≈ 0.392699081698724 atol = eps
@test Healpix.pix2angRing(lowresol,  6)[1] ≈ 0.841068670567930 atol = eps
@test Healpix.pix2angRing(lowresol,  6)[2] ≈ 1.178097245096172 atol = eps
@test Healpix.pix2angRing(lowresol,  7)[1] ≈ 0.841068670567930 atol = eps
@test Healpix.pix2angRing(lowresol,  7)[2] ≈ 1.963495408493621 atol = eps
@test Healpix.pix2angRing(lowresol,  8)[1] ≈ 0.841068670567930 atol = eps
@test Healpix.pix2angRing(lowresol,  8)[2] ≈ 2.748893571891069 atol = eps
@test Healpix.pix2angRing(lowresol,  9)[1] ≈ 0.841068670567930 atol = eps
@test Healpix.pix2angRing(lowresol,  9)[2] ≈ 3.534291735288517 atol = eps
@test Healpix.pix2angRing(lowresol, 10)[1] ≈ 0.841068670567930 atol = eps
@test Healpix.pix2angRing(lowresol, 10)[2] ≈ 4.319689898685965 atol = eps
@test Healpix.pix2angRing(lowresol, 11)[1] ≈ 0.841068670567930 atol = eps
@test Healpix.pix2angRing(lowresol, 11)[2] ≈ 5.105088062083414 atol = eps
@test Healpix.pix2angRing(lowresol, 12)[1] ≈ 0.841068670567930 atol = eps
@test Healpix.pix2angRing(lowresol, 12)[2] ≈ 5.890486225480862 atol = eps
@test Healpix.pix2angRing(lowresol, 13)[1] ≈ 1.230959417340775 atol = eps
@test Healpix.pix2angRing(lowresol, 13)[2] ≈ 0.000000000000000 atol = eps
@test Healpix.pix2angRing(lowresol, 14)[1] ≈ 1.230959417340775 atol = eps
@test Healpix.pix2angRing(lowresol, 14)[2] ≈ 0.785398163397448 atol = eps
@test Healpix.pix2angRing(lowresol, 15)[1] ≈ 1.230959417340775 atol = eps
@test Healpix.pix2angRing(lowresol, 15)[2] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angRing(lowresol, 16)[1] ≈ 1.230959417340775 atol = eps
@test Healpix.pix2angRing(lowresol, 16)[2] ≈ 2.356194490192345 atol = eps
@test Healpix.pix2angRing(lowresol, 17)[1] ≈ 1.230959417340775 atol = eps
@test Healpix.pix2angRing(lowresol, 17)[2] ≈ 3.141592653589793 atol = eps
@test Healpix.pix2angRing(lowresol, 18)[1] ≈ 1.230959417340775 atol = eps
@test Healpix.pix2angRing(lowresol, 18)[2] ≈ 3.926990816987241 atol = eps
@test Healpix.pix2angRing(lowresol, 19)[1] ≈ 1.230959417340775 atol = eps
@test Healpix.pix2angRing(lowresol, 19)[2] ≈ 4.712388980384690 atol = eps
@test Healpix.pix2angRing(lowresol, 20)[1] ≈ 1.230959417340775 atol = eps
@test Healpix.pix2angRing(lowresol, 20)[2] ≈ 5.497787143782138 atol = eps
@test Healpix.pix2angRing(lowresol, 21)[1] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angRing(lowresol, 21)[2] ≈ 0.392699081698724 atol = eps
@test Healpix.pix2angRing(lowresol, 22)[1] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angRing(lowresol, 22)[2] ≈ 1.178097245096172 atol = eps
@test Healpix.pix2angRing(lowresol, 23)[1] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angRing(lowresol, 23)[2] ≈ 1.963495408493621 atol = eps
@test Healpix.pix2angRing(lowresol, 24)[1] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angRing(lowresol, 24)[2] ≈ 2.748893571891069 atol = eps
@test Healpix.pix2angRing(lowresol, 25)[1] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angRing(lowresol, 25)[2] ≈ 3.534291735288517 atol = eps
@test Healpix.pix2angRing(lowresol, 26)[1] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angRing(lowresol, 26)[2] ≈ 4.319689898685965 atol = eps
@test Healpix.pix2angRing(lowresol, 27)[1] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angRing(lowresol, 27)[2] ≈ 5.105088062083414 atol = eps
@test Healpix.pix2angRing(lowresol, 28)[1] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angRing(lowresol, 28)[2] ≈ 5.890486225480862 atol = eps
@test Healpix.pix2angRing(lowresol, 29)[1] ≈ 1.910633236249019 atol = eps
@test Healpix.pix2angRing(lowresol, 29)[2] ≈ 0.000000000000000 atol = eps
@test Healpix.pix2angRing(lowresol, 30)[1] ≈ 1.910633236249019 atol = eps
@test Healpix.pix2angRing(lowresol, 30)[2] ≈ 0.785398163397448 atol = eps
@test Healpix.pix2angRing(lowresol, 31)[1] ≈ 1.910633236249019 atol = eps
@test Healpix.pix2angRing(lowresol, 31)[2] ≈ 1.570796326794897 atol = eps
@test Healpix.pix2angRing(lowresol, 32)[1] ≈ 1.910633236249019 atol = eps
@test Healpix.pix2angRing(lowresol, 32)[2] ≈ 2.356194490192345 atol = eps
@test Healpix.pix2angRing(lowresol, 33)[1] ≈ 1.910633236249019 atol = eps
@test Healpix.pix2angRing(lowresol, 33)[2] ≈ 3.141592653589793 atol = eps
@test Healpix.pix2angRing(lowresol, 34)[1] ≈ 1.910633236249019 atol = eps
@test Healpix.pix2angRing(lowresol, 34)[2] ≈ 3.926990816987241 atol = eps
@test Healpix.pix2angRing(lowresol, 35)[1] ≈ 1.910633236249019 atol = eps
@test Healpix.pix2angRing(lowresol, 35)[2] ≈ 4.712388980384690 atol = eps
@test Healpix.pix2angRing(lowresol, 36)[1] ≈ 1.910633236249019 atol = eps
@test Healpix.pix2angRing(lowresol, 36)[2] ≈ 5.497787143782138 atol = eps
@test Healpix.pix2angRing(lowresol, 37)[1] ≈ 2.300523983021863 atol = eps
@test Healpix.pix2angRing(lowresol, 37)[2] ≈ 0.392699081698724 atol = eps
@test Healpix.pix2angRing(lowresol, 38)[1] ≈ 2.300523983021863 atol = eps
@test Healpix.pix2angRing(lowresol, 38)[2] ≈ 1.178097245096172 atol = eps
@test Healpix.pix2angRing(lowresol, 39)[1] ≈ 2.300523983021863 atol = eps
@test Healpix.pix2angRing(lowresol, 39)[2] ≈ 1.963495408493621 atol = eps
@test Healpix.pix2angRing(lowresol, 40)[1] ≈ 2.300523983021863 atol = eps
@test Healpix.pix2angRing(lowresol, 40)[2] ≈ 2.748893571891069 atol = eps
@test Healpix.pix2angRing(lowresol, 41)[1] ≈ 2.300523983021863 atol = eps
@test Healpix.pix2angRing(lowresol, 41)[2] ≈ 3.534291735288517 atol = eps
@test Healpix.pix2angRing(lowresol, 42)[1] ≈ 2.300523983021863 atol = eps
@test Healpix.pix2angRing(lowresol, 42)[2] ≈ 4.319689898685965 atol = eps
@test Healpix.pix2angRing(lowresol, 43)[1] ≈ 2.300523983021863 atol = eps
@test Healpix.pix2angRing(lowresol, 43)[2] ≈ 5.105088062083414 atol = eps
@test Healpix.pix2angRing(lowresol, 44)[1] ≈ 2.300523983021863 atol = eps
@test Healpix.pix2angRing(lowresol, 44)[2] ≈ 5.890486225480862 atol = eps
@test Healpix.pix2angRing(lowresol, 45)[1] ≈ 2.730454791267445 atol = eps
@test Healpix.pix2angRing(lowresol, 45)[2] ≈ 0.785398163397448 atol = eps
@test Healpix.pix2angRing(lowresol, 46)[1] ≈ 2.730454791267445 atol = eps
@test Healpix.pix2angRing(lowresol, 46)[2] ≈ 2.356194490192345 atol = eps
@test Healpix.pix2angRing(lowresol, 47)[1] ≈ 2.730454791267445 atol = eps
@test Healpix.pix2angRing(lowresol, 47)[2] ≈ 3.926990816987241 atol = eps

@test Healpix.pix2angRing(resol,      1)[1] ≈ 0.0031894411211228 atol = eps
@test Healpix.pix2angRing(resol,      1)[2] ≈ 0.7853981633974483 atol = eps
@test Healpix.pix2angRing(resol,      2)[1] ≈ 0.0031894411211113 atol = eps
@test Healpix.pix2angRing(resol,      2)[2] ≈ 2.3561944901923448 atol = eps
@test Healpix.pix2angRing(resol,      3)[1] ≈ 0.0031894411211113 atol = eps
@test Healpix.pix2angRing(resol,      3)[2] ≈ 3.9269908169872414 atol = eps
@test Healpix.pix2angRing(resol,      4)[1] ≈ 0.0031894411211113 atol = eps
@test Healpix.pix2angRing(resol,      4)[2] ≈ 5.4977871437821380 atol = eps
@test Healpix.pix2angRing(resol,  74885)[1] ≈ 0.6290728186524177 atol = eps
@test Healpix.pix2angRing(resol,  74885)[2] ≈ 0.0040484441412240 atol = eps
@test Healpix.pix2angRing(resol,  75040)[1] ≈ 0.6290728186524177 atol = eps
@test Healpix.pix2angRing(resol,  75040)[2] ≈ 1.2590661279206516 atol = eps
@test Healpix.pix2angRing(resol,  75195)[1] ≈ 0.6290728186524177 atol = eps
@test Healpix.pix2angRing(resol,  75195)[2] ≈ 2.5140838117000794 atol = eps
@test Healpix.pix2angRing(resol,  75350)[1] ≈ 0.6290728186524177 atol = eps
@test Healpix.pix2angRing(resol,  75350)[2] ≈ 3.7691014954795072 atol = eps
@test Healpix.pix2angRing(resol,  75505)[1] ≈ 0.6290728186524177 atol = eps
@test Healpix.pix2angRing(resol,  75505)[2] ≈ 5.0241191792589346 atol = eps
@test Healpix.pix2angRing(resol, 270849)[1] ≈ 1.2557128565725952 atol = eps
@test Healpix.pix2angRing(resol, 270849)[2] ≈ 0.0000000000000000 atol = eps
@test Healpix.pix2angRing(resol, 271054)[1] ≈ 1.2557128565725952 atol = eps
@test Healpix.pix2angRing(resol, 271054)[2] ≈ 1.2578642460662257 atol = eps
@test Healpix.pix2angRing(resol, 272282)[1] ≈ 1.2584506449956214 atol = eps
@test Healpix.pix2angRing(resol, 272282)[2] ≈ 2.5126605305566803 atol = eps
@test Healpix.pix2angRing(resol, 272487)[1] ≈ 1.2584506449956214 atol = eps
@test Healpix.pix2angRing(resol, 272487)[2] ≈ 3.7705247766229060 atol = eps
@test Healpix.pix2angRing(resol, 271668)[1] ≈ 1.2557128565725952 atol = eps
@test Healpix.pix2angRing(resol, 271668)[2] ≈ 5.0253210611133605 atol = eps
@test Healpix.pix2angRing(resol, 514561)[1] ≈ 1.8858797970171981 atol = eps
@test Healpix.pix2angRing(resol, 514561)[2] ≈ 0.0000000000000000 atol = eps
@test Healpix.pix2angRing(resol, 514766)[1] ≈ 1.8858797970171981 atol = eps
@test Healpix.pix2angRing(resol, 514766)[2] ≈ 1.2578642460662257 atol = eps
@test Healpix.pix2angRing(resol, 513946)[1] ≈ 1.8831420085941717 atol = eps
@test Healpix.pix2angRing(resol, 513946)[2] ≈ 2.5126605305566803 atol = eps
@test Healpix.pix2angRing(resol, 514151)[1] ≈ 1.8831420085941717 atol = eps
@test Healpix.pix2angRing(resol, 514151)[2] ≈ 3.7705247766229060 atol = eps
@test Healpix.pix2angRing(resol, 515380)[1] ≈ 1.8858797970171981 atol = eps
@test Healpix.pix2angRing(resol, 515380)[2] ≈ 5.0253210611133605 atol = eps
@test Healpix.pix2angRing(resol, 710773)[1] ≈ 2.5125198349373754 atol = eps
@test Healpix.pix2angRing(resol, 710773)[2] ≈ 0.0040484441412240 atol = eps
@test Healpix.pix2angRing(resol, 710928)[1] ≈ 2.5125198349373754 atol = eps
@test Healpix.pix2angRing(resol, 710928)[2] ≈ 1.2590661279206516 atol = eps
@test Healpix.pix2angRing(resol, 711083)[1] ≈ 2.5125198349373754 atol = eps
@test Healpix.pix2angRing(resol, 711083)[2] ≈ 2.5140838117000794 atol = eps
@test Healpix.pix2angRing(resol, 711238)[1] ≈ 2.5125198349373754 atol = eps
@test Healpix.pix2angRing(resol, 711238)[2] ≈ 3.7691014954795072 atol = eps
@test Healpix.pix2angRing(resol, 711393)[1] ≈ 2.5125198349373754 atol = eps
@test Healpix.pix2angRing(resol, 711393)[2] ≈ 5.0241191792589346 atol = eps
@test Healpix.pix2angRing(resol, 710773)[1] ≈ 2.5125198349373754 atol = eps
@test Healpix.pix2angRing(resol, 710773)[2] ≈ 0.0040484441412240 atol = eps
@test Healpix.pix2angRing(resol, 786429)[1] ≈ 3.1384032124686820 atol = eps
@test Healpix.pix2angRing(resol, 786429)[2] ≈ 0.7853981633974483 atol = eps
@test Healpix.pix2angRing(resol, 786429)[1] ≈ 3.1384032124686820 atol = eps
@test Healpix.pix2angRing(resol, 786429)[2] ≈ 0.7853981633974483 atol = eps
@test Healpix.pix2angRing(resol, 786430)[1] ≈ 3.1384032124686820 atol = eps
@test Healpix.pix2angRing(resol, 786430)[2] ≈ 2.3561944901923448 atol = eps
@test Healpix.pix2angRing(resol, 786431)[1] ≈ 3.1384032124686820 atol = eps
@test Healpix.pix2angRing(resol, 786431)[2] ≈ 3.9269908169872414 atol = eps
@test Healpix.pix2angRing(resol, 786432)[1] ≈ 3.1384032124686820 atol = eps
@test Healpix.pix2angRing(resol, 786432)[2] ≈ 5.4977871437821380 atol = eps

include("interp.jl")
include("xyf.jl")

# Iterator interface

m = Healpix.Map{Int8, Healpix.Ring}(1)
for i in 1:length(m)
    m[i] = i
end

for i in m
    @test m[i] == i
end

@test m[1:3] == [1, 2, 3]
@test m[end-2:end] == [10, 11, 12]

# Conformability

@test Healpix.conformables(Healpix.Map{Int16,Healpix.Ring}(4),
                           Healpix.Map{Float32,Healpix.Ring}(4))
# nside mismatch
@test !Healpix.conformables(Healpix.Map{Int16,Healpix.Ring}(8),
                            Healpix.Map{Int16,Healpix.Ring}(4))
# order mismatch
@test !Healpix.conformables(Healpix.Map{Float32,Healpix.Ring}(4),
                            Healpix.Map{Float32,Healpix.Nest}(4))

# Map making

pixidx = [1, 5, 3, 2, 2, 3, 3]
tod = [0.0, missing, 2.5, 1.5, 2.5, 3.5, missing]
(binmap, hitmap) = Healpix.tod2map(pixidx, tod, nside=1, ordering=Healpix.Ring)
@test binmap.pixels ≈ [0.0, 2.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
@test hitmap.pixels == [1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0]

pixidx1 = [1, 3, 2, 2, 3]
tod1 = [0.0, 2.5, 1.5, 2.5, 3.5]
(binmap1, hitmap1) = Healpix.tod2map(pixidx1, tod1, nside=1, ordering=Healpix.Ring)
@test binmap1.pixels ≈ [0.0, 2.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
@test hitmap1.pixels == [1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0]

binmap2 = Healpix.Map{Float64,Healpix.Ring}(1)
binmap2.pixels = [1.0, 0.0, 3.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
hitmap2 = Healpix.Map{Int,Healpix.Ring}(1)
hitmap2.pixels = [1, 6, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0]
Healpix.combinemaps!(binmap1, hitmap1, binmap2, hitmap2)
@test binmap1.pixels ≈ [0.5, 0.5, 3.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
@test hitmap1.pixels == [2, 8, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0]

# Map loading

m = Healpix.readMapFromFITS("float_map.fits", 1, Float32)
@test typeof(m) == Healpix.Map{Float32,Healpix.Ring}
@test m.resolution.nside == 4
@test m.pixels == [Float32(x) for x in 0:(12 * 4^2 - 1)]

m = Healpix.readMapFromFITS("int_map.fits", 1, Int8)
@test typeof(m) == Healpix.Map{Int8,Healpix.Ring}
@test m.resolution.nside == 1
@test m.pixels == [Int8(x) for x in 0:11]

# Map saving

const mapFileName = tempname()
print("Saving $mapFileName\n")
Healpix.saveToFITS(m, "!$mapFileName", typechar="I")
m2 = Healpix.readMapFromFITS(mapFileName, 1, Int8)
@test m.pixels == m2.pixels

# Map projections

m = Healpix.Map{Float64,Healpix.Ring}(1)
m.pixels = 1.0:12.0

bmp = Healpix.equirectangular(m, Dict(:width => 50))
bmp = Healpix.mollweide(m, Dict(:width => 50))
bmp = Healpix.orthographic(m, Dict(:width => 50))

# Alm creation

@test Healpix.numberOfAlms(10, 5) == 51
@test Healpix.numberOfAlms(10, 7) == 60
@test Healpix.numberOfAlms(12, 7) == 76
@test Healpix.numberOfAlms(12, 12) == 91
@test_throws DomainError(-1, "`lmax` is not positive or zero") Healpix.numberOfAlms(-1, 1)
@test_throws DomainError(-1, "`mmax` is not positive or zero") Healpix.numberOfAlms(4, -1)
@test_throws DomainError((5, 7), "`lmax` and `mmax` are inconsistent") Healpix.numberOfAlms(5, 7)

alm = Healpix.Alm{ComplexF32}(10, 8)
@test Healpix.almIndex(alm, 4, 2) == 24
@test Healpix.almIndex(alm, 5, 2) == 25
@test Healpix.almIndex(alm, 5, 3) == 33
@test Healpix.almIndex(alm, [4, 6, 5], [3, 4, 5]) == [32, 41, 46]

alm = Healpix.readAlmFromFITS("alm.fits", ComplexF64)
@test alm[1]  ≈ (5.443205775735e+03 + 0.000000000000e+00im) atol = eps
@test alm[2]  ≈ (-3.143659646589e+03 + 0.000000000000e+00im) atol = eps
@test alm[3]  ≈ (-8.445976910202e-07 + 0.000000000000e+00im) atol = eps
@test alm[4]  ≈ (3.003475555079e-07 + 0.000000000000e+00im) atol = eps
@test alm[5]  ≈ (-1.094164444296e-06 + 0.000000000000e+00im) atol = eps
@test alm[6]  ≈ (3.745732939005e-07 + 0.000000000000e+00im) atol = eps
@test alm[7]  ≈ (-1.344818023454e-06 + 0.000000000000e+00im) atol = eps
@test alm[8]  ≈ (6.658742467775e-01 + -3.280201017201e+01im) atol = eps
@test alm[9]  ≈ (1.200156696497e-15 + -1.483545355539e-15im) atol = eps
@test alm[10] ≈ (-1.959362683381e-01 + -3.069662938925e+00im) atol = eps
@test alm[11] ≈ (-4.068874968688e-15 + -5.766800364761e-16im) atol = eps
@test alm[12] ≈ (-1.134265758838e-01 + 1.102692148708e+00im) atol = eps
@test alm[13] ≈ (-2.153997451326e-15 + -5.152134573109e-15im) atol = eps
@test alm[14] ≈ (-6.895464505703e-01 + 1.597235776935e+01im) atol = eps
@test alm[15] ≈ (4.344648310121e-15 + -1.892253965354e-15im) atol = eps
@test alm[16] ≈ (6.488192068017e-02 + 3.967268430232e+00im) atol = eps
@test alm[17] ≈ (1.340722726247e-15 + -9.822172672993e-15im) atol = eps
@test alm[18] ≈ (1.485579846001e-01 + 7.942515768792e-01im) atol = eps
@test alm[19] ≈ (6.938894269949e-01 + -1.028821633749e+01im) atol = eps
@test alm[20] ≈ (3.412745093853e-15 + -4.420258002639e-15im) atol = eps
@test alm[21] ≈ (3.712279444471e-02 + -3.564529788432e+00im) atol = eps
@test alm[22] ≈ (-6.205890749143e-15 + 4.855843625358e-16im) atol = eps
@test alm[23] ≈ (-6.893793878861e-01 + 7.453657075068e+00im) atol = eps
@test alm[24] ≈ (4.644726834988e-11 + -4.685776289892e-15im) atol = eps
@test alm[25] ≈ (-1.162363120645e-01 + 3.084870414802e+00im) atol = eps
@test alm[26] ≈ (6.806207052149e-01 + -5.769903744427e+00im) atol = eps
@test alm[27] ≈ (-1.307082489340e-15 + 1.143824238899e-14im) atol = eps
@test alm[28] ≈ (-6.698490836781e-01 + 4.661675665246e+00im) atol = eps


text:
function get_crosssection_idx_and_value(g::Grid{T, 3, :cylindrical}, r, φ, z)::Tuple{Symbol,Int,T} where {T <: SSDFloat}

    cross_section::Symbol, idx::Int = if ismissing(φ) && ismissing(r) && ismissing(z)
        :φ, 1
    elseif !ismissing(φ) && ismissing(r) && ismissing(z)
        φ_rad::T = T(deg2rad(φ))
        while !(g.φ.interval.left <= φ_rad <= g.φ.interval.right) && g.φ.interval.right != g.φ.interval.left
            if φ_rad > g.φ.interval.right
                φ_rad -= g.φ.interval.right - g.φ.interval.left
            elseif φ_rad < g.φ.interval.left
                φ_rad += g.φ.interval.right - g.φ.interval.left
            end
        end
        :φ, searchsortednearest(g.φ, φ_rad)
    elseif ismissing(φ) && !ismissing(r) && ismissing(z)
        :r, searchsortednearest(g.r, T(r))
    elseif ismissing(φ) && ismissing(r) && !ismissing(z)
        :z, searchsortednearest(g.z, T(z))
    else
        error(ArgumentError, ": Only one of the keywords `r, φ, z` is allowed.")
    end

    value::T = if cross_section == :φ
        rad2deg(g.φ[idx])
    elseif cross_section == :r
        g.r[idx]
    elseif cross_section == :z
        g.z[idx]
    end

    cross_section, idx, value
end

@recipe function f(ep::ElectricPotential{T,3,:cylindrical}; r = missing, φ = missing, z = missing) where {T <: SSDFloat}

    if !(ep.grid[2][end] - ep.grid[2][1] ≈ 2π) ep = get_2π_potential(ep, n_points_in_φ = 72) end

    g::Grid{T, 3, :cylindrical} = ep.grid
    cross_section::Symbol, idx::Int, value::T = get_crosssection_idx_and_value(g, r, φ, z)

    seriescolor --> :viridis
    title --> "Electric Potential @ $(cross_section) = $(round(value,sigdigits=2))"*(cross_section == :φ ? "°" : "m")

    ep, g, cross_section, idx, value
end

@recipe function f(wp::WeightingPotential{T,3,:cylindrical}; r = missing, φ = missing, z = missing) where {T <: SSDFloat}

    if !(wp.grid[2][end] - wp.grid[2][1] ≈ 2π)
        wp = get_2π_potential(wp, n_points_in_φ = 72)
    end

    g::Grid{T, 3, :cylindrical} = wp.grid
    cross_section::Symbol, idx::Int, value::T = get_crosssection_idx_and_value(g, r, φ, z)

    seriescolor --> :viridis
    clims --> (0,1)
    title --> "Weighting Potential @ $(cross_section) = $(round(value,sigdigits=2))"*(cross_section == :φ ? "°" : "m")

    wp, g, cross_section, idx, value
end

@recipe function f(ρ::ChargeDensity{T,3,:cylindrical}; r = missing, φ = missing, z = missing) where {T <: SSDFloat}

    if !(ρ.grid[2][end] - ρ.grid[2][1] ≈ 2π)
        ρ = get_2π_potential(ρ, n_points_in_φ = 72)
    end

    g::Grid{T, 3, :cylindrical} = ρ.grid
    cross_section::Symbol, idx::Int, value::T = get_crosssection_idx_and_value(g, r, φ, z)

    seriescolor --> :inferno
    title --> "Effective Charge Density @ $(cross_section) = $(round(value,sigdigits=2))"*(cross_section == :φ ? "°" : "m")

    ρ, g, cross_section, idx, value
end

@recipe function f(pt::PointTypes{T,3,:cylindrical}; r = missing, φ = missing, z = missing) where {T <: SSDFloat}

    if !(pt.grid[2][end] - pt.grid[2][1] ≈ 2π)
        pt = get_2π_potential(pt, n_points_in_φ = 72)
    end

    g::Grid{T, 3, :cylindrical} = pt.grid
    cross_section::Symbol, idx::Int, value::T = get_crosssection_idx_and_value(g, r, φ, z)

    seriescolor --> :viridis
    clims --> (0,7)
    title --> "Point Type Map @ $(cross_section) = $(round(value,sigdigits=2))"*(cross_section == :φ ? "°" : "m")

    pt, g, cross_section, idx, value
end

@recipe function f(sp::ScalarPotential{T,3,:cylindrical}, g::Grid{T, 3, :cylindrical}, cross_section::Symbol, idx::Int, value::T) where {T}

    g::Grid{T, 3, :cylindrical} = sp.grid

    if minimum(sp.data) == maximum(sp.data)
        #@info "Set colorbar to display heatmap with non uniform axes"
        clims --> (sp.data[1], sp.data[1]+1)
    end

    @series begin
        seriestype := :heatmap
        foreground_color_border --> nothing
        tick_direction --> :out
        if cross_section == :φ
            aspect_ratio --> 1
            xguide --> "r / m"
            yguide --> "z / m"
            xlims --> (g.r[1],g.r[end])
            ylims --> (g.z[1],g.z[end])
            gr_ext::Array{T,1} = midpoints(get_extended_ticks(g.r))
            gz_ext::Array{T,1} = midpoints(get_extended_ticks(g.z))
            midpoints(gr_ext), midpoints(gz_ext), sp.data[:,idx,:]'
        elseif cross_section == :r
            xguide --> "φ / °"
            yguide --> "z / m"
            ylims --> (g.z[1],g.z[end])
            g.φ, g.z, sp.data[idx,:,:]'
        elseif cross_section == :z
            projection --> :polar
            g.φ, g.r, sp.data[:,:,idx]
        end
    end
end

@recipe function f(ϵ::DielectricDistribution{T,3,:cylindrical}; φ = 0) where {T <: SSDFloat}

    g::Grid{T, 3, :cylindrical} = ϵ.grid
    cross_section::Symbol, idx::Int, value::T = get_crosssection_idx_and_value(g, missing, φ, missing)

    seriestype --> :heatmap
    seriescolor --> :inferno
    foreground_color_border --> nothing
    tick_direction --> :out
    title --> "Dielectric Distribution @ $(cross_section) = $(round(value,sigdigits=2))"*(cross_section == :φ ? "°" : "m")

    gr_ext::Array{T,1} = midpoints(get_extended_ticks(g.r))
    gφ_ext::Array{T,1} = midpoints(get_extended_ticks(g.φ))
    gz_ext::Array{T,1} = midpoints(get_extended_ticks(g.z))

    @series begin
        if cross_section == :φ
            aspect_ratio --> 1
            xguide --> "r / m"
            yguide --> "z / m"
            xlims --> (g.r[1],g.r[end])
            ylims --> (g.z[1],g.z[end])
            gr_ext, gz_ext, ϵ.data[:,idx,:]'
        elseif cross_section == :r
            xguide --> "φ / °"
            yguide --> "z / m"
            ylims --> (g.z[1],g.z[end])
            rad2deg_backend.(gφ_ext), gz_ext, ϵ.data[idx,:,:]'
        elseif cross_section == :z
            projection --> :polar
            rad2deg_backend.(gφ_ext), gr_ext, ϵ.data[:,:,idx]
        end
    end
end

ext: jl


text:
using Yao

mutable struct U1{T<:Number} <: PrimitiveBlock{1}
    lambda::T
end

# 2-parameter 1-pulse single qubit gate
mutable struct U2{T<:Number} <: PrimitiveBlock{1}
    phi::T
    lambda::T
end

# 3-parameter 2-pulse single qubit gate
mutable struct U3{T<:Number} <: PrimitiveBlock{1}
    theta::T
    phi::T
    lambda::T
end

Base.:(==)(u1_1::U1, u1_2::U1) = u1_1.lambda == u1_2.lambda
Base.:(==)(u2_1::U2, u2_2::U2) = u2_1.phi == u2_2.phi && u2_1.lambda == u2_2.lambda
Base.:(==)(u3_1::U3, u3_2::U3) =
    u3_1.theta == u3_2.theta && u3_1.phi == u3_2.phi && u3_1.lambda == u3_2.lambda

function Yao.mat(::Type{T}, u1::U1) where {T}
    λ = u1.lambda

    T[
        1 0
        0 exp(im * λ)
    ]
end

function Yao.mat(::Type{T}, u2::U2) where {T}
    ϕ, λ = u2.phi, u2.lambda

    T[
        1/√2 (-exp(im * λ))/√2
        (exp(im * ϕ))/√2 (exp(im * (ϕ + λ)))/√2
    ]
end

function Yao.mat(::Type{T}, u3::U3) where {T}
    θ, ϕ, λ = u3.theta, u3.phi, u3.lambda

    T[
        cos(θ / 2) -sin(θ / 2)*exp(im * λ)
        sin(θ / 2)*exp(im * ϕ) cos(θ / 2)*exp(im * (ϕ + λ))
    ]
end

Yao.iparams_eltype(::U1{T}) where {T} = T
Yao.iparams_eltype(::U2{T}) where {T} = T
Yao.iparams_eltype(::U3{T}) where {T} = T

Yao.getiparams(u1::U1{T}) where {T} = (u1.lambda)
Yao.getiparams(u2::U2{T}) where {T} = (u2.phi, u2.lambda)
Yao.getiparams(u3::U3{T}) where {T} = (u3.theta, u3.phi, u3.lambda)

function Yao.setiparams!(u1::U1{T}, λ) where {T}
    u1.lambda = λ
    return u1
end

function Yao.setiparams!(u2::U2{T}, ϕ, λ) where {T}
    u2.phi = ϕ
    u2.lambda = λ
    return u2
end

function Yao.setiparams!(u3::U3{T}, θ, ϕ, λ) where {T}
    u3.theta = θ
    u3.phi = ϕ
    u3.lambda = λ
    return u3
end

YaoBlocks.@dumpload_fallback U1 U1
YaoBlocks.@dumpload_fallback U2 U2
YaoBlocks.@dumpload_fallback U3 U3

"""
    convert_to_qbir(inst)

Converts Qobj based instructions back to YaoIR.

- `inst`: The Qobj based instructions.

For Example:
```julia
q = convert_to_qobj(chain(1, put(1 => H)))
ir = q.experiments[1].instructions |> convert_to_qbir
```
"""
function convert_to_qbir(inst)
    n = maximum(x -> maximum(x.qubits), inst) + 1
    chain(
        n,
        map(inst) do x
            name, locs = x.name, x.qubits .+ 1
            nc = 0
            while name[nc+1] == 'c' && nc < length(name)
                nc += 1
            end
            if nc > 0
                control(
                    n,
                    locs[1:nc],
                    locs[nc+1:end] => name_index(name[nc+1:end], x.params),
                )
            elseif name == "measure"
                put(n, locs => Yao.Measure(locs...))
            else
                put(n, locs => name_index(name, x.params))
            end
        end,
    )
end

function name_index(name, params = nothing)
    if name == "u1"
        U1(params...)
    elseif name == "u2"
        if isapprox(params, [0, π])
            H
        else
            U2(params...)
        end
    elseif name == "u3"
        if isapprox(params[2], -π / 2) && isapprox(params[3], π / 2)
            Rx(params[1])
        elseif params[2] == 0 && params[3] == 0
            Ry(params[1])
        else
            U3(params...)
        end
    elseif name == "id"
        I2
    elseif name == "x"
        X
    elseif name == "y"
        Y
    elseif name == "z"
        Z
    elseif name == "t"
        T
    elseif name == "swap"
        SWAP
    else
        error("gate type `$name` not defined!")
    end
end


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

mutable struct DataLakeStoreAccountProperties <: SwaggerModel
    provisioningState::Any # spec type: Union{ Nothing, String } # spec name: provisioningState
    state::Any # spec type: Union{ Nothing, String } # spec name: state
    creationTime::Any # spec type: Union{ Nothing, DateTime } # spec name: creationTime
    lastModifiedTime::Any # spec type: Union{ Nothing, DateTime } # spec name: lastModifiedTime
    endpoint::Any # spec type: Union{ Nothing, String } # spec name: endpoint
    accountId::Any # spec type: Union{ Nothing, String } # spec name: accountId

    function DataLakeStoreAccountProperties(;provisioningState=nothing, state=nothing, creationTime=nothing, lastModifiedTime=nothing, endpoint=nothing, accountId=nothing)
        o = new()
        validate_property(DataLakeStoreAccountProperties, Symbol("provisioningState"), provisioningState)
        setfield!(o, Symbol("provisioningState"), provisioningState)
        validate_property(DataLakeStoreAccountProperties, Symbol("state"), state)
        setfield!(o, Symbol("state"), state)
        validate_property(DataLakeStoreAccountProperties, Symbol("creationTime"), creationTime)
        setfield!(o, Symbol("creationTime"), creationTime)
        validate_property(DataLakeStoreAccountProperties, Symbol("lastModifiedTime"), lastModifiedTime)
        setfield!(o, Symbol("lastModifiedTime"), lastModifiedTime)
        validate_property(DataLakeStoreAccountProperties, Symbol("endpoint"), endpoint)
        setfield!(o, Symbol("endpoint"), endpoint)
        validate_property(DataLakeStoreAccountProperties, Symbol("accountId"), accountId)
        setfield!(o, Symbol("accountId"), accountId)
        o
    end
end # type DataLakeStoreAccountProperties

const _property_map_DataLakeStoreAccountProperties = Dict{Symbol,Symbol}(Symbol("provisioningState")=>Symbol("provisioningState"), Symbol("state")=>Symbol("state"), Symbol("creationTime")=>Symbol("creationTime"), Symbol("lastModifiedTime")=>Symbol("lastModifiedTime"), Symbol("endpoint")=>Symbol("endpoint"), Symbol("accountId")=>Symbol("accountId"))
const _property_types_DataLakeStoreAccountProperties = Dict{Symbol,String}(Symbol("provisioningState")=>"String", Symbol("state")=>"String", Symbol("creationTime")=>"DateTime", Symbol("lastModifiedTime")=>"DateTime", Symbol("endpoint")=>"String", Symbol("accountId")=>"String")
Base.propertynames(::Type{ DataLakeStoreAccountProperties }) = collect(keys(_property_map_DataLakeStoreAccountProperties))
Swagger.property_type(::Type{ DataLakeStoreAccountProperties }, name::Symbol) = Union{Nothing,eval(Meta.parse(_property_types_DataLakeStoreAccountProperties[name]))}
Swagger.field_name(::Type{ DataLakeStoreAccountProperties }, property_name::Symbol) =  _property_map_DataLakeStoreAccountProperties[property_name]

const _allowed_DataLakeStoreAccountProperties_provisioningState = ["Failed", "Creating", "Running", "Succeeded", "Patching", "Suspending", "Resuming", "Deleting", "Deleted", "Undeleting", "Canceled"]

const _allowed_DataLakeStoreAccountProperties_state = ["Active", "Suspended"]

function check_required(o::DataLakeStoreAccountProperties)
    true
end

function validate_property(::Type{ DataLakeStoreAccountProperties }, name::Symbol, val)
    if name === Symbol("provisioningState")
        Swagger.validate_param(name, "DataLakeStoreAccountProperties", :enum, val, _allowed_DataLakeStoreAccountProperties_provisioningState)
    end
    if name === Symbol("state")
        Swagger.validate_param(name, "DataLakeStoreAccountProperties", :enum, val, _allowed_DataLakeStoreAccountProperties_state)
    end
end


text:
#unum.jl
#collation includes for all the code that supports the unum type (but not the
#type definition itself, that must be forwarded separately.)

include("./unum-helpers.jl")
include("./unum-constants.jl")
include("./unum-properties.jl")
include("./unum-operations.jl")
include("./unum-convert.jl")

#h-layer stuff

include("./unum-hlayer.jl")

#mathematical stuff

include("./math/unum-comparison.jl")
include("./math/unum-addition.jl")
include("./math/unum-subtraction.jl")
include("./math/unum-multiplication.jl")
include("./math/unum-division.jl")
include("./math/unum-sqrs.jl")

max_stars_repo_name: REX-Computing/unumjl

max_issues_repo_name: REX-Computing/unumjl

max_forks_repo_name: REX-Computing/unumjl


text:
export rearrange
export drop_powers
export get_averaged_equations
export d
export substitute_all
export get_all_terms
export var_name

"The derivative of f w.r.t. x of degree deg"
function d(f::Num, x::Num, deg=1)
    isequal(deg,0) ? f : (Differential(x)^deg)(f)
end
d(funcs::Vector{Num}, x::Num, deg=1) = [d(f, x, deg) for f in funcs]

"Declare a variable in the the currently active namespace"
 function declare_variable(name::String)
    var_sym = Symbol(name)
    @eval($(var_sym) = first(@variables $var_sym))
    return eval(var_sym)
 end

 "Declare a variable that is a function of another variable in the the current namespace"
 function declare_variable(name::String, independent_variable::Num)
    # independent_variable = declare_variable(independent_variable) convert string into Num
    var_sym = Symbol(name)
    new_var = @variables $var_sym(independent_variable)
    @eval($(var_sym) = first($new_var)) # store the variable under "name" in this namespace
    return eval(var_sym)
 end

 "Return the name of a variable (excluding independent variables)"
 var_name(x::Num) = var_name(x.val)
 var_name(x::Term) = String(Symbolics._toexpr(x).args[1])
 var_name(x::Sym) = String(x.name)

 """
 $(TYPEDSIGNATURES)

 Perform substitutions in `rules` on `x`.
 `include_derivatives=true` also includes all derivatives of the variables of the keys of `rules`.
 """
 function substitute_all(x::Union{Num, Equation}, rules::Dict; include_derivatives=true)
    if include_derivatives
        rules = merge(rules, Dict([Differential(var) => Differential(rules[var]) for var in keys(rules)]))
    end
    return substitute(x, rules)
 end

 "Variable substitution - dictionary"
function substitute_all(dict::Dict, rules::Dict)
    new_keys = substitute_all.(keys(dict), rules)
    new_values = substitute_all.(values(dict), rules)
    return Dict(zip(new_keys, new_values))
end

substitute_all(v::Union{Array{Num}, Array{Equation}}, rules::Union{Dict, Pair, Vector}) = [substitute_all(x, rules) for x in v]
substitute_all(x::Union{Num, Equation}, rules::Union{Pair, Vector, Dict}) = substitute_all(x, Dict(rules))
substitute_all(x, rules::OrderedDict) = substitute_all(x, Dict(rules))
substitute_all(x::Complex{Num}, rules) = substitute_all(Num(x.re.val.arguments[1]), rules)
substitute_all(x, rules) = substitute_all(Num(x), rules)

"""
$(SIGNATURES)
Remove parts of `expr` where the combined power of `vars` is => `deg`.

# Example
```julia-repl
julia> @variables x,y;
julia>drop_powers((x+y)^2, x, 2)
y^2 + 2*x*y
julia>drop_powers((x+y)^2, [x,y], 2)
0
julia>drop_powers((x+y)^2 + (x+y)^3, [x,y], 3)
x^2 + y^2 + 2*x*y
```
"""
function drop_powers(expr::Num, vars::Vector{Num}, deg::Int)
    @variables ϵ
    subs_expr = deepcopy(expr)
    rules = Dict([var => ϵ*var for var in unique(vars)])
    subs_expr = Symbolics.expand(substitute_all(subs_expr, rules))
    max_deg = max_power(subs_expr, ϵ)
    removal = Dict([ϵ^d =>Num(0) for d in deg:max_deg])
    res = substitute_all(substitute_all(subs_expr, removal), Dict(ϵ => Num(1)))
    Symbolics.expand(res)
    #res isa Complex ? Num(res.re.val.arguments[1]) : res
end

drop_powers(expr::Vector{Num}, var::Num, deg::Int) = [drop_powers(x, var, deg) for x in expr]

# calls the above for various types of the first argument
drop_powers(eq::Equation, var, deg) = drop_powers(eq.lhs, var, deg) .~ drop_powers(eq.lhs, var, deg)
drop_powers(eqs::Vector{Equation}, var, deg) = [drop_powers(eq.lhs, var, deg) .~ drop_powers(eq.rhs, var, deg) for eq in eqs]
drop_powers(expr, var::Num, deg::Int) = drop_powers(expr, [var], deg)
drop_powers(x, vars, deg) = drop_powers(Num(x), vars, deg)

flatten(a) = collect(Iterators.flatten(a))

###
# STUFF BELOW IS MAINLY FOR FOURIER-TRANSFORMING
###

get_independent(x::Num, t::Num) = get_independent(x.val, t)
get_independent(x::Complex{Num}, t::Num) = get_independent(x.re, t) + im*get_independent(x.im, t)
get_independent(x::Union{Term, Sym}, t::Num) = !is_function(x, t) ? x : 0
get_independent(x::Add, t::Num) = sum([get_independent(arg, t) for arg in arguments(x)])
get_independent(x::Pow, t::Num) = !is_function(x.base, t) && !is_function(x.exp, t) ? x : 0
get_independent(x::Div, t::Num) = !is_function(x.den, t) ? get_independent(x.num, t) / x.den : 0
get_independent(x::Mul, t::Num) = prod([get_independent(arg, t) for arg in arguments(x)])
get_independent(v::Vector{Num}, t::Num) = [get_independent(el, t) for el in v]
get_independent(x, t::Num) = x

#=
function get_independent(expr::SymbolicUtils.Add, t::Num)
    primitive_terms = keys(expr.dict)
    total = expr.coeff
    for term in primitive_terms
        total += get_independent(term, t) * expr.dict[term]
    end
    return total
end
=#

"Return all the terms contained in `x`"
get_all_terms(x::Num) = unique(_get_all_terms(Symbolics.expand(x).val))
get_all_terms(x::Equation) = unique(cat(get_all_terms(Num(x.lhs)), get_all_terms(Num(x.rhs)), dims=1))

_get_all_terms(x::Mul) = Num.(SymbolicUtils.arguments(x))
_get_all_terms(x::Div) = Num.([_get_all_terms(x.num)..., _get_all_terms(x.den)...])
_get_all_terms(x) = Num(x)

function _get_all_terms(x::Add)::Vector{Num}
    list = []
    for term in keys(x.dict)
        list = cat(list, _get_all_terms(term), dims=1)
    end
    return list
end

function is_harmonic(x::Num, t::Num)
    all_terms = get_all_terms(x)
    t_terms = setdiff(all_terms, get_independent(all_terms, t))
    isempty(t_terms) && return true
    trigs = is_trig.(t_terms)

    if !prod(trigs)
        return false
    else
        powers = [max_power(first(term.val.arguments), t) for term in t_terms[trigs]]
        return unique(powers) == [1]
    end
end

is_harmonic(x::Equation, t::Num) = is_harmonic(x.lhs, t) && is_harmonic(x.rhs, t)
is_harmonic(x, t) = is_harmonic(Num(x), Num(t))

"Convert all sin/cos terms in `x` into exponentials."
function trig_to_exp(x::Num)
    all_terms = get_all_terms(x)
    trigs = filter(z -> is_trig(z), all_terms)

    rules = []
    for trig in trigs
        is_pow = trig.val isa Pow # trig is either a trig or a power of a trig
        power = is_pow ? trig.val.exp : 1
        arg = is_pow ? arguments(trig.val.base)[1] : arguments(trig.val)[1]
        type = is_pow ? operation(trig.val.base) : operation(trig.val)

        if type == cos
            term = Complex{Num}((exp(im*arg) + exp(-im*arg))^power * (1//2)^power,0)
        elseif type == sin
            term = (1*im^power)* Complex{Num}( ((exp(-im*arg) - exp(im*arg)))^power *(1//2)^power, 0)
        end
        # avoid Complex{Num} where possible as this causes bugs
        # instead, the Nums store SymbolicUtils Complex types
        term = Num(term.re.val + im*term.im.val)
        append!(rules, [trig => term])
    end

    result = Symbolics.substitute(x, Dict(rules))
    #result = result isa Complex ? Num(first(result.re.val.arguments)) : result
    result = Num(result)
    return result
end

"Return true if `f` is a function of `var`."
is_function(f, var) = any(isequal.(get_variables(f), var))

"Return true if `f` is a sin or cos."
function is_trig(f::Num)
    f = f.val isa Pow ? f.val.base : f.val
    f isa Term && SymbolicUtils.operation(f) ∈ [cos,sin] && return true
    return false
end

"A vector of Sym(0) of length n"
Num_zeros(n::Int64) = [Num(0) for k in 1:n]
Num_zeros(vec::Vector{Any}) = Num_zeros(length(vec))

"""
$(TYPEDSIGNATURES)
Returns the coefficient of cos(ωt) in `x`.
"""
function fourier_cos_term(x, ω, t)
    _fourier_term(x,ω, t, cos)
end

"""
$(TYPEDSIGNATURES)
Returns the coefficient of sin(ωt) in `x`.
"""
function fourier_sin_term(x, ω, t)
    _fourier_term(x,ω, t, sin)
end

function _fourier_term(x::Equation, ω, t, f)
    _fourier_term(x.lhs, ω, t, f) .~ _fourier_term(x.rhs, ω, t, f)
end

"Return the coefficient of f(ωt) in `x` where `f` is a cos or sin."
function _fourier_term(x, ω, t, f)
    term = x * f(ω * t)
    term = trig_reduce(term)
    indep = get_independent(term, t)
    ft = Num(simplify_complex(Symbolics.expand(indep)))
    !isequal(ω, 0) ? 2*ft : ft # extra factor in case ω = 0 !
end

"Expand all sin/cos powers in `x`."
function trig_reduce(x)
    x = Symbolics.expand(x) # open all brackets
    x = trig_to_exp(x)
    x = expand_all(x) # expand products of exponentials
    x= simplify_exp_products(x) # simplify products of exps
    x = exp_to_trig(x)
    x
end

"Return the highest power of `y` occuring in the term `x`."
function max_power(x::Num, y::Num)
    terms = get_all_terms(x)
    powers = power_of.(terms, y)
    maximum(powers)
end

max_power(x::Vector{Num}, y::Num) = maximum(max_power.(x, y))
max_power(x::Complex, y::Num) = maximum(max_power.([x.re, x.im], y))
max_power(x, t) = max_power(Num(x), Num(t))

"Return the power of `y` in the term `x`"
function power_of(x::Num, y::Num)
    y.val isa Sym ? nothing : error("power of " * string(y) * " is ambiguous")
    power_of(x.val, y.val)
end

power_of(x::Pow, y::Sym) = isequal(x.base, y) ? x.exp : 0
power_of(x::Sym, y::Sym) = isequal(x, y) ? 1 : 0
power_of(x::Term, y::Sym) = 0
power_of(x, y) = 0


text:
#!/usr/bin/env python
# coding: utf-8

# # Spontaneous moralization on simple graph

# ## Loading modules

using QSWalk
using GraphPlot # For plotting graph
using LightGraphs
using LinearAlgebra

# ## Moralizing evolution

# Here we provide the simple example of graph, for which the spontaneous moralization happens. Note there is no path from vertex 1 to 2.

digraph = DiGraph(3)
add_edge!(digraph, 1, 3)
add_edge!(digraph, 2, 3)

gplot(digraph)

# Here we generate some basic operators. Note in the case of directed graphs we need to transpose adjacency matrix, as *QSWalk.jl* multiplies the state on the right side of evolution operator. Note we choose zero matrix as Hamiltonian of the system.
#
# As we deal with the graph of very small size, we choose full-matrix evolution algorithm. In order to do such, we need to provide in opmoral at least one full matrix.

adjacency = Matrix(transpose(adjacency_matrix(digraph)))
timepoint = 100.

opmoral = evolve_generator(zero(adjacency), [adjacency])
println(typeof(opmoral))

# As a result of the evolution we get an stationary state with non-zero probability of measuring vertex 2. Note the state is actually a stationary state.

rho = evolve(opmoral, proj(1, 3), timepoint)
println("Cannonical measurement on stationary state: $(real.(diag(rho)))")
println("Norm of opmoral times rho: $(norm(opmoral*res(rho)))")

# ## Non-moralizing evolution

# In this example we present model, which do not possess unintuitive property.

lnonmoral, vset = nm_lind(adjacency)
hlocal = nm_loc_ham(vset)
opnonmoral = evolve_generator(zero(lnonmoral), [lnonmoral], hlocal);

# *vset* and *hlocal* represent parametrization and additional operator for non-moralizing evolution. Note that vset is actually a partition of the new, increased linear space between vertices.

println("vset: $vset")
println("Subspace dimension: $(vertexsetsize(vset))")
println("Size of new Lindblad operator: $(size(lnonmoral))")

# Since the subspace has different dimension, one should consider using more advanced functions for initial states. The function below creates a state localized in subspace corresponding to vertex 1. Note it coincides with the first element of *vset*.

rhoinit = nm_init(vset[[1]], vset)
println("state: $rhoinit")
println("equivalence class corresponding to vertex 1: $(vset[[1]])")

# This result in evolution, which prohibit passing amplitude to vertex 2. This can be seen in the example below.

rho = evolve(opnonmoral, rhoinit, timepoint)
println("Natural measurement on state: $(nm_measurement(rho, vset))")


text:
using Parameters
using PyPlot

include("lv_model.jl")

function iso1(u2, p)
    @unpack α12, K1 = p
    return K1 - α12 * u2 / K1
end

function iso2(u2, p)
    @unpack α21, K2 = p
    return (K2 - u2) / α21
end

let
    par = LVPar(K1 = 1.5)
    u2range = 0.0:0.1:3.0
    lv_plot = figure()
    plot(u2range, [iso1(u2, par) for u2 in u2range])
    plot(u2range, [iso2(u2, par) for u2 in u2range])
    xlim(0,3)
    ylim(0,3)
    return lv_plot
end

max_stars_repo_name: McCannLab/TheoryClub

max_issues_repo_name: McCannLab/TheoryClub

max_forks_repo_name: McCannLab/TheoryClub


text:
#---------------------------------------------------------------------#
#This code computes the Legendre-Gauss points & weights
#which are the roots of the Legendre Polynomials.
#Written by F.X. Giraldo on 4/2008
#           Department of Applied Mathematics
#           Naval Postgraduate School
#           Monterey; CA 93943-5216
#---------------------------------------------------------------------#
function legendre_gauss(P::Integer,DFloat)

    xgl=zeros(DFloat,P)
    wgl=zeros(DFloat,P)

    p=P-1; #Order of Polynomials [P is the number of points: p+1]
    ph=floor(typeof(P), (p+1)/2 )

    for i=1:ph
        x=cos( (2*i-1)*pi/(2*p+1) )
        for k=1:20
            (L0,L0_1,L0_2)=legendre_poly(p+1,x); #Compute the N+1 Legendre Polys

            #Get new Newton Iteration
            dx=-L0/L0_1
            x=x+dx
            if (abs(dx) < 1.0e-20)
                break
            end
        end
        xgl[p+2-i]=x
        wgl[p+2-i]=2/( (1-x^2)*L0_1^2 )
    end

    #Check for Zero Root
    if (p+1 != 2*ph)
        x=0
        (L0,L0_1,L0_2)=legendre_poly(p+1,x)
        xgl[ph+1]=x
        wgl[ph+1]=2/( (1-x^2)*L0_1^2 )
    end

    #Find remainder of roots via symmetry
    for i=1:ph
        xgl[i]=-xgl[p+2-i]
        wgl[i]=+wgl[p+2-i]
    end
    return xgl,wgl
end #function


text:
abstract type CIService end

###############
## Travis CI ##
###############
struct TravisCI <: CIService
    enable_cron_builds::Bool
    enable_api_builds::Bool
    function TravisCI(; enable_cron_builds=true, enable_api_builds=true)
        return new(enable_cron_builds, enable_api_builds)
    end
end
function conditions_met_for_pr_build(cfg::TravisCI; env=ENV, master_branch, kwargs...)
    return get(env, "TRAVIS_EVENT_TYPE", nothing) == "pull_request" &&
           get(env, "TRAVIS_BRANCH", nothing) == master_branch
end
function conditions_met_for_merge_build(cfg::TravisCI; env=ENV, master_branch, kwargs...)
    ## Check that we are on the correct branch
    branch_ok = get(env, "TRAVIS_BRANCH", nothing) == master_branch
    ## Check that we are running a cron or api job
    event_type = get(env, "TRAVIS_EVENT_TYPE", nothing)
    cron_ok = event_type == "cron" && cfg.enable_cron_builds
    api_ok = event_type == "api" && cfg.enable_api_builds
    return branch_ok && (cron_ok || api_ok)
end
function pull_request_number(cfg::TravisCI; env=ENV, kwargs...)
    return parse(Int, env["TRAVIS_PULL_REQUEST"])
end
function current_pr_head_commit_sha(cfg::TravisCI; env=ENV, kwargs...)
    return env["TRAVIS_PULL_REQUEST_SHA"]
end
function directory_of_cloned_registry(cfg::TravisCI; env=ENV, kwargs...)
    return env["TRAVIS_BUILD_DIR"]
end
function username(api::GitHub.GitHubAPI, cfg::TravisCI; auth)
    return username(api, auth) # use /user endpoint
end

####################
## GitHub Actions ##
####################
struct GitHubActions <: CIService
    enable_cron_builds::Bool
    function GitHubActions(; enable_cron_builds=true)
        return new(enable_cron_builds)
    end
end

function conditions_met_for_pr_build(cfg::GitHubActions; env=ENV, kwargs...)
    # TODO: Should also check the PR is against "master" or maybe thats done later?
    return get(env, "GITHUB_EVENT_NAME", nothing) == "pull_request"
end
function conditions_met_for_merge_build(cfg::GitHubActions; env=ENV, master_branch, kwargs...)
    ## Check that we are on the correct branch
    m = match(r"^refs\/heads\/(.*)$", get(env, "GITHUB_REF", ""))
    branch_ok = m !== nothing && m.captures[1] == master_branch
    ## Check that we are running a cron job
    event_type = get(env, "GITHUB_EVENT_NAME", nothing)
    cron_ok = event_type == "schedule" && cfg.enable_cron_builds
    return branch_ok && cron_ok
end
function pull_request_number(cfg::GitHubActions; env=ENV, kwargs...)
    m = match(r"^refs\/pull\/(\d+)\/merge$", get(env, "GITHUB_REF", ""))
    always_assert(m !== nothing)
    return parse(Int, m.captures[1])
end
function current_pr_head_commit_sha(cfg::GitHubActions; env=ENV, kwargs...)
    always_assert(get(env, "GITHUB_EVENT_NAME", nothing) == "pull_request")
    file = get(env, "GITHUB_EVENT_PATH", nothing)
    file === nothing && return nothing
    content = JSON.parsefile(file)
    return content["pull_request"]["head"]["sha"]
end
function directory_of_cloned_registry(cfg::GitHubActions; env=ENV, kwargs...)
    return get(env, "GITHUB_WORKSPACE", nothing)
end
function username(api::GitHub.GitHubAPI, cfg::GitHubActions; auth)
    # /user endpoint of GitHub API not available
    # with the GITHUB_TOKEN authentication
    return "github-actions[bot]"
end

##############
## TeamCity ##
##############
struct TeamCity <: CIService
end

function conditions_met_for_pr_build(cfg::TeamCity; env=ENV, kwargs...)
    pr_number_ok = tryparse(Int, get(env, "teamcity_pullRequest_number", "")) !== nothing
    return haskey(env, "teamcity_pullRequest_title") && pr_number_ok
end

function conditions_met_for_merge_build(cfg::TeamCity; env=ENV, master_branch, kwargs...)
    pr_number_ok = tryparse(Int, get(env, "teamcity_pullRequest_number", "")) !== nothing
    haskey(env, "teamcity_pullRequest_title") && pr_number_ok && return false
    ## Check that we are on the correct branch
    m = match(r"^refs\/heads\/(.*)$", get(env, "vcsroot_branch", ""))
    branch_ok = m !== nothing && m.captures[1] == master_branch
    return branch_ok
end

function pull_request_number(cfg::TeamCity; env=ENV, kwargs...)
    pr_number = tryparse(Int, get(env, "teamcity_pullRequest_number", ""))
    always_assert(pr_number !== nothing)
    return pr_number
end

function current_pr_head_commit_sha(cfg::TeamCity; env=ENV, kwargs...)
    # black magic relying on TC build parameter teamcity.git.fetchAllHeads=true
    tc_pr_branch_name = get(env, "teamcity_pullRequest_source_branch", nothing)
    always_assert(!isnothing(tc_pr_branch_name))
    git_info = read(pipeline(`git show-ref`, `grep $tc_pr_branch_name`), String)
    git_info_row = split(git_info, "\n")[1]
    pr_sha = split(git_info_row, " ")[1]
    return string(pr_sha)
end

directory_of_cloned_registry(cfg::TeamCity; env=ENV, kwargs...) = get(env, "PWD", nothing)

username(api::GitHub.GitHubAPI, cfg::TeamCity; auth) = "svc-aivision-reg"

####################
## Auto detection ##
####################
function auto_detect_ci_service(; env=ENV)
    if haskey(env, "TRAVIS_REPO_SLUG")
        return TravisCI()
    elseif haskey(env, "GITHUB_REPOSITORY")
        return GitHubActions()
    elseif haskey(env, "TEAMCITY_PROJECT_NAME")
        return TeamCity()
    else
        error("Could not detect system.")
    end
end


text:
# ---
# title: 1653. Minimum Deletions to Make String Balanced
# id: problem1653
# author: Tian Jun
# date: 2020-10-31
# difficulty: Medium
# categories: String, Greedy
# link: <https://leetcode.com/problems/minimum-deletions-to-make-string-balanced/description/>
# hidden: true
# ---
#
# You are given a string `s` consisting only of characters `'a'` and `'b'`.
#
# You can delete any number of characters in `s` to make `s` **balanced**. `s`
# is **balanced** if there is no pair of indices `(i,j)` such that `i < j` and
# `s[i] = 'b'` and `s[j]= 'a'`.
#
# Return _the **minimum** number of deletions needed to make _`s`
# _**balanced**_.
#
#
#
# **Example 1:**
#
#
#
#     Input: s = "aababbab"
#     Output: 2
#     Explanation: You can either:
#     Delete the characters at 0-indexed positions 2 and 6 ("aa _b_ abb _a_ b" -> "aaabbb"), or
#     Delete the characters at 0-indexed positions 3 and 6 ("aab _a_ bb _a_ b" -> "aabbbb").
#
#
# **Example 2:**
#
#
#
#     Input: s = "bbaaaaabb"
#     Output: 2
#     Explanation: The only solution is to delete the first two characters.
#
#
#
#
# **Constraints:**
#
#   * `1 <= s.length <= 105`
#   * `s[i]` is `'a'` or `'b'`.
#
#
## @lc code=start
using LeetCode

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


text:
module Utils
using Distributed

# project root
const PROJECT_ROOT = joinpath(@__DIR__, "..", "..")
# create a global variable to keep track of experiments and their processes
const experiments_dictionary = Dict{String, Int64}()
# keep track of the number of experiments for each process
experiment_counts = zeros(Int64, nworkers())
worker_ids = workers()
# create a training progress message channel
const training_progress = Dict{String, Vector{String}}()
# storage for result file names
const result_file_dictionary = Dict{String, String}()

function log_message(msg)
    prefix = ""
    if myid() == 1
        prefix = "      From master 1:    "
    end
    Core.println(prefix*msg)
end

function init_workers(workers::Vector{Int64})
    global worker_ids = workers
    global experiment_counts = zeros(Int64, length(workers))
end

experiment_registered(experiment_id::String) = haskey(experiments_dictionary, experiment_id)

get_experiment_process(experiment_id::String) = experiments_dictionary[experiment_id]

log_progress(experiment_id::String, s::String) = @spawnat 1 push!(training_progress[experiment_id], s)

get_progress(experiment_id::String) = training_progress[experiment_id]

store_result(experiment_id::String, result_file::String) = @spawnat 1 push!(result_file_dictionary, experiment_id => result_file)

get_result(experiment_id::String) = result_file_dictionary[experiment_id]

function register_experiment(experiment_id::String)
    # find a suitable worker (that with the minimal number of experiments)
    proc_idx = argmin(experiment_counts)
    proc_id = worker_ids[proc_idx]
    experiments_dictionary[experiment_id] = proc_id
    # update counts
    experiment_counts[proc_idx] += 1
    # init message queue
    training_progress[experiment_id] = Vector{String}()
    result_file_dictionary[experiment_id] = ""
    proc_id
end

function unregister_experiment(experiment_id::String)
    proc_id = get_experiment_process(experiment_id)
    delete!(experiments_dictionary, experiment_id)
    delete!(training_progress, experiment_id)
    result_file = get_result(experiment_id)
    if result_file != ""
        rm(result_file, force = true)
    end
    delete!(result_file_dictionary, experiment_id)
    proc_id
end

export experiment_registered, register_experiment, unregister_experiment
export log_message, log_progress, get_experiment_process, get_progress, get_result
export PROJECT_ROOT

end


text:
# get a small mesh
domain = [0 2.0 0 2.2 0 1.2]
n      = [12;8; 7]
M      = getRegularMesh(domain,n)

# sources / receivers on top edge
idx    = reshape(collect(1:prod(n.+1)),tuple(n.+1...))
ib     = idx[:,1,:];

n_nodes = prod(n.+1);
Q      = SparseMatrixCSC(1.0I, n_nodes, n_nodes)
Q      = Q[:,vec(ib)]
R      = copy(Q)

# get param without parallelizaion
pFor = getEikonalInvParam(M,Q,R,true)
m0   = 0.2*rand(Float64,tuple(n.+1...)) .+ 1.0
dho, = getData(vec(m0),pFor)
pFor.HO = false;
dlo, = getData(vec(m0),pFor)
@test norm(dho-dlo)/norm(dho) < 0.05

# parallelize over sources
pForp,continuationDivision,SourcesSubInd = getEikonalInvParam(M,Q,R,true,nworkers())
dphor, = getData(vec(m0),pForp)
dpho = zeros(size(dho))
for k=1:length(dphor)
	dpho[:,SourcesSubInd[k]] = fetch(dphor[k])
end
pForp,continuationDivision,SourcesSubInd = getEikonalInvParam(M,Q,R,false,nworkers())
dplor, = getData(vec(m0),pForp)
dplo = zeros(size(dho))
for k=1:length(dplor)
	dplo[:,SourcesSubInd[k]] = fetch(dplor[k])
end

@test norm(dpho-dho)/norm(dho) < 1e-12
@test norm(dplo-dlo)/norm(dlo) < 1e-12


text:
module PostgresTest

using Postgres
const pg = Postgres
using FactCheck

facts("Postgres Initialisation") do
	context("Setup") do
		options = Dict{ByteString, ByteString}()
		options["user"] = "postgres"

		conn = pg.pg_connect()
		msg = pg.pg_msg(:start, options)
		pg.writemsg(conn, msg)
		rmsg = pg.readmsg(conn)
		@fact pg.parsemsg(rmsg) => (:AuthenticationOK, )
		close(conn)
	end

	context("PGConnection") do
		conn = pg.PGConnection("postgres")
		close(conn)
	end
end
end


text:
using Niancat.Gameface
using Niancat.Users
using Niancat.Persistence
using Niancat.Instances
using Niancat.Http
using Niancat.Formatters
using Niancat.Games.NiancatGames
import Niancat.Instances: registergame!
import Niancat.Persistence: getuser, updatenotificationendpoint!, updatedisplayname!

# This is a placeholder until a proper implementation is done
using Niancat.Games.NiancatGames

using SQLite

struct NiancatService
    persistence::GamePersistence
    instances::GameInstances

    function NiancatService(db::SQLite.DB; httpclient :: HttpClient = RealHttpClient())
        # Initialize the database if it is empty.
        tableresult = SQLite.tables(db)
        tables = tableresult[:name]
        if isempty(tables)
            Persistence.initializedatabase!(db)
        end
        persistence = GamePersistence(db)
        new(persistence, GameInstances(httpclient, persistence))
    end
end

function findcommand(svc::NiancatService, user::User, command::String) :: Tuple{Game, GameCommand}
    # Dummy implementation that only returns the Niancat game in the default instance.
    game = getgame(svc.instances, "Niancat", "defaultinstance")

    if command == "!nian"
        game, NiancatGames.GetPuzzle()
    elseif startswith(command, "!sättnian")
        word = split(command)[2]
        game, NiancatGames.SetPuzzle(word)
    else
        game, NiancatGames.Guess(command)
    end
end

loadgameinstances!(svc::NiancatService) = Instances.loadgameinstances!(svc.instances)
Instances.registergame!(svc::NiancatService, name::String, initialstate::String, factory::Function) = registergame!(svc.instances, name, initialstate, factory)

function Instances.newgame!(svc::NiancatService,
                            instancename::String,
                            gamename::String)
    newgame!(svc.instances, instancename, gamename)
end

declareinstance!(svc::NiancatService, instancename::String) = Persistence.declareinstance!(svc.persistence, instancename)
listinstancenames(svc::NiancatService) :: Vector{String} = Persistence.listinstancenames(svc.persistence)

Persistence.getuser(svc::NiancatService, userid::String, teamname::String) :: User = getuser(svc.persistence, userid, teamname)
updateteamendpoint!(svc::NiancatService, teamname::AbstractString, uri::AbstractString) = updatenotificationendpoint!(svc.persistence, teamname, uri)

function Persistence.updatedisplayname!(svc::NiancatService, user::User, displayname::String)
    updatedisplayname!(svc.persistence, user, displayname)
end

# TODO The formatting is currently hard coded to Slack, so there's no need for an implementation of this.
#      But there should be an implementation of this.
updateformatting!(svc::NiancatService, teamname::AbstractString, formattername::AbstractString, language::AbstractString) = nothing

getformatter(svc::NiancatService, teamname::AbstractString) :: Formatter = SlackFormatter()

export NiancatService, findcommand, loadgameinstances!, declareinstance!, listinstancenames, newgame!
export getuser, updateteamendpoint!, updatedisplayname!
export updateformatting!, getformatter


text:
# by lazarusA # HIDE
# using GLMakie # HIDE
using GLMakie
GLMakie.activate!() # HIDE
let
    U = LinRange(-pi, pi, 100)
    V = LinRange(-pi, pi, 20)
    x1 = [cos(u) + .5 * cos(u) * cos(v)      for u in U, v in V]
    y1 = [sin(u) + .5 * sin(u) * cos(v)      for u in U, v in V]
    z1 = [.5 * sin(v)                        for u in U, v in V]
    x2 = [1 + cos(u) + .5 * cos(u) * cos(v)  for u in U, v in V]
    y2 = [.5 * sin(v)                        for u in U, v in V]
    z2 = [sin(u) + .5 * sin(u) * cos(v)      for u in U, v in V]

    fig = Figure(resolution =(1200,800))
    ax = LScene(fig, scenekw = (camera = cam3d!, show_axis = true))

    tori1 = surface!(ax, x1, y1, z1, colormap = :viridis, shading=false)
    tori2 = surface!(ax, x2, y2, z2, colormap = :plasma, shading=false)
    wireframe!(ax, x1, y1, z1, linewidth = 0.85)

    axis = ax.scene[OldAxis]
    axis[:names, :axisnames] = ("x", "y", "z")
    tstyle = axis[:names] #  get the nested attributes and work directly with them

    tstyle[:textsize] = 15
    tstyle[:textcolor] = (:red, :green, :black)
    tstyle[:font] = "helvetica"
    tstyle[:gap] = 10
    axis[:ticks][:textcolor] = :black
    axis[:ticks][:textsize] = 10
    cbar1 = Colorbar(fig, tori1, label = "z",width = 25, ticklabelsize = 30,
        labelsize = 30, ticksize=25, tickalign = 1, height = Relative(3/4)
    )
    cbar2 = Colorbar(fig, tori2, label = "z",width = 25, flipaxis = false,
        labelsize = 30, ticklabelsize = 30, ticksize=25, tickalign = 1,
        height = Relative(3/4))
    fig[1, 2] = ax
    fig[1, 3] = cbar1
    fig[1, 1] = cbar2
    colgap!(fig.layout, 2)
    fig
    save(joinpath(@__DIR__, "output", "wireSurfToris.png"), fig, px_per_unit = 2.0) # HIDE
end
using Pkg # HIDE
Pkg.status(["GLMakie"]) # HIDE

max_stars_repo_name: MisterBiggs/BeautifulMakie

max_issues_repo_name: MisterBiggs/BeautifulMakie

max_forks_repo_name: MisterBiggs/BeautifulMakie


text:
Base.@kwdef mutable struct ParamDesc
    name::String
    type::String
    default_value
    value
    desc::String = ""
    min = nothing
    max = nothing
end

function param_gui(desc, param_desc)
    quote
        if $param_desc.type == "Int"
            @cstatic v = Cint($param_desc.value) begin
                @c CImGui.InputInt($param_desc.name, &v)
                # if $param_desc.value === nothing
                #     v = Int32($param_desc.default_value)
                # end
                if isa($desc, ProblemDesc)
                    update_problem_desc($desc, nothing, $param_desc.name, v)
                elseif isa($desc, AlgorithmDesc)
                    update_algorithm_desc($desc, nothing, $param_desc.name, v)
                end
                CImGui.SameLine()
                HelpMarker($param_desc.desc)
            end
        end
    end
end


text:
import DataStructures:OrderedDict

typealias GtfHeader OrderedDict{ASCIIString, ASCIIString}

"""
http://asia.ensembl.org/info/website/upload/gff.html?redirect=no
    seqname - name of the chromosome or scaffold; chromosome names can be given with or without the 'chr' prefix. Important note: the seqname must be one used within Ensembl, i.e. a standard chromosome name or an Ensembl identifier such as a scaffold ID, without any additional content such as species or assembly. See the example GFF output below.
    source - name of the program that generated this feature, or the data source (database or project name)
    feature - feature type name, e.g. Gene, Variation, Similarity
    start - Start position of the feature, with sequence numbering starting at 1.
    end - End position of the feature, with sequence numbering starting at 1.
    score - A floating point value.
    strand - defined as + (forward) or - (reverse).
    frame - One of '0', '1' or '2'. '0' indicates that the first base of the feature is the first base of a codon, '1' that the second base is the first base of a codon, and so on..
    attribute - A semicolon-separated list of tag-value pairs, providing additional information about each feature.
"""

type GtfItem
    seqname::ASCIIString
    source::ASCIIString
    feature::ASCIIString
    start_pos::Int64
    end_pos::Int64
    score::ASCIIString
    strand::ASCIIString
    frame::ASCIIString
    attributes::OrderedDict{ASCIIString, ASCIIString}
end

typealias GtfData Array{GtfItem, 1}

type Gtf
    header::GtfHeader
    data::GtfData
end


text:
include("etcdserver.jl")

leader_prefix(etcd::EtcdServer,
              leader::String) = "http://$(etcd.ip):$(etcd.port)/mod/$(etcd.version)/leader/$(leader)"

function set_leader(etcd::EtcdServer,leader::String;
                    name::Union(String,Nothing)=nothing,
                    ttl::Union(Int,Nothing)=nothing)
    if is(name,nothing) && is(ttl,nothing)
        warn("Must specify a name and ttl for leader")
    else
        etcd_request(:put,leader_prefix(etcd,leader),
                    {"name"=>name,"ttl"=>ttl}) |>
        check_etcd_error
    end
end

function get_leader(etcd::EtcdServer,leader::String)
    etcd_request(:get,leader_prefix(etcd,leader)) |>
    check_etcd_error
end

function delete_leader(etcd::EtcdServer,leader::String;
                       name::Union(String,Nothing)=nothing)
    if is(name,nothing)
        warn("Must specify leader name for deletion")
    else
        etcd_request(:delete,leader_prefix(etcd,leader),{"name"=>name}) |>
        check_etcd_error
    end
end


text:
using RecipesBase

@recipe function f(triang::AbstractTriangulationPartition) where {D, T}
    simplices =
    legend --> false
    gridalpha --> 0.5
    foreground_color_grid --> :black
    for point in getpoints(triang)
        @series begin
            seriestype := :scatter
            ms --> 2,
            mc --> :black
            fc --> :black

            splitaxes(point)
        end
    end
    for simplex in getsimplices(triang)
        @series begin
            lc --> :black
            lw --> 0.8
            lα --> 0.8
            simplex
        end
    end
end