text:
# [
#  [ MPIStateArray Name, Field Name, Maximum, Minimum, Mean, Standard Deviation ],
#  [         :                :          :        :      :          :           ],
# ]

parr = [
    ["3D state", "u[1]", 12, 12, 0, 12],
    ["3D state", "u[2]", 0, 0, 0, 0],
    ["3D state", "η", 12, 12, 0, 12],
    ["3D state", "θ", 15, 15, 15, 15],
    ["3D aux", "y", 15, 15, 15, 15],
    ["3D aux", "w", 12, 12, 0, 12],
    ["3D aux", "pkin", 15, 15, 15, 15],
    ["3D aux", "wz0", 12, 12, 0, 12],
    ["3D aux", "uᵈ[1]", 12, 12, 0, 12],
    ["3D aux", "uᵈ[2]", 0, 0, 0, 0],
    ["3D aux", "ΔGᵘ[1]", 11, 11, 0, 12],
    ["3D aux", "ΔGᵘ[2]", 0, 0, 0, 0],
    ["2D state", "η", 12, 12, 0, 12],
    ["2D state", "U[1]", 12, 12, 0, 12],
    ["2D state", "U[2]", 0, 0, 0, 0],
    ["2D aux", "y", 15, 15, 15, 2],
    ["2D aux", "Gᵁ[1]", 11, 11, 0, 12],
    ["2D aux", "Gᵁ[2]", 0, 0, 0, 0],
    ["2D aux", "Δu[1]", 12, 12, 0, 12],
    ["2D aux", "Δu[2]", 0, 0, 0, 0],
]

uncoupled = [
    [
        "3D state",
        "u[1]",
        -9.58547428246830479637e-01,
        9.58547428246829258391e-01,
        -6.82121026329696195717e-18,
        4.45400655325317695876e-01,
    ],
    [
        "3D state",
        "u[2]",
        -4.13574641907576004779e-14,
        1.84325494853789287544e-14,
        1.94567057477529826177e-17,
        2.12815907156924710074e-15,
    ],
    [
        "3D state",
        "η",
        -8.52721734395889496838e-01,
        8.52834259382379111791e-01,
        2.18869899981655176688e-14,
        6.02983573168680453414e-01,
    ],
    [
        "3D state",
        "θ",
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
    ],
    [
        "3D aux",
        "y",
        0.00000000000000000000e+00,
        1.00000000000000011642e+06,
        5.00000000000000000000e+05,
        2.92775877460665535182e+05,
    ],
    [
        "3D aux",
        "w",
        -4.04489222828922911912e-04,
        4.04649979048336849198e-04,
        7.79376563286859913379e-19,
        1.63949585575251901345e-04,
    ],
    [
        "3D aux",
        "pkin",
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
    ],
    [
        "3D aux",
        "wz0",
        -2.00933099660541601228e-04,
        2.00809859469744893647e-04,
        2.62012633811536956698e-19,
        1.42064682697776552755e-04,
    ],
    [
        "3D aux",
        "uᵈ[1]",
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
    ],
    [
        "3D aux",
        "uᵈ[2]",
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
    ],
    [
        "3D aux",
        "ΔGᵘ[1]",
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
    ],
    [
        "3D aux",
        "ΔGᵘ[2]",
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
    ],
    [
        "2D state",
        "η",
        -8.52715894965927923010e-01,
        8.52861218874714666072e-01,
        -7.70938868299708696148e-16,
        6.03458382295490314284e-01,
    ],
    [
        "2D state",
        "U[1]",
        -3.15423945317149438949e+01,
        3.15423945317147342848e+01,
        1.42724412149908289268e-14,
        2.24262219407601044452e+01,
    ],
    [
        "2D state",
        "U[2]",
        -9.38673083374999972374e-13,
        1.16534781393478256382e-12,
        1.93385973223830695204e-14,
        2.16634164433978071172e-13,
    ],
    [
        "2D aux",
        "y",
        0.00000000000000000000e+00,
        1.00000000000000011642e+06,
        5.00000000000000000000e+05,
        2.92775877460665535182e+05,
    ],
    [
        "2D aux",
        "Gᵁ[1]",
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
    ],
    [
        "2D aux",
        "Gᵁ[2]",
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
    ],
    [
        "2D aux",
        "Δu[1]",
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
    ],
    [
        "2D aux",
        "Δu[2]",
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
    ],
]

coupled = [
    [
        "3D state",
        "u[1]",
        -9.58544854429326798062e-01,
        9.58544854429326798062e-01,
        -4.09272615797817732838e-17,
        4.45400401208546903309e-01,
    ],
    [
        "3D state",
        "u[2]",
        -4.09119364541065205420e-15,
        3.41954410407034240802e-15,
        1.57855184364031418231e-19,
        7.69982545727116047928e-16,
    ],
    [
        "3D state",
        "η",
        -8.52733075123627615177e-01,
        8.52843573070954374948e-01,
        7.27595761418342649852e-17,
        6.02992194663175995473e-01,
    ],
    [
        "3D state",
        "θ",
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
    ],
    [
        "3D aux",
        "y",
        0.00000000000000000000e+00,
        1.00000000000000011642e+06,
        5.00000000000000000000e+05,
        2.92775877460665535182e+05,
    ],
    [
        "3D aux",
        "w",
        -4.04456725919283483547e-04,
        4.04616610112968017130e-04,
        1.33892896769793873666e-18,
        1.63945200913093809460e-04,
    ],
    [
        "3D aux",
        "pkin",
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
    ],
    [
        "3D aux",
        "wz0",
        -2.00813442787548966564e-04,
        2.00686991710668984502e-04,
        1.68642877440561282675e-18,
        1.41979510156587984725e-04,
    ],
    [
        "3D aux",
        "uᵈ[1]",
        -8.79713597641291755735e-01,
        8.79713597641291200624e-01,
        -9.26547727431170607429e-17,
        4.41871673548253185437e-01,
    ],
    [
        "3D aux",
        "uᵈ[2]",
        -5.88884665747485312740e-28,
        6.47654803186450692243e-28,
        1.40221555861782666734e-30,
        4.22950073030020620100e-29,
    ],
    [
        "3D aux",
        "ΔGᵘ[1]",
        -1.50292385646252865781e-09,
        1.50292385640701573972e-09,
        -3.03178502810731714103e-21,
        6.72141424487058536370e-10,
    ],
    [
        "3D aux",
        "ΔGᵘ[2]",
        -2.50330922252795548175e-19,
        2.79421319642066487612e-19,
        8.87468518373638336981e-36,
        5.19465794381941235415e-20,
    ],
    [
        "2D state",
        "η",
        -8.52733075123627615177e-01,
        8.52843573070954374948e-01,
        1.61115565333602722195e-16,
        6.03463098440266798583e-01,
    ],
    [
        "2D state",
        "U[1]",
        -3.15402749945522060671e+01,
        3.15402749945527389741e+01,
        2.12974776703234167348e-14,
        2.24262621677375086904e+01,
    ],
    [
        "2D state",
        "U[2]",
        -1.63647745816416607002e-12,
        1.36781764162808076476e-12,
        6.31420737450488849608e-17,
        3.08233543917742288569e-13,
    ],
    [
        "2D aux",
        "y",
        0.00000000000000000000e+00,
        1.00000000000000011642e+06,
        5.00000000000000000000e+05,
        2.92775877460665535182e+05,
    ],
    [
        "2D aux",
        "Gᵁ[1]",
        -6.01169542562806285963e-07,
        6.01169542585011466433e-07,
        1.21270571032004377760e-18,
        2.69066532005499711718e-07,
    ],
    [
        "2D aux",
        "Gᵁ[2]",
        -1.11768527856826595815e-16,
        1.00132368901118217729e-16,
        -3.50057026691823957451e-33,
        2.07948587451660775232e-17,
    ],
    [
        "2D aux",
        "Δu[1]",
        -6.53936429129693404076e-04,
        6.53936429129569046087e-04,
        -2.70378337774435083119e-18,
        4.64975945389895016328e-04,
    ],
    [
        "2D aux",
        "Δu[2]",
        -3.76049176138251460297e-17,
        3.57641761985933683411e-17,
        -4.12443309266433447246e-19,
        7.09162842149286857838e-18,
    ],
]

thirty_minutes = [
    [
        "3D state",
        "u[1]",
        -9.58527737426365766815e-01,
        9.58527737426364989659e-01,
        -2.95585778076201651428e-17,
        4.45397585011924779241e-01,
    ],
    [
        "3D state",
        "u[2]",
        -3.91776258115697290002e-15,
        3.71573344368902785991e-15,
        9.99453214450878842160e-18,
        7.55533641450465537744e-16,
    ],
    [
        "3D state",
        "η",
        -8.52729582431237531637e-01,
        8.52830944991449846349e-01,
        -2.54658516496419884307e-16,
        6.02990141900936249542e-01,
    ],
    [
        "3D state",
        "θ",
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
    ],
    [
        "3D aux",
        "y",
        0.00000000000000000000e+00,
        1.00000000000000011642e+06,
        5.00000000000000000000e+05,
        2.92775877460665535182e+05,
    ],
    [
        "3D aux",
        "w",
        -4.06712181304362465229e-04,
        4.06869755985816939844e-04,
        9.07052211118752913371e-19,
        1.64290385445136678539e-04,
    ],
    [
        "3D aux",
        "pkin",
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
    ],
    [
        "3D aux",
        "wz0",
        -2.09003099782708142351e-04,
        2.08868143992394606845e-04,
        1.33781874467331362536e-18,
        1.47768608464728741676e-04,
    ],
    [
        "3D aux",
        "uᵈ[1]",
        -8.79792191807299950312e-01,
        8.79792191807298729067e-01,
        -9.54969436861574689412e-17,
        4.41911149114936674387e-01,
    ],
    [
        "3D aux",
        "uᵈ[2]",
        -4.49650715975976729085e-28,
        3.22939933074851707840e-28,
        1.28559371735991545201e-30,
        3.12162656228539824003e-29,
    ],
    [
        "3D aux",
        "ΔGᵘ[1]",
        -1.52356619979685413105e-09,
        1.52356619973800994984e-09,
        -3.00415481336788178489e-21,
        6.81373145706173027634e-10,
    ],
    [
        "3D aux",
        "ΔGᵘ[2]",
        -2.17115289587171316651e-19,
        2.99271337844227832879e-19,
        3.57452597678270976423e-36,
        5.23982958192948877053e-20,
    ],
    [
        "2D state",
        "η",
        -8.52729582431237531637e-01,
        8.52830944991449846349e-01,
        -3.20454773827805192348e-16,
        6.03461044074932395631e-01,
    ],
    [
        "2D state",
        "U[1]",
        -3.15407643291233448224e+01,
        3.15407643291237640426e+01,
        2.30678864898692384736e-14,
        2.24265574817805202201e+01,
    ],
    [
        "2D state",
        "U[2]",
        -1.56710503246274425174e-12,
        1.48629337747559491236e-12,
        3.99781285780299048032e-15,
        3.02449468686897625244e-13,
    ],
    [
        "2D aux",
        "y",
        0.00000000000000000000e+00,
        1.00000000000000011642e+06,
        5.00000000000000000000e+05,
        2.92775877460665535182e+05,
    ],
    [
        "2D aux",
        "Gᵁ[1]",
        -6.09426479895203986555e-07,
        6.09426479918741655731e-07,
        1.20165633492970096897e-18,
        2.72762104279987029506e-07,
    ],
    [
        "2D aux",
        "Gᵁ[2]",
        -1.19708535137691129300e-16,
        8.68461158348685235787e-17,
        -1.50869648123518501517e-33,
        2.09756864038773538444e-17,
    ],
    [
        "2D aux",
        "Δu[1]",
        -3.89449877638695009935e-03,
        3.89449877638627485824e-03,
        -2.02396849009311295664e-17,
        2.76903473119681107703e-03,
    ],
    [
        "2D aux",
        "Δu[2]",
        -2.13991366909841745553e-16,
        2.02991354131742782465e-16,
        -1.26781868574011981865e-18,
        4.34606820130057938426e-17,
    ],
]

sixty_minutes = [
    [
        "3D state",
        "u[1]",
        -9.58507705628042327994e-01,
        9.58507705628042550039e-01,
        -5.22959453519433752618e-17,
        4.45394100308371843067e-01,
    ],
    [
        "3D state",
        "u[2]",
        -4.09893498131451878178e-15,
        3.66595063838075513859e-15,
        3.52058149555652693147e-18,
        7.65972478919525466697e-16,
    ],
    [
        "3D state",
        "η",
        -8.52715753705294066123e-01,
        8.52819886810596838878e-01,
        0.00000000000000000000e+00,
        6.02986351734545844572e-01,
    ],
    [
        "3D state",
        "θ",
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
    ],
    [
        "3D aux",
        "y",
        0.00000000000000000000e+00,
        1.00000000000000011642e+06,
        5.00000000000000000000e+05,
        2.92775877460665535182e+05,
    ],
    [
        "3D aux",
        "w",
        -4.09355343664679748733e-04,
        4.09526445665209497954e-04,
        8.01581023779363006131e-19,
        1.64782726593626366188e-04,
    ],
    [
        "3D aux",
        "pkin",
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
    ],
    [
        "3D aux",
        "wz0",
        -2.18597874938533713813e-04,
        2.18512725277962983460e-04,
        1.16684439888103955116e-18,
        1.54581525183602542031e-04,
    ],
    [
        "3D aux",
        "uᵈ[1]",
        -8.79886113674857694988e-01,
        8.79886113674856806810e-01,
        -8.81072992342524199517e-17,
        4.41958323665245178535e-01,
    ],
    [
        "3D aux",
        "uᵈ[2]",
        -5.04476548888837049561e-28,
        4.09418809809705127009e-28,
        1.53142189509630563206e-30,
        3.27579623353337388378e-29,
    ],
    [
        "3D aux",
        "ΔGᵘ[1]",
        -1.12461707299293835875e-09,
        1.12461707291060059378e-09,
        -2.89803852573586336546e-21,
        5.02954103857782471789e-10,
    ],
    [
        "3D aux",
        "ΔGᵘ[2]",
        -2.29220407034248886795e-19,
        3.23795504633739099693e-19,
        4.19082355898662551731e-36,
        5.50021671320874203932e-20,
    ],
    [
        "2D state",
        "η",
        -8.52715753705294066123e-01,
        8.52819886810596838878e-01,
        -2.04281036531028799987e-17,
        6.03457250948630341547e-01,
    ],
    [
        "2D state",
        "U[1]",
        -3.15415180428826182890e+01,
        3.15415180428829948767e+01,
        1.77902803599749859788e-14,
        2.24265293235027023400e+01,
    ],
    [
        "2D state",
        "U[2]",
        -1.63957399252576030728e-12,
        1.46638025535227397199e-12,
        1.40823259822193190848e-15,
        3.06628264537953242560e-13,
    ],
    [
        "2D aux",
        "y",
        0.00000000000000000000e+00,
        1.00000000000000011642e+06,
        5.00000000000000000000e+05,
        2.92775877460665535182e+05,
    ],
    [
        "2D aux",
        "Gᵁ[1]",
        -4.49846829164240224277e-07,
        4.49846829197175353425e-07,
        1.15921837490966064206e-18,
        2.01338753352722549629e-07,
    ],
    [
        "2D aux",
        "Gᵁ[2]",
        -1.29518201853495637566e-16,
        9.16881628136995516365e-17,
        -2.08062063752041870574e-33,
        2.20180483211723137251e-17,
    ],
    [
        "2D aux",
        "Δu[1]",
        -7.71677156339491132631e-03,
        7.71677156339359640591e-03,
        -2.97775205101297201914e-17,
        5.48673197909435757247e-03,
    ],
    [
        "2D aux",
        "Δu[2]",
        -5.01794629524824969143e-16,
        5.51655281127317078031e-16,
        3.20748218455203547025e-18,
        9.36761976343254920594e-17,
    ],
]

ninety_minutes = [
    [
        "3D state",
        "u[1]",
        -9.58488051495743675900e-01,
        9.58488051495742121588e-01,
        2.50111042987555274331e-17,
        4.45390687454859546257e-01,
    ],
    [
        "3D state",
        "u[2]",
        -1.23989905776825655281e-15,
        1.61970487656192169626e-15,
        3.83419479315953585092e-17,
        3.55219724018798369983e-16,
    ],
    [
        "3D state",
        "η",
        -8.52731405452109680887e-01,
        8.52809353848989926128e-01,
        -2.45563569478690627377e-16,
        6.02988963894262375298e-01,
    ],
    [
        "3D state",
        "θ",
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
    ],
    [
        "3D aux",
        "y",
        0.00000000000000000000e+00,
        1.00000000000000011642e+06,
        5.00000000000000000000e+05,
        2.92775877460665535182e+05,
    ],
    [
        "3D aux",
        "w",
        -4.11959288170071617242e-04,
        4.12126623290091649143e-04,
        -2.00395255944840751533e-19,
        1.65355949740609838115e-04,
    ],
    [
        "3D aux",
        "pkin",
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
        0.00000000000000000000e+00,
    ],
    [
        "3D aux",
        "wz0",
        -2.28048874139989487609e-04,
        2.27949849600796259491e-04,
        -3.35287353436797287965e-19,
        1.61271245461141072295e-04,
    ],
    [
        "3D aux",
        "uᵈ[1]",
        -8.79979607451056078382e-01,
        8.79979607451055745315e-01,
        -2.84217094304040087969e-18,
        4.42005283454923181274e-01,
    ],
    [
        "3D aux",
        "uᵈ[2]",
        -2.89610559829263959062e-28,
        2.76495747279964637797e-28,
        -2.23087062731398024379e-31,
        2.03879747098428489165e-29,
    ],
    [
        "3D aux",
        "ΔGᵘ[1]",
        -8.86991425991573654091e-10,
        8.86991425890194811807e-10,
        -2.95809316169619294608e-22,
        3.96682558403758137461e-10,
    ],
    [
        "3D aux",
        "ΔGᵘ[2]",
        -1.46453678699776496163e-19,
        1.78310815453102811486e-19,
        3.45126646034192634633e-36,
        3.36942772885638802169e-20,
    ],
    [
        "2D state",
        "η",
        -8.52731405452109680887e-01,
        8.52809353848989926128e-01,
        -2.24886775868071691631e-16,
        6.03459865148300189652e-01,
    ],
    [
        "2D state",
        "U[1]",
        -3.15423820746574818941e+01,
        3.15423820746572900475e+01,
        1.25987324739451618828e-14,
        2.24266774102466719398e+01,
    ],
    [
        "2D state",
        "U[2]",
        -4.95959623107294663097e-13,
        6.47881950624733081946e-13,
        1.53367791726381670695e-14,
        1.42198852443335733848e-13,
    ],
    [
        "2D aux",
        "y",
        0.00000000000000000000e+00,
        1.00000000000000011642e+06,
        5.00000000000000000000e+05,
        2.93004519336559635121e+05,
    ],
    [
        "2D aux",
        "Gᵁ[1]",
        -3.54796570356077906525e-07,
        3.54796570396629450056e-07,
        1.18322201808542668922e-19,
        1.58796938275634264439e-07,
    ],
    [
        "2D aux",
        "Gᵁ[2]",
        -7.13243261812411242092e-17,
        5.85814714799106030876e-17,
        -1.27696859032651283100e-33,
        1.34882362672174716756e-17,
    ],
    [
        "2D aux",
        "Δu[1]",
        -1.14629123365972158261e-02,
        1.14629123365972678678e-02,
        2.41175081207994926868e-18,
        8.15149713200666835300e-03,
    ],
    [
        "2D aux",
        "Δu[2]",
        -7.92579521344275918936e-16,
        6.08374854985514025679e-16,
        -3.41928350044524220733e-18,
        1.39041335489639128848e-16,
    ],
]

refVals = (
    uncoupled = (uncoupled, parr),
    coupled = (coupled, parr),
    thirty_minutes = (thirty_minutes, parr),
    sixty_minutes = (sixty_minutes, parr),
    ninety_minutes = (ninety_minutes, parr),
)


text:
#ENV["CUDA_VISIBLE_DEVICES"] = "0,1,2,3,4,5,6,7"
#using Revise
using ADSeismic
using ADCME
using PyPlot
using MAT
using DelimitedFiles
matplotlib.use("Agg")
close("all")

gpu = has_gpu() ? true : false

output_dir = "data/acoustic"

check_path(dir) = !ispath(dir) ? mkpath(dir) : nothing
check_path(output_dir)

################### Generate synthetic data #####################
reset_default_graph()
model_name = "models/marmousi2-model-true.mat"
# model_name = "models/marmousi2-model-true-large.mat"
# model_name = "models/BP-model-true.mat"

## load model setting
params = load_params(model_name, vp_ref=1e3)
src = load_acoustic_source(model_name)
rcv = load_acoustic_receiver(model_name)
vp = constant(matread(model_name)["vp"])
## For debug, only run the first source
# src = [src[1]]
# rcv = [rcv[1]]

## assemble acoustic propagator model
model = x->AcousticPropagatorSolver(params, x, vp)

## simulated wavefield
if gpu
  Rs_ = compute_forward_GPU(model, src, rcv)
else
  [SimulatedObservation!(model(src[i]), rcv[i]) for i = 1:length(src)]
  Rs_ = [rcv[i].rcvv for i = 1:length(rcv)]
end
sess = Session(); init(sess)
Rs = run(sess, Rs_)

## save results
for i = 1:length(src)
    writedlm(joinpath(output_dir, "marmousi-r$i.txt"), Rs[i])
    # writedlm(joinpath(output_dir, "BP-r$i.txt"), Rs[i])
end
@info "Data written."

## visualize_wavefield if needed
ii = 1 # source number
u = run(sess, model(src[ii]).u)
p = visualize_wavefield(u, params)
saveanim(p, "marmousi-wavefield.gif")

ext: jl


text:
using ObjectFile
using Test

@testset "basic" begin
    # Test that an empty file is a magic mismatch
    mktempdir() do dir
        fpath = joinpath(dir, "empty")
        touch(fpath)
        @test_throws MagicMismatch readmeta(fpath) do oh
            @test false
        end
    end
end

function test_libfoo_and_fooifier(fooifier_path, libfoo_path)
    # Actually read it in
    oh_exe = readmeta(open(fooifier_path, "r"))
    oh_lib = readmeta(open(libfoo_path, "r"))

    # Tease out some information from the containing folder name
    dir_path = basename(dirname(libfoo_path))
    types = Dict(
        "linux" => ELFHandle,
        "mac" => MachOHandle,
        "win" => COFFHandle,
    )

    platform = dir_path[1:end-2]
    H = types[platform]
    bits = dir_path[end-1:end]

    @testset "$(dir_path)" begin
        @testset "General Properties" begin
            for oh in (oh_exe, oh_lib)
                # Test that we got the right type
                @test typeof(oh) <: H

                # Test that we got the right number of bits
                @test is64bit(oh) == (bits == "64")

                # Everything is always little endian
                @test endianness(oh) == :LittleEndian
            end

            # None of these are .o files
            @test !isrelocatable(oh_exe)
            @test !isrelocatable(oh_lib)

            # Ensure these are the kinds of files we thought they were
            @test isexecutable(oh_exe)
            @test islibrary(oh_lib)
            @test isdynamic(oh_exe) && isdynamic(oh_lib)
        end

        @testset "Dynamic Linking" begin
            # Ensure that `dir_path` is one of the RPath entries
            rpath = RPath(oh_exe)
            can_paths = canonical_rpaths(rpath)
            @test abspath(dir_path * Base.Filesystem.path_separator) in can_paths

            # Ensure that `fooifier` is going to try to load `libfoo`:
            foo_libs = find_libraries(oh_exe)
            @test !isempty(foo_libs)
            @test abspath(libfoo_path) in values(foo_libs)
        end

        # Ensure that `foo()` is referenced in both, defined in `libfoo`, and
        # not defined in `fooifier`.  Also ensure that `_main` is defined in
        # `fooifier` and is not present in `libfoo`.
        @testset "Symbols" begin
            syms_exe = collect(Symbols(oh_exe))
            syms_lib = collect(Symbols(oh_lib))

            syms_names_exe = symbol_name.(syms_exe)
            syms_names_lib = symbol_name.(syms_lib)

            # ELF stores the symbol name as "foo", MachO stores it as "_foo"
            foo_sym_name = mangle_symbol_name(oh_exe, "foo")
            main_sym_name = mangle_symbol_name(oh_exe, "main")

            @test foo_sym_name in syms_names_exe
            @test foo_sym_name in syms_names_lib
            @test main_sym_name in syms_names_exe
            @test !(main_sym_name in syms_names_lib)

            foo_idx_exe = findfirst(syms_names_exe .== foo_sym_name)
            main_idx_exe = findfirst(syms_names_exe .== main_sym_name)
            foo_idx_lib = findfirst(syms_names_lib .== foo_sym_name)

            @test foo_idx_exe != 0
            @test main_idx_exe != 0
            @test foo_idx_lib != 0

            # definedness doesn't seem to be for COFF files...
            if !isa(oh_exe, COFFHandle)
                @test isundef(syms_exe[foo_idx_exe])
                @test !isundef(syms_exe[main_idx_exe])
                @test !isundef(syms_lib[foo_idx_lib])
            end

            @test !islocal(syms_exe[foo_idx_exe])
            @test !islocal(syms_exe[main_idx_exe])
            @test !islocal(syms_lib[foo_idx_lib])

            # Global detection doesn't seem to be working on OSX...
            if !isa(oh_exe, MachOHandle)
                @test isglobal(syms_exe[foo_idx_exe])
                @test isglobal(syms_exe[main_idx_exe])
                @test isglobal(syms_lib[foo_idx_lib])
            end
        end

        @testset "Printing" begin
            # Print out to an IOContext that will limit long lists
            io = IOContext(stdout, :limit => true)

            # Helper that shows the type, then the value:
            function tshow(x)
                type_name = typeof(x).name.name
                println(io, "INFO: Showing $(type_name)")
                show(io, x)
                print(io, "\n")
            end

            # Show printing of a Handle
            tshow(oh_lib)

            # Test showing of the header
            tshow(header(oh_lib))

            # Test showing of Sections
            sects = Sections(oh_exe)
            tshow(sects)
            tshow(sects[1])

            # Test showing of Segments on non-COFF
            if !isa(oh_exe, COFFHandle)
                segs = Segments(oh_lib)
                tshow(segs)
                tshow(segs[1])
            end

            # Test showing of Symbols
            syms = Symbols(oh_exe)
            tshow(syms)
            tshow(syms[1])

            # Test showing of RPath and DynamicLinks
            rpath = RPath(oh_exe)
            tshow(rpath)

            dls = DynamicLinks(oh_exe)
            tshow(dls)
            tshow(dls[1])
        end
    end
end

# Run ELF tests
test_libfoo_and_fooifier("./linux32/fooifier", "./linux32/libfoo.so")
test_libfoo_and_fooifier("./linux64/fooifier", "./linux64/libfoo.so")

# Run MachO tests
test_libfoo_and_fooifier("./mac64/fooifier", "./mac64/libfoo.dylib")

# Ensure that fat Mach-O files don't look like anything to us
@testset "macfat" begin
    @test_throws ObjectFile.MagicMismatch readmeta(open("./macfat/fooifier","r"))
    @test_throws ObjectFile.MagicMismatch readmeta(open("./macfat/libfoo.dylib","r"))
end

# Run COFF tests
test_libfoo_and_fooifier("./win32/fooifier.exe", "./win32/libfoo.dll")
test_libfoo_and_fooifier("./win64/fooifier.exe", "./win64/libfoo.dll")

# Ensure that ELF version stuff works
@testset "ELF Version Info Parsing" begin
    libstdcxx_path = "./linux64/libstdc++.so.6"

    # Extract all pieces of `.gnu.version_d` from libstdc++.so, find the `GLIBCXX_*`
    # symbols, and use the maximum version of that to find the GLIBCXX ABI version number
    version_symbols = readmeta(libstdcxx_path) do oh
        unique(vcat((x -> x.names).(ObjectFile.ELF.ELFVersionData(oh))...))
    end
    version_symbols = filter(x -> startswith(x, "GLIBCXX_"), version_symbols)
    max_version = maximum([VersionNumber(split(v, "_")[2]) for v in version_symbols])
    @test max_version == v"3.4.25"
end

# Ensure that these tricksy win32 files work
@testset "git win32 problems" begin
    # Test that 6a66694a8dd5ca85bd96fe6236f21d5b183e7de6 fix worked
    libmsobj_path = "./win32/msobj140.dll"

    dynamic_links = readmeta(libmsobj_path) do oh
        path.(DynamicLinks(oh))
    end

    @test "KERNEL32.dll" in dynamic_links
    @test "api-ms-win-crt-heap-l1-1-0.dll" in dynamic_links
    @test "api-ms-win-crt-convert-l1-1-0.dll" in dynamic_links
    @test "api-ms-win-crt-runtime-l1-1-0.dll" in dynamic_links

    whouses_exe = "./win32/WhoUses.exe"
    dynamic_links = readmeta(whouses_exe) do oh
        path.(DynamicLinks(oh))
    end

    @test "ADVAPI32.dll" in dynamic_links
    @test "KERNEL32.dll" in dynamic_links
    @test "libstdc++-6.dll" in dynamic_links
end


text:
const MINVAL = 1.0e-15
const PI = 3.141592653589793
const MAXVAL = 1.0e10
const MINMU = 1.0e-5
const MINIMP = 0.0001
const MAXIMP = 0.9999
const MAXCONPAIR = 50
const MAXVFS = 200
const MAXVFSNAME = 100

const NEQDATA = 7
const NDYN = 10
const NGAIN = 10
const NBIAS = 10
const NREF = 2
const NIMP = 5
const NSOLVER = 1000

@enum mjtDisableBit begin             # disable default feature bitflags
    DSBL_CONSTRAINT   = 1<<0   # entire constraint solver
    DSBL_EQUALITY     = 1<<1   # equality constraints
    DSBL_FRICTIONLOSS = 1<<2   # joint and tendon frictionloss constraints
    DSBL_LIMIT        = 1<<3   # joint and tendon limit constraints
    DSBL_CONTACT      = 1<<4   # contact constraints
    DSBL_PASSIVE      = 1<<5   # passive forces
    DSBL_GRAVITY      = 1<<6   # gravitational forces
    DSBL_CLAMPCTRL    = 1<<7   # clamp control to specified range
    DSBL_WARMSTART    = 1<<8   # warmstart constraint solver
    DSBL_FILTERPARENT = 1<<9   # remove collisions with parent body
    DSBL_ACTUATION    = 1<<10  # apply actuation forces
    DSBL_REFSAFE      = 1<<11  # integrator safety: make ref[0]>=2*timestep

    NDISABLE          = 12     # number of disable flags
end

@enum mjtEnableBit begin              # enable optional feature bitflags
    ENBL_OVERRIDE     = 1<<0   # override contact parameters
    ENBL_ENERGY       = 1<<1   # energy computation
    ENBL_FWDINV       = 1<<2   # record solver statistics
    ENBL_SENSORNOISE  = 1<<3   # add noise to sensor data

    #NENABLE           = 4      # number of enable flags
end
const NENABLE = 4

@enum mjtJoint begin                  # type of degree of freedom
    JNT_FREE          = 0      # global position and orientation (quat)       (7)
    JNT_BALL                   # orientation (quat) relative to parent        (4)
    JNT_SLIDE                  # sliding distance along body-fixed axis       (1)
    JNT_HINGE                  # rotation angle (rad) around body-fixed axis  (1)
end

@enum mjtGeom begin                   # type of geometric shape
                                 # regular geom types
    GEOM_PLANE        = 0      # plane
    GEOM_HFIELD                # height field
    GEOM_SPHERE                # sphere
    GEOM_CAPSULE               # capsule
    GEOM_ELLIPSOID             # ellipsoid
    GEOM_CYLINDER              # cylinder
    GEOM_BOX                   # box
    GEOM_MESH                  # mesh

    NGEOMTYPES                 # number of regular geom types

                               # rendering-only geom types: not used in mjModel not counted in mjNGEOMTYPES
    GEOM_ARROW        = 100    # arrow
    GEOM_ARROW1                # arrow without wedges
    GEOM_ARROW2                # arrow in both directions
    GEOM_LINE                  # line
    GEOM_SKIN                  # skin
    GEOM_LABEL                 # text label

    GEOM_NONE         = 1001   # missing geom type
end

@enum mjtCamLight begin               # tracking mode for camera and light
    CAMLIGHT_FIXED    = 0      # pos and rot fixed in body
    CAMLIGHT_TRACK             # pos tracks body, rot fixed in global
    CAMLIGHT_TRACKCOM          # pos tracks subtree com, rot fixed in body
    CAMLIGHT_TARGETBODY        # pos fixed in body, rot tracks target body
    CAMLIGHT_TARGETBODYCOM     # pos fixed in body rot tracks target subtree com
end

@enum mjtTexture begin                # type of texture
    TEXTURE_2D        = 0      # 2d texture, suitable for planes and hfields
    TEXTURE_CUBE               # cube texture, suitable for all other geom types
    TEXTURE_SKYBOX             # cube texture used as skybox
end

@enum mjtIntegrator begin             # integrator mode
    INT_EULER         = 0      # semi-implicit Euler
    INT_RK4                    # 4th-order Runge Kutta
end

@enum mjtCollision begin              # collision mode for selecting geom pairs
    COL_ALL           = 0      # test precomputed and dynamic pairs
    COL_PAIR                   # test predefined pairs only
    COL_DYNAMIC                # test dynamic pairs only
end

@enum mjtCone begin                   # type of friction cone
    CONE_PYRAMIDAL     = 0     # pyramidal
    CONE_ELLIPTIC              # elliptic
end

@enum mjtJacobian begin               # type of constraint Jacobian
    JAC_DENSE          = 0     # dense
    JAC_SPARSE                 # sparse
    JAC_AUTO                   # dense if nv<60 sparse otherwise
end

@enum mjtSolver begin                 # constraint solver algorithm
    SOL_PGS            = 0     # PGS    (dual)
    SOL_CG                     # CG     (primal)
    SOL_NEWTON                 # Newton (primal)
end

@enum mjtEq begin                     # type of equality constraint
    EQ_CONNECT        = 0      # connect two bodies at a point (ball joint)
    EQ_WELD                    # fix relative position and orientation of two bodies
    EQ_JOINT                   # couple the values of two scalar joints with cubic
    EQ_TENDON                  # couple the lengths of two tendons with cubic
    EQ_DISTANCE                # fix the contact distance betweent two geoms
end

@enum mjtWrap begin                   # type of tendon wrap object
    WRAP_NONE         = 0      # null object
    WRAP_JOINT                 # constant moment arm
    WRAP_PULLEY                # pulley used to split tendon
    WRAP_SITE                  # pass through site
    WRAP_SPHERE                # wrap around sphere
    WRAP_CYLINDER              # wrap around (infinite) cylinder
end

@enum mjtTrn begin                    # type of actuator transmission
    TRN_JOINT         = 0      # force on joint
    TRN_JOINTINPARENT          # force on joint, expressed in parent frame
    TRN_SLIDERCRANK            # force via slider-crank linkage
    TRN_TENDON                 # force on tendon
    TRN_SITE                   # force on site

    TRN_UNDEFINED     = 1000   # undefined transmission type
end

@enum mjtDyn begin                    # type of actuator dynamics
    DYN_NONE          = 0      # no internal dynamics; ctrl specifies force
    DYN_INTEGRATOR             # integrator: da/dt = u
    DYN_FILTER                 # linear filter: da/dt = (u-a) / tau
    DYN_MUSCLE                 # piece-wise linear filter with two time constants
    DYN_USER                   # user-defined dynamics type
end

@enum mjtGain begin                   # type of actuator gain
    GAIN_FIXED        = 0      # fixed gain
    GAIN_MUSCLE                # muscle FLV curve computed by mju_muscleGain()
    GAIN_USER                  # user-defined gain type
end

@enum mjtBias begin                   # type of actuator bias
    BIAS_NONE         = 0      # no bias
    BIAS_AFFINE                # const + kp*length + kv*velocity
    BIAS_MUSCLE                # muscle passive force computed by mju_muscleBias()
    BIAS_USER                  # user-defined bias type
end

@enum mjtObj begin                    # type of MujoCo object
    OBJ_UNKNOWN       = 0      # unknown object type
    OBJ_BODY                   # body
    OBJ_XBODY                  # body, used to access regular frame instead of i-frame
    OBJ_JOINT                  # joint
    OBJ_DOF                    # dof
    OBJ_GEOM                   # geom
    OBJ_SITE                   # site
    OBJ_CAMERA                 # camera
    OBJ_LIGHT                  # light
    OBJ_MESH                   # mesh
    OBJ_SKIN                   # skin
    OBJ_HFIELD                 # heightfield
    OBJ_TEXTURE                # texture
    OBJ_MATERIAL               # material for rendering
    OBJ_PAIR                   # geom pair to include
    OBJ_EXCLUDE                # body pair to exclude
    OBJ_EQUALITY               # equality constraint
    OBJ_TENDON                 # tendon
    OBJ_ACTUATOR               # actuator
    OBJ_SENSOR                 # sensor
    OBJ_NUMERIC                # numeric
    OBJ_TEXT                   # text
    OBJ_TUPLE                  # tuple
    OBJ_KEY                    # keyframe
end

@enum mjtConstraint begin             # type of constraint
    CNSTR_EQUALITY    = 0      # equality constraint
    CNSTR_FRICTION_DOF         # dof friction
    CNSTR_FRICTION_TENDON      # tendon friction
    CNSTR_LIMIT_JOINT          # joint limit
    CNSTR_LIMIT_TENDON         # tendon limit
    CNSTR_CONTACT_FRICTIONLESS # frictionless contact
    CNSTR_CONTACT_PYRAMIDAL    # frictional contact, pyramidal friction cone
    CNSTR_CONTACT_ELLIPTIC     # frictional contact elliptic friction cone
end

@enum mjtConstraintState begin        # constraint state
    CNSTRSTATE_SATISFIED = 0   # constraint satisfied, zero cost (limit, contact)
    CNSTRSTATE_QUADRATIC       # quadratic cost (equality, friction, limit, contact)
    CNSTRSTATE_LINEARNEG       # linear cost, negative side (friction)
    CNSTRSTATE_LINEARPOS       # linear cost, positive side (friction)
    CNSTRSTATE_CONE            # squared distance to cone cost (elliptic contact)
end

@enum mjtSensor begin                 # type of sensor
                                 # common robotic sensors attached to a site
    SENS_TOUCH        = 0      # scalar contact normal forces summed over sensor zone
    SENS_ACCELEROMETER         # 3D linear acceleration, in local frame
    SENS_VELOCIMETER           # 3D linear velocity, in local frame
    SENS_GYRO                  # 3D angular velocity, in local frame
    SENS_FORCE                 # 3D force between site's body and its parent body
    SENS_TORQUE                # 3D torque between site's body and its parent body
    SENS_MAGNETOMETER          # 3D magnetometer
    SENS_RANGEFINDER           # scalar distance to nearest geom or site along z-axis

                               # sensors related to scalar joints tendons, actuators
    SENS_JOINTPOS              # scalar joint position (hinge and slide only)
    SENS_JOINTVEL              # scalar joint velocity (hinge and slide only)
    SENS_TENDONPOS             # scalar tendon position
    SENS_TENDONVEL             # scalar tendon velocity
    SENS_ACTUATORPOS           # scalar actuator position
    SENS_ACTUATORVEL           # scalar actuator velocity
    SENS_ACTUATORFRC           # scalar actuator force

                               # sensors related to ball joints
    SENS_BALLQUAT              # 4D ball joint quaterion
    SENS_BALLANGVEL            # 3D ball joint angular velocity

                               # joint and tendon limit sensors in constraint space
    SENS_JOINTLIMITPOS         # joint limit distance-margin
    SENS_JOINTLIMITVEL         # joint limit velocity
    SENS_JOINTLIMITFRC         # joint limit force
    SENS_TENDONLIMITPOS        # tendon limit distance-margin
    SENS_TENDONLIMITVEL        # tendon limit velocity
    SENS_TENDONLIMITFRC        # tendon limit force

                               # sensors attached to an object with spatial frame: (x)body geom, site, camera
    SENS_FRAMEPOS              # 3D position
    SENS_FRAMEQUAT             # 4D unit quaternion orientation
    SENS_FRAMEXAXIS            # 3D unit vector: x-axis of object's frame
    SENS_FRAMEYAXIS            # 3D unit vector: y-axis of object's frame
    SENS_FRAMEZAXIS            # 3D unit vector: z-axis of object's frame
    SENS_FRAMELINVEL           # 3D linear velocity
    SENS_FRAMEANGVEL           # 3D angular velocity
    SENS_FRAMELINACC           # 3D linear acceleration
    SENS_FRAMEANGACC           # 3D angular acceleration

                               # sensors related to kinematic subtrees; attached to a body (which is the subtree root)
    SENS_SUBTREECOM            # 3D center of mass of subtree
    SENS_SUBTREELINVEL         # 3D linear velocity of subtree
    SENS_SUBTREEANGMOM         # 3D angular momentum of subtree

                               # user-defined sensor
    SENS_USER                  # sensor data provided by mjcb_sensor callback
end

@enum mjtStage begin                  # computation stage
    STAGE_NONE        = 0      # no computations
    STAGE_POS                  # position-dependent computations
    STAGE_VEL                  # velocity-dependent computations
    STAGE_ACC                  # acceleration/force-dependent computations
end

@enum mjtDataType begin               # data type for sensors
    DATATYPE_REAL     = 0      # real values, no constraints
    DATATYPE_POSITIVE          # positive values; 0 or negative: inactive
    DATATYPE_AXIS              # 3D unit vector
    DATATYPE_QUATERNION        # unit quaternion
end

@enum mjtLRMode begin                 # mode for actuator length range computation
    LRMODE_NONE   = 0          # do not process any actuators
    LRMODE_MUSCLE              # process muscle actuators
    LRMODE_MUSCLEUSER          # process muscle and user actuators
    LRMODE_ALL                 # process all actuators
end

#------------------------------ mjLROpt ------------------------------------------------

struct mjLROpt         # options for mj_setLengthRange()
                     # flags
   mode              # which actuators to process (mjtLRMode)
   useexisting::Cint # use existing length range if available
   uselimit::Cint    # use joint and tendon limits if available

                     # algorithm parameters
   accel::mjtNum     # target acceleration used to compute force
   maxforce::mjtNum  # maximum force 0: no limit
   timeconst::mjtNum # time constant for velocity reduction min 0.01
   timestep::mjtNum  # simulation timestep 0: use mjOption.timestep
   inttotal::mjtNum  # total simulation time interval
   inteval::mjtNum   # evaluation time interval (at the end)
   tolrange::mjtNum  # convergence tolerance (relative to range)
end

struct mjVFS
   nfile::Cint
   filename::SVector{MAXVFS, SVector{MAXVFSNAME, UInt8}}
   filesize::SVector{MAXVFS, Cint}
   filedata::SVector{MAXVFS, Ptr{Cvoid}}
end

struct mjOption
   timestep::mjtNum
   apirate::mjtNum

   impratio::mjtNum
   tolerance::mjtNum
   noslip_tolerance::mjtNum
   mpr_tolerance::mjtNum

   gravity::SVector{3, mjtNum}
   wind::SVector{3, mjtNum}
   magnetic::SVector{3, mjtNum}
   density::mjtNum
   viscosity::mjtNum

   o_margin::mjtNum
   o_solref::SVector{NREF, mjtNum}
   o_solimp::SVector{NIMP, mjtNum}

   integrator::Cint
   collision::Cint
   cone::Cint
   jacobian::Cint
   solver::Cint
   iterations::Cint
   noslip_iterations::Cint
   mpr_iterations::Cint
   disableflags::Cint
   enableflags::Cint
end

struct _global
	fovy::Cfloat
	ipd::Cfloat
	linewidth::Cfloat
	glow::Cfloat
	offwidth::Cint
	offheight::Cint
end

struct quality
	shadowsize::Cint
	offsamples::Cint
	numslices::Cint
	numstacks::Cint
	numquads::Cint
end

struct headlight
   ambient::SVector{3, Cfloat}
   diffuse::SVector{3, Cfloat}
   specular::SVector{3, Cfloat}
	active::Cint
end

struct map
	stiffness::Cfloat
	stiffnessrot::Cfloat
	force::Cfloat
	torque::Cfloat
	alpha::Cfloat
	fogstart::Cfloat
	fogend::Cfloat
	znear::Cfloat
	zfar::Cfloat
	haze::Cfloat
	shadowclip::Cfloat
	shadowscale::Cfloat
	actuatortendon::Cfloat
end

struct scale
	forcewidth::Cfloat
	contactwidth::Cfloat
	contactheight::Cfloat
	connect::Cfloat
	com::Cfloat
	camera::Cfloat
	light::Cfloat
	selectpoint::Cfloat
	jointlength::Cfloat
	jointwidth::Cfloat
	actuatorlength::Cfloat
	actuatorwidth::Cfloat
	framelength::Cfloat
	framewidth::Cfloat
	constraint::Cfloat
	slidercrank::Cfloat
end

struct rgba
	fog::SVector{4, Cfloat}
	haze::SVector{4, Cfloat}
	force::SVector{4, Cfloat}
	inertia::SVector{4, Cfloat}
	joint::SVector{4, Cfloat}
	actuator::SVector{4, Cfloat}
	actuatornegative::SVector{4, Cfloat}
	actuatorpositive::SVector{4, Cfloat}
	com::SVector{4, Cfloat}
	camera::SVector{4, Cfloat}
	light::SVector{4, Cfloat}
	selectpoint::SVector{4, Cfloat}
	connect::SVector{4, Cfloat}
	contactpoint::SVector{4, Cfloat}
	contactforce::SVector{4, Cfloat}
	contactfriction::SVector{4, Cfloat}
	contacttorque::SVector{4, Cfloat}
	contactgap::SVector{4, Cfloat}
	rangefinder::SVector{4, Cfloat}
	constraint::SVector{4, Cfloat}
	slidercrank::SVector{4, Cfloat}
	crankbroken::SVector{4, Cfloat}
end

struct mjVisual
	_global::_global
	quality::quality
	headlight::headlight
	map::map
	scale::scale
	rgba::rgba
end

struct mjStatistic
	meaninertia::mjtNum
	meanmass::mjtNum
	meansize::mjtNum
	extent::mjtNum
	center::SVector{3, mjtNum}
end

struct mjModel
	nq::Cint
	nv::Cint
	nu::Cint
	na::Cint
	nbody::Cint
	njnt::Cint
	ngeom::Cint
	nsite::Cint
	ncam::Cint
	nlight::Cint
	nmesh::Cint
	nmeshvert::Cint
	nmeshtexvert::Cint
	nmeshface::Cint
	nmeshgraph::Cint
	nskin::Cint
	nskinvert::Cint
	nskintexvert::Cint
	nskinface::Cint
	nskinbone::Cint
	nskinbonevert::Cint
	nhfield::Cint
	nhfielddata::Cint
	ntex::Cint
	ntexdata::Cint
	nmat::Cint
	npair::Cint
	nexclude::Cint
	neq::Cint
	ntendon::Cint
	nwrap::Cint
	nsensor::Cint
	nnumeric::Cint
	nnumericdata::Cint
	ntext::Cint
	ntextdata::Cint
	ntuple::Cint
	ntupledata::Cint
	nkey::Cint
	nuser_body::Cint
	nuser_jnt::Cint
	nuser_geom::Cint
	nuser_site::Cint
	nuser_cam::Cint
	nuser_tendon::Cint
	nuser_actuator::Cint
	nuser_sensor::Cint
	nnames::Cint

	nM::Cint
	nemax::Cint
	njmax::Cint
	nconmax::Cint
	nstack::Cint
	nuserdata::Cint
	nmocap::Cint
	nsensordata::Cint

	nbuffer::Cint

	opt::mjOption
	vis::mjVisual
	stat::mjStatistic

	buffer::Ptr{Cvoid}

	qpos0::Ptr{mjtNum}
	qpos_spring::Ptr{mjtNum}

	body_parentid::Ptr{Cint}
	body_rootid::Ptr{Cint}
	body_weldid::Ptr{Cint}
	body_mocapid::Ptr{Cint}
	body_jntnum::Ptr{Cint}
	body_jntadr::Ptr{Cint}
	body_dofnum::Ptr{Cint}
	body_dofadr::Ptr{Cint}
	body_geomnum::Ptr{Cint}
	body_geomadr::Ptr{Cint}
	body_simple::Ptr{mjtByte}
	body_sameframe::Ptr{mjtByte}
	body_pos::Ptr{mjtNum}
	body_quat::Ptr{mjtNum}
	body_ipos::Ptr{mjtNum}
	body_iquat::Ptr{mjtNum}
	body_mass::Ptr{mjtNum}
	body_subtreemass::Ptr{mjtNum}
	body_inertia::Ptr{mjtNum}
	body_invweight0::Ptr{mjtNum}
	body_user::Ptr{mjtNum}

	jnt_type::Ptr{Cint}
	jnt_qposadr::Ptr{Cint}
	jnt_dofadr::Ptr{Cint}
	jnt_bodyid::Ptr{Cint}
	jnt_group::Ptr{Cint}
	jnt_limited::Ptr{mjtByte}
	jnt_solref::Ptr{mjtNum}
	jnt_solimp::Ptr{mjtNum}
	jnt_pos::Ptr{mjtNum}
	jnt_axis::Ptr{mjtNum}
	jnt_stiffness::Ptr{mjtNum}
	jnt_range::Ptr{mjtNum}
	jnt_margin::Ptr{mjtNum}
	jnt_user::Ptr{mjtNum}

	dof_bodyid::Ptr{Cint}
	dof_jntid::Ptr{Cint}
	dof_parentid::Ptr{Cint}
	dof_Madr::Ptr{Cint}
	dof_simplenum::Ptr{Cint}
	dof_solref::Ptr{mjtNum}
	dof_solimp::Ptr{mjtNum}
	dof_frictionloss::Ptr{mjtNum}
	dof_armature::Ptr{mjtNum}
	dof_damping::Ptr{mjtNum}
	dof_invweight0::Ptr{mjtNum}
	dof_M0::Ptr{mjtNum}

	geom_type::Ptr{Cint}
	geom_contype::Ptr{Cint}
	geom_conaffinity::Ptr{Cint}
	geom_condim::Ptr{Cint}
	geom_bodyid::Ptr{Cint}
	geom_dataid::Ptr{Cint}
	geom_matid::Ptr{Cint}
	geom_group::Ptr{Cint}
	geom_priority::Ptr{Cint}
	geom_sameframe::Ptr{mjtByte}
	geom_solmix::Ptr{mjtNum}
	geom_solref::Ptr{mjtNum}
	geom_solimp::Ptr{mjtNum}
	geom_size::Ptr{mjtNum}
	geom_rbound::Ptr{mjtNum}
	geom_pos::Ptr{mjtNum}
	geom_quat::Ptr{mjtNum}
	geom_friction::Ptr{mjtNum}
	geom_margin::Ptr{mjtNum}
	geom_gap::Ptr{mjtNum}
	geom_user::Ptr{mjtNum}
	geom_rgba::Ptr{Cfloat}

	site_type::Ptr{Cint}
	site_bodyid::Ptr{Cint}
	site_matid::Ptr{Cint}
	site_group::Ptr{Cint}
	site_sameframe::Ptr{mjtByte}
	site_size::Ptr{mjtNum}
	site_pos::Ptr{mjtNum}
	site_quat::Ptr{mjtNum}
	site_user::Ptr{mjtNum}
	site_rgba::Ptr{Cfloat}

	cam_mode::Ptr{Cint}
	cam_bodyid::Ptr{Cint}
	cam_targetbodyid::Ptr{Cint}
	cam_pos::Ptr{mjtNum}
	cam_quat::Ptr{mjtNum}
	cam_poscom0::Ptr{mjtNum}
	cam_pos0::Ptr{mjtNum}
	cam_mat0::Ptr{mjtNum}
	cam_fovy::Ptr{mjtNum}
	cam_ipd::Ptr{mjtNum}
	cam_user::Ptr{mjtNum}

	light_mode::Ptr{Cint}
	light_bodyid::Ptr{Cint}
	light_targetbodyid::Ptr{Cint}
	light_directional::Ptr{mjtByte}
	light_castshadow::Ptr{mjtByte}
	light_active::Ptr{mjtByte}
	light_pos::Ptr{mjtNum}
	light_dir::Ptr{mjtNum}
	light_poscom0::Ptr{mjtNum}
	light_pos0::Ptr{mjtNum}
	light_dir0::Ptr{mjtNum}
	light_attenuation::Ptr{Cfloat}
	light_cutoff::Ptr{Cfloat}
	light_exponent::Ptr{Cfloat}
	light_ambient::Ptr{Cfloat}
	light_diffuse::Ptr{Cfloat}
	light_specular::Ptr{Cfloat}

	mesh_vertadr::Ptr{Cint}
	mesh_vertnum::Ptr{Cint}
	mesh_texcoordadr::Ptr{Cint}
	mesh_faceadr::Ptr{Cint}
	mesh_facenum::Ptr{Cint}
	mesh_graphadr::Ptr{Cint}
	mesh_vert::Ptr{Cfloat}
	mesh_normal::Ptr{Cfloat}
	mesh_texcoord::Ptr{Cfloat}
	mesh_face::Ptr{Cint}
	mesh_graph::Ptr{Cint}

   skin_matid::Ptr{Cint}
   skin_rgba::Ptr{Cfloat}
   skin_inflate::Ptr{Cfloat}
   skin_vertadr::Ptr{Cint}
   skin_vertnum::Ptr{Cint}
   skin_texcoordadr::Ptr{Cint}
   skin_faceadr::Ptr{Cint}
   skin_facenum::Ptr{Cint}
   skin_boneadr::Ptr{Cint}
   skin_bonenum::Ptr{Cint}
   skin_vert::Ptr{Cfloat}
   skin_texcoord::Ptr{Cfloat}
   skin_face::Ptr{Cint}
   skin_bonevertadr::Ptr{Cint}
   skin_bonevertnum::Ptr{Cint}
   skin_bonebindpos::Ptr{Cfloat}
   skin_bonebindquat::Ptr{Cfloat}
   skin_bonebodyid::Ptr{Cint}
   skin_bonevertid::Ptr{Cint}
   skin_bonevertweight::Ptr{Cfloat}

	hfield_size::Ptr{mjtNum}
	hfield_nrow::Ptr{Cint}
	hfield_ncol::Ptr{Cint}
	hfield_adr::Ptr{Cint}
	hfield_data::Ptr{Cfloat}

	tex_type::Ptr{Cint}
	tex_height::Ptr{Cint}
	tex_width::Ptr{Cint}
	tex_adr::Ptr{Cint}
	tex_rgb::Ptr{mjtByte}

	mat_texid::Ptr{Cint}
	mat_texuniform::Ptr{mjtByte}
	mat_texrepeat::Ptr{Cfloat}
	mat_emission::Ptr{Cfloat}
	mat_specular::Ptr{Cfloat}
	mat_shininess::Ptr{Cfloat}
	mat_reflectance::Ptr{Cfloat}
	mat_rgba::Ptr{Cfloat}

	pair_dim::Ptr{Cint}
	pair_geom1::Ptr{Cint}
	pair_geom2::Ptr{Cint}
	pair_signature::Ptr{Cint}
	pair_solref::Ptr{mjtNum}
	pair_solimp::Ptr{mjtNum}
	pair_margin::Ptr{mjtNum}
	pair_gap::Ptr{mjtNum}
	pair_friction::Ptr{mjtNum}

	exclude_signature::Ptr{Cint}

	eq_type::Ptr{Cint}
	eq_obj1id::Ptr{Cint}
	eq_obj2id::Ptr{Cint}
	eq_active::Ptr{mjtByte}
	eq_solref::Ptr{mjtNum}
	eq_solimp::Ptr{mjtNum}
	eq_data::Ptr{mjtNum}

	tendon_adr::Ptr{Cint}
	tendon_num::Ptr{Cint}
	tendon_matid::Ptr{Cint}
	tendon_group::Ptr{Cint}
	tendon_limited::Ptr{mjtByte}
	tendon_width::Ptr{mjtNum}
	tendon_solref_lim::Ptr{mjtNum}
	tendon_solimp_lim::Ptr{mjtNum}
	tendon_solref_fri::Ptr{mjtNum}
	tendon_solimp_fri::Ptr{mjtNum}
	tendon_range::Ptr{mjtNum}
	tendon_margin::Ptr{mjtNum}
	tendon_stiffness::Ptr{mjtNum}
	tendon_damping::Ptr{mjtNum}
	tendon_frictionloss::Ptr{mjtNum}
	tendon_lengthspring::Ptr{mjtNum}
	tendon_length0::Ptr{mjtNum}
	tendon_invweight0::Ptr{mjtNum}
	tendon_user::Ptr{mjtNum}
	tendon_rgba::Ptr{Cfloat}

	wrap_type::Ptr{Cint}
	wrap_objid::Ptr{Cint}
	wrap_prm::Ptr{mjtNum}

	actuator_trntype::Ptr{Cint}
	actuator_dyntype::Ptr{Cint}
	actuator_gaintype::Ptr{Cint}
	actuator_biastype::Ptr{Cint}
	actuator_trnid::Ptr{Cint}
	actuator_group::Ptr{Cint}
	actuator_ctrllimited::Ptr{mjtByte}
	actuator_forcelimited::Ptr{mjtByte}
	actuator_dynprm::Ptr{mjtNum}
	actuator_gainprm::Ptr{mjtNum}
	actuator_biasprm::Ptr{mjtNum}
	actuator_ctrlrange::Ptr{mjtNum}
	actuator_forcerange::Ptr{mjtNum}
	actuator_gear::Ptr{mjtNum}
	actuator_cranklength::Ptr{mjtNum}
	actuator_acc0::Ptr{mjtNum}
	actuator_length0::Ptr{mjtNum}
	actuator_lengthrange::Ptr{mjtNum}
	actuator_user::Ptr{mjtNum}

	sensor_type::Ptr{Cint}
	sensor_datatype::Ptr{Cint}
	sensor_needstage::Ptr{Cint}
	sensor_objtype::Ptr{Cint}
	sensor_objid::Ptr{Cint}
	sensor_dim::Ptr{Cint}
	sensor_adr::Ptr{Cint}
	sensor_cutoff::Ptr{mjtNum}
	sensor_noise::Ptr{mjtNum}
	sensor_user::Ptr{mjtNum}

	numeric_adr::Ptr{Cint}
	numeric_size::Ptr{Cint}
	numeric_data::Ptr{mjtNum}

	text_adr::Ptr{Cint}
	text_size::Ptr{Cint}
	text_data::Ptr{UInt8}

	tuple_adr::Ptr{Cint}
	tuple_size::Ptr{Cint}
	tuple_objtype::Ptr{Cint}
	tuple_objid::Ptr{Cint}
	tuple_objprm::Ptr{mjtNum}

	key_time::Ptr{mjtNum}
	key_qpos::Ptr{mjtNum}
	key_qvel::Ptr{mjtNum}
	key_act::Ptr{mjtNum}

	name_bodyadr::Ptr{Cint}
	name_jntadr::Ptr{Cint}
	name_geomadr::Ptr{Cint}
	name_siteadr::Ptr{Cint}
	name_camadr::Ptr{Cint}
	name_lightadr::Ptr{Cint}
	name_meshadr::Ptr{Cint}
	name_skinadr::Ptr{Cint}
	name_hfieldadr::Ptr{Cint}
	name_texadr::Ptr{Cint}
	name_matadr::Ptr{Cint}
	name_pairadr::Ptr{Cint}
	name_excludeadr::Ptr{Cint}
	name_eqadr::Ptr{Cint}
	name_tendonadr::Ptr{Cint}
	name_actuatoradr::Ptr{Cint}
	name_sensoradr::Ptr{Cint}
	name_numericadr::Ptr{Cint}
	name_textadr::Ptr{Cint}
	name_tupleadr::Ptr{Cint}
	name_keyadr::Ptr{Cint}
	names::Ptr{UInt8}
end


text:
#  MIT License
#
#  Copyright (c) 2020 Michael J Simms. All rights reserved.
#
#  Permission is hereby granted, free of charge, to any person obtaining a copy
#  of this software and associated documentation files (the "Software"), to deal
#  in the Software without restriction, including without limitation the rights
#  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#  copies of the Software, and to permit persons to whom the Software is
#  furnished to do so, subject to the following conditions:
#
#  The above copyright notice and this permission notice shall be included in all
#  copies or substantial portions of the Software.
#
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
#  SOFTWARE.

module Signals

import Statistics
export smooth

# Smooths the data, which should be a list, by averaging with the given window size.
function smooth(indata, windowsize)
    outdata = []
    outdatalen = length(indata) - windowsize
    if outdatalen <= 0
        return outdata
    end

    for i in 1:outdatalen
        tempdata = indata[i:i + windowsize]
        val = Statistics.mean(tempdata)
        push!(outdata, val)
    end

    outdata
end

end

max_stars_repo_name: msimms/LibMath

max_issues_repo_name: msimms/LibMath

max_forks_repo_name: msimms/LibMath


text:
# This file is auto-generated by AWSMetadata.jl
using AWS
using AWS.AWSServices: serverlessapplicationrepository
using AWS.Compat
using AWS.UUIDs

"""
    CreateApplication()

Creates an application, optionally including an AWS SAM file to create the first application version in the same call.

# Required Parameters
- `author`: The name of the author publishing the app.Minimum length=1. Maximum length=127.Pattern \"^[a-z0-9](([a-z0-9]|-(?!-))*[a-z0-9])?\";
- `description`: The description of the application.Minimum length=1. Maximum length=256
- `name`: The name of the application that you want to publish.Minimum length=1. Maximum length=140Pattern: \"[a-zA-Z0-9-]+\";

# Optional Parameters
- `homePageUrl`: A URL with more information about the application, for example the location of your GitHub repository for the application.
- `labels`: Labels to improve discovery of apps in search results.Minimum length=1. Maximum length=127. Maximum number of labels: 10Pattern: \"^[a-zA-Z0-9+-_:/@]+\";
- `licenseBody`: A local text file that contains the license of the app that matches the spdxLicenseID value of your application.
 The file has the format file://<path>/<filename>.Maximum size 5 MBYou can specify only one of licenseBody and licenseUrl; otherwise, an error results.
- `licenseUrl`: A link to the S3 object that contains the license of the app that matches the spdxLicenseID value of your application.Maximum size 5 MBYou can specify only one of licenseBody and licenseUrl; otherwise, an error results.
- `readmeBody`: A local text readme file in Markdown language that contains a more detailed description of the application and how it works.
 The file has the format file://<path>/<filename>.Maximum size 5 MBYou can specify only one of readmeBody and readmeUrl; otherwise, an error results.
- `readmeUrl`: A link to the S3 object in Markdown language that contains a more detailed description of the application and how it works.Maximum size 5 MBYou can specify only one of readmeBody and readmeUrl; otherwise, an error results.
- `semanticVersion`: The semantic version of the application:
 https://semver.org/

- `sourceCodeArchiveUrl`: A link to the S3 object that contains the ZIP archive of the source code for this version of your application.Maximum size 50 MB
- `sourceCodeUrl`: A link to a public repository for the source code of your application, for example the URL of a specific GitHub commit.
- `spdxLicenseId`: A valid identifier from https://spdx.org/licenses/.
- `templateBody`: The local raw packaged AWS SAM template file of your application.
 The file has the format file://<path>/<filename>.You can specify only one of templateBody and templateUrl; otherwise an error results.
- `templateUrl`: A link to the S3 object containing the packaged AWS SAM template of your application.You can specify only one of templateBody and templateUrl; otherwise an error results.
"""
create_application(author, description, name; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("POST", "/applications", Dict{String, Any}("author"=>author, "description"=>description, "name"=>name); aws_config=aws_config)
create_application(author, description, name, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("POST", "/applications", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("author"=>author, "description"=>description, "name"=>name), args)); aws_config=aws_config)

"""
    CreateApplicationVersion()

Creates an application version.

# Required Parameters
- `applicationId`: The Amazon Resource Name (ARN) of the application.
- `semanticVersion`: The semantic version of the new version.

# Optional Parameters
- `sourceCodeArchiveUrl`: A link to the S3 object that contains the ZIP archive of the source code for this version of your application.Maximum size 50 MB
- `sourceCodeUrl`: A link to a public repository for the source code of your application, for example the URL of a specific GitHub commit.
- `templateBody`: The raw packaged AWS SAM template of your application.
- `templateUrl`: A link to the packaged AWS SAM template of your application.
"""
create_application_version(applicationId, semanticVersion; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("PUT", "/applications/$(applicationId)/versions/$(semanticVersion)"; aws_config=aws_config)
create_application_version(applicationId, semanticVersion, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("PUT", "/applications/$(applicationId)/versions/$(semanticVersion)", args; aws_config=aws_config)

"""
    CreateCloudFormationChangeSet()

Creates an AWS CloudFormation change set for the given application.

# Required Parameters
- `applicationId`: The Amazon Resource Name (ARN) of the application.
- `stackName`: This property corresponds to the parameter of the same name for the AWS CloudFormation CreateChangeSet
  API.

# Optional Parameters
- `capabilities`: A list of values that you must specify before you can deploy certain applications.
 Some applications might include resources that can affect permissions in your AWS
 account, for example, by creating new AWS Identity and Access Management (IAM) users.
 For those applications, you must explicitly acknowledge their capabilities by
 specifying this parameter.The only valid values are CAPABILITY_IAM, CAPABILITY_NAMED_IAM,
 CAPABILITY_RESOURCE_POLICY, and CAPABILITY_AUTO_EXPAND.The following resources require you to specify CAPABILITY_IAM or
 CAPABILITY_NAMED_IAM:
 AWS::IAM::Group,
 AWS::IAM::InstanceProfile,
 AWS::IAM::Policy, and
 AWS::IAM::Role.
 If the application contains IAM resources, you can specify either CAPABILITY_IAM
 or CAPABILITY_NAMED_IAM. If the application contains IAM resources
 with custom names, you must specify CAPABILITY_NAMED_IAM.The following resources require you to specify CAPABILITY_RESOURCE_POLICY:
 AWS::Lambda::Permission,
 AWS::IAM:Policy,
 AWS::ApplicationAutoScaling::ScalingPolicy,
 AWS::S3::BucketPolicy,
 AWS::SQS::QueuePolicy, and
 AWS::SNS:TopicPolicy.Applications that contain one or more nested applications require you to specify
 CAPABILITY_AUTO_EXPAND.If your application template contains any of the above resources, we recommend that you review
 all permissions associated with the application before deploying. If you don't specify
 this parameter for an application that requires capabilities, the call will fail.
- `changeSetName`: This property corresponds to the parameter of the same name for the AWS CloudFormation CreateChangeSet
  API.
- `clientToken`: This property corresponds to the parameter of the same name for the AWS CloudFormation CreateChangeSet
  API.
- `description`: This property corresponds to the parameter of the same name for the AWS CloudFormation CreateChangeSet
  API.
- `notificationArns`: This property corresponds to the parameter of the same name for the AWS CloudFormation CreateChangeSet
  API.
- `parameterOverrides`: A list of parameter values for the parameters of the application.
- `resourceTypes`: This property corresponds to the parameter of the same name for the AWS CloudFormation CreateChangeSet
  API.
- `rollbackConfiguration`: This property corresponds to the parameter of the same name for the AWS CloudFormation CreateChangeSet
  API.
- `semanticVersion`: The semantic version of the application:
 https://semver.org/

- `tags`: This property corresponds to the parameter of the same name for the AWS CloudFormation CreateChangeSet
  API.
- `templateId`: The UUID returned by CreateCloudFormationTemplate.Pattern: [0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}
"""
create_cloud_formation_change_set(applicationId, stackName; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("POST", "/applications/$(applicationId)/changesets", Dict{String, Any}("stackName"=>stackName); aws_config=aws_config)
create_cloud_formation_change_set(applicationId, stackName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("POST", "/applications/$(applicationId)/changesets", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("stackName"=>stackName), args)); aws_config=aws_config)

"""
    CreateCloudFormationTemplate()

Creates an AWS CloudFormation template.

# Required Parameters
- `applicationId`: The Amazon Resource Name (ARN) of the application.

# Optional Parameters
- `semanticVersion`: The semantic version of the application:
 https://semver.org/

"""
create_cloud_formation_template(applicationId; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("POST", "/applications/$(applicationId)/templates"; aws_config=aws_config)
create_cloud_formation_template(applicationId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("POST", "/applications/$(applicationId)/templates", args; aws_config=aws_config)

"""
    DeleteApplication()

Deletes the specified application.

# Required Parameters
- `applicationId`: The Amazon Resource Name (ARN) of the application.

"""
delete_application(applicationId; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("DELETE", "/applications/$(applicationId)"; aws_config=aws_config)
delete_application(applicationId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("DELETE", "/applications/$(applicationId)", args; aws_config=aws_config)

"""
    GetApplication()

Gets the specified application.

# Required Parameters
- `applicationId`: The Amazon Resource Name (ARN) of the application.

# Optional Parameters
- `semanticVersion`: The semantic version of the application to get.
"""
get_application(applicationId; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("GET", "/applications/$(applicationId)"; aws_config=aws_config)
get_application(applicationId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("GET", "/applications/$(applicationId)", args; aws_config=aws_config)

"""
    GetApplicationPolicy()

Retrieves the policy for the application.

# Required Parameters
- `applicationId`: The Amazon Resource Name (ARN) of the application.

"""
get_application_policy(applicationId; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("GET", "/applications/$(applicationId)/policy"; aws_config=aws_config)
get_application_policy(applicationId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("GET", "/applications/$(applicationId)/policy", args; aws_config=aws_config)

"""
    GetCloudFormationTemplate()

Gets the specified AWS CloudFormation template.

# Required Parameters
- `applicationId`: The Amazon Resource Name (ARN) of the application.
- `templateId`: The UUID returned by CreateCloudFormationTemplate.Pattern: [0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}

"""
get_cloud_formation_template(applicationId, templateId; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("GET", "/applications/$(applicationId)/templates/$(templateId)"; aws_config=aws_config)
get_cloud_formation_template(applicationId, templateId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("GET", "/applications/$(applicationId)/templates/$(templateId)", args; aws_config=aws_config)

"""
    ListApplicationDependencies()

Retrieves the list of applications nested in the containing application.

# Required Parameters
- `applicationId`: The Amazon Resource Name (ARN) of the application.

# Optional Parameters
- `maxItems`: The total number of items to return.
- `nextToken`: A token to specify where to start paginating.
- `semanticVersion`: The semantic version of the application to get.
"""
list_application_dependencies(applicationId; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("GET", "/applications/$(applicationId)/dependencies"; aws_config=aws_config)
list_application_dependencies(applicationId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("GET", "/applications/$(applicationId)/dependencies", args; aws_config=aws_config)

"""
    ListApplicationVersions()

Lists versions for the specified application.

# Required Parameters
- `applicationId`: The Amazon Resource Name (ARN) of the application.

# Optional Parameters
- `maxItems`: The total number of items to return.
- `nextToken`: A token to specify where to start paginating.
"""
list_application_versions(applicationId; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("GET", "/applications/$(applicationId)/versions"; aws_config=aws_config)
list_application_versions(applicationId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("GET", "/applications/$(applicationId)/versions", args; aws_config=aws_config)

"""
    ListApplications()

Lists applications owned by the requester.

# Optional Parameters
- `maxItems`: The total number of items to return.
- `nextToken`: A token to specify where to start paginating.
"""
list_applications(; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("GET", "/applications"; aws_config=aws_config)
list_applications(args::AbstractDict{String, Any}; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("GET", "/applications", args; aws_config=aws_config)

"""
    PutApplicationPolicy()

Sets the permission policy for an application. For the list of actions supported for this operation, see
 Application
 Permissions
 .

# Required Parameters
- `applicationId`: The Amazon Resource Name (ARN) of the application.
- `statements`: An array of policy statements applied to the application.

"""
put_application_policy(applicationId, statements; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("PUT", "/applications/$(applicationId)/policy", Dict{String, Any}("statements"=>statements); aws_config=aws_config)
put_application_policy(applicationId, statements, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("PUT", "/applications/$(applicationId)/policy", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("statements"=>statements), args)); aws_config=aws_config)

"""
    UnshareApplication()

Unshares an application from an AWS Organization.This operation can be called only from the organization's master account.

# Required Parameters
- `applicationId`: The Amazon Resource Name (ARN) of the application.
- `organizationId`: The AWS Organization ID to unshare the application from.

"""
unshare_application(applicationId, organizationId; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("POST", "/applications/$(applicationId)/unshare", Dict{String, Any}("organizationId"=>organizationId); aws_config=aws_config)
unshare_application(applicationId, organizationId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("POST", "/applications/$(applicationId)/unshare", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("organizationId"=>organizationId), args)); aws_config=aws_config)

"""
    UpdateApplication()

Updates the specified application.

# Required Parameters
- `applicationId`: The Amazon Resource Name (ARN) of the application.

# Optional Parameters
- `author`: The name of the author publishing the app.Minimum length=1. Maximum length=127.Pattern \"^[a-z0-9](([a-z0-9]|-(?!-))*[a-z0-9])?\";
- `description`: The description of the application.Minimum length=1. Maximum length=256
- `homePageUrl`: A URL with more information about the application, for example the location of your GitHub repository for the application.
- `labels`: Labels to improve discovery of apps in search results.Minimum length=1. Maximum length=127. Maximum number of labels: 10Pattern: \"^[a-zA-Z0-9+-_:/@]+\";
- `readmeBody`: A text readme file in Markdown language that contains a more detailed description of the application and how it works.Maximum size 5 MB
- `readmeUrl`: A link to the readme file in Markdown language that contains a more detailed description of the application and how it works.Maximum size 5 MB
"""
update_application(applicationId; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("PATCH", "/applications/$(applicationId)"; aws_config=aws_config)
update_application(applicationId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = serverlessapplicationrepository("PATCH", "/applications/$(applicationId)", args; aws_config=aws_config)


text:
"""
    ignore_derivatives(f::Function)

Tells the AD system to ignore the gradients of the wrapped closure. The primal computation
(forward pass) is executed normally.

```julia
ignore_derivatives() do
    value = rand()
    push!(collection, value)
end
```

Using this incorrectly could lead to incorrect gradients.
For example, the following function will have zero gradients with respect to its argument:
```julia
function wrong_grads(x)
    y = ones(3)
    ignore_derivatives() do
        push!(y, x)
    end
    return sum(y)
end
```
"""
ignore_derivatives(f::Function) = f()

"""
    ignore_derivatives(x)

Tells the AD system to ignore the gradients of the argument. Can be used to avoid
unnecessary computation of gradients.

```julia
ignore_derivatives(x) * w
```
"""
ignore_derivatives(x) = x

@non_differentiable ignore_derivatives(f)

"""
    @ignore_derivatives (...)

Tells the AD system to ignore the expression. Equivalent to `ignore_derivatives() do (...) end`.
"""
macro ignore_derivatives(ex)
    return :(
        ChainRulesCore.ignore_derivatives() do
            $(esc(ex))
        end
    )
end


text:
using Term.progress
using DataFrames
import JSONTables: objecttable, jsontable

import jcontrol: FULLTRACK
import jcontrol.io: load_trials
import jcontrol.trial: Trial

"""
Save each "raw" trial from python to a json file

"""
# folder with json files exported from python's database
# TRIALS_FOLDER = "/Users/federicoclaudi/Dropbox (UCL)/Rotation_vte/Locomotion/analysis/behavior/inbound_bouts"
TRIALS_FOLDER = "D:\\Dropbox (UCL)\\Rotation_vte\\Locomotion\\analysis\\behavior\\saved_data"

# folder where processed/cached julia trials will be stored
# CACHE_FOLDER  = "/Users/federicoclaudi/Dropbox (UCL)/Rotation_vte/Locomotion/analysis/behavior/jl_inbound_trials"
CACHE_FOLDER = "D:\\Dropbox (UCL)\\Rotation_vte\\Locomotion\\analysis\\behavior\\jl_trials_cache"

@info "Caching data" TRIALS_FOLDER CACHE_FOLDER

# load trials
trials = load_trials(; folder=TRIALS_FOLDER)

# cache trials
pbar = ProgressBar()
job = addjob!(pbar; N=size(trials, 1))

with(pbar) do
    for (i, trial) in enumerate(eachrow(trials))
        trial = Trial(trial, FULLTRACK)

        trialdict = Dict(
            "x" => trial.x,
            "y" => trial.y,
            "s" => trial.s,
            "θ" => trial.θ,
            "ω" => trial.ω,
            "speed" => trial.speed,
            "u" => trial.u,
            "v" => trial.v,
            "duration" => trial.duration,
        )

        df = DataFrame(trialdict)

        open(joinpath(CACHE_FOLDER, "trial_$(i).json"), "w") do f
            write(f, objecttable(df))
        end

        update!(job)
        sleep(0.001)
    end
end

# open(joinpath(CACHE_FOLDER, "trial_1.json")) do f
#     data = read(f)
#     @time jsontable(data)
#     print(jsontable(data).x)
# end

max_stars_repo_name: FedeClaudi/LocomotionControl

max_issues_repo_name: FedeClaudi/LocomotionControl

max_forks_repo_name: FedeClaudi/LocomotionControl


text:
using MyQuantum
using Test

@testset "MyQuantum.jl" begin
    # Write your own tests here.
    @test is_unitary.([X, Y, Z]) == fill(true, 3)
    @test is_unitary(H) == true
    @test is_hermitian.([X, Y, Z, H]) == fill(true, 4)
    @test im * X * Z == Y
    @test H * ket_0 == ket_plus
    @test H^2 ≈ Id
    @test H == (X + Z) ./ sqrt(2)
    @test T^4 ≈ S^2 ≈ Z
    @test test_Cgates() == true
end

max_stars_repo_name: anandijain/MyQuantum

max_issues_repo_name: anandijain/MyQuantum

max_forks_repo_name: anandijain/MyQuantum


text:
export QuLDE, LDEMSAlgHHL, QuNLDE
export QuEuler, QuLeapfrog, QuAB2, QuAB3, QuAB4

abstract type QuODEAlgorithm <: DiffEqBase.AbstractODEAlgorithm end
"""
    LDEMSAlgHHL <: QuODEAlgorithm

Multi-step methods based on HHL

"""
abstract type LDEMSAlgHHL <: QuODEAlgorithm end

"""
    QuLDE <: QuODEAlgorithm

Linear differential equation solvers (non-HHL)
    * k : order of Taylor series expansion

"""
struct QuLDE <: QuODEAlgorithm
    k::Int
    QuLDE(k = 3) = new(k)
end

"""
    QuNLDE <: QuODEAlgorithm

Linear differential equation solvers (non-HHL)
    * k : order of Taylor series expansion
    * ϵ : precision

"""
struct QuNLDE <: QuODEAlgorithm
    k::Int
    ϵ::Real
    QuNLDE(k = 3, ϵ = 1e-3) = new(k,ϵ)
end

"""
    QuEuler{T} <: LDEMSAlgHHL

Euler Method using HHL (1-step method)

"""
struct QuEuler{T} <: LDEMSAlgHHL
    step::Int
    α::Vector{T}
    β::Vector{T}
    nreg::Int
    QuEuler(nreg = 12,::Type{T} = Float64) where {T} = new{T}(1,[1.0,],[1.0,],nreg)
end

"""
    QuLeapfrog{T} <: LDEMSAlgHHL

Leapfrog Method using HHL (2-step method)

"""
struct QuLeapfrog{T} <: LDEMSAlgHHL
    step::Int
    α::Vector{T}
    β::Vector{T}
    nreg::Int
    QuLeapfrog(nreg = 12,::Type{T} = Float64) where {T} = new{T}(2,[0, 1.0],[2.0, 0],nreg)
end

"""
    QuAB2{T} <: LDEMSAlgHHL

AB2 Method using HHL (2-step method)

"""
struct QuAB2{T} <: LDEMSAlgHHL
    step::Int
    α::Vector{T}
    β::Vector{T}
    nreg::Int
    QuAB2(nreg = 12,::Type{T} = Float64) where {T} = new{T}(2,[1.0, 0], [1.5, -0.5],nreg)
end

"""
    QuAB3{T} <: LDEMSAlgHHL

AB3 Method using HHL (3-step method)

"""
struct QuAB3{T} <: LDEMSAlgHHL
    step::Int
    α::Vector{T}
    β::Vector{T}
    nreg::Int
    QuAB3(nreg = 12,::Type{T} = Float64) where {T} = new{T}(3,[1.0, 0, 0], [23/12, -16/12, 5/12],nreg)
end

"""
    QuAB4{T} <: LDEMSAlgHHL

AB4 Method using HHL (4-step method)

"""
struct QuAB4{T} <: LDEMSAlgHHL
    step::Int
    α::Vector{T}
    β::Vector{T}
    nreg::Int
    QuAB4(nreg = 12,::Type{T} = Float64) where {T} = new{T}(4,[1.0, 0, 0, 0], [55/24, -59/24, 37/24, -9/24],nreg)
end


text:
# -*- coding: utf-8 -*-
# ---
# jupyter:
#   jupytext:
#     formats: ipynb,jl:hydrogen
#     text_representation:
#       extension: .jl
#       format_name: hydrogen
#       format_version: '1.3'
#       jupytext_version: 1.11.2
#   kernelspec:
#     display_name: Julia 1.8.0-DEV
#     language: julia
#     name: julia-1.8
# ---

# %%
using Memoization
using SpecialFunctions
fact(n) = gamma(n + 1)

# %%
fact(100)

# %%
factorial(big(100)) |> Float64

# %%
coeff_sin(n) = Tuple((-1)^k/fact(2k+1) for k in 0:n-1)
taylor_odd(x, c) = x*evalpoly(x^2, c)

# %%
c = coeff_sin(8)
x = π/4
@show sin(x)
[(n, taylor_odd(x, coeff_sin(n))) for n in 1:9]

# %%

max_stars_repo_name: genkuroki/public

max_issues_repo_name: genkuroki/public

max_forks_repo_name: genkuroki/public


text:
import AlphaZero.Scripts.dummy_run
import AlphaZero.Scripts.test_game
# include("game.jl")
# println("TEST GAME")
# test_game(GameSpec())
println("DUMMY RUN")
dummy_run("fanorona")


text:
"""
    obl06(date1, date2)

Mean obliquity of the ecliptic, IAU 2006 precession model.

### Given ###

- `date1`, `date2`: TT as a 2-part Julian Date (Note 1)

### Returned ###

- Obliquity of the ecliptic (radians, Note 2)

### Notes ###

1. The TT date date1+date2 is a Julian Date, apportioned in any
   convenient way between the two arguments.  For example,
   JD(TT)=2450123.7 could be expressed in any of these ways,
   among others:

   | `date1`   |     `date2` |                    |
   |:----------|:------------|:-------------------|
   | 2450123.7 |         0.0 | JD method          |
   | 2451545.0 |     -1421.3 | J2000 method       |
   | 2400000.5 |     50123.2 | MJD method         |
   | 2450123.5 |         0.2 | date & time method |

   The JD method is the most natural and convenient to use in
   cases where the loss of several decimal digits of resolution
   is acceptable.  The J2000 method is best matched to the way
   the argument is handled internally and will deliver the
   optimum resolution.  The MJD method and the date & time methods
   are both good compromises between resolution and convenience.

2. The result is the angle between the ecliptic and mean equator of
   date date1+date2.

### Reference ###

- Hilton, J. et al., 2006, Celest.Mech.Dyn.Astron. 94, 351

"""
obl06

"""
    obl80(date1, date2)

Mean obliquity of the ecliptic, IAU 1980 model.

### Given ###

- `date1`, `date2`: TT as a 2-part Julian Date (Note 1)

### Returned ###

- Obliquity of the ecliptic (radians, Note 2)

### Notes ###

1. The TT date date1+date2 is a Julian Date, apportioned in any
   convenient way between the two arguments.  For example,
   JD(TT)=2450123.7 could be expressed in any of these ways,
   among others:

   | `date1`   |     `date2` |                    |
   |:----------|:------------|:-------------------|
   | 2450123.7 |         0.0 | JD method          |
   | 2451545.0 |     -1421.3 | J2000 method       |
   | 2400000.5 |     50123.2 | MJD method         |
   | 2450123.5 |         0.2 | date & time method |

   The JD method is the most natural and convenient to use in
   cases where the loss of several decimal digits of resolution
   is acceptable.  The J2000 method is best matched to the way
   the argument is handled internally and will deliver the
   optimum resolution.  The MJD method and the date & time methods
   are both good compromises between resolution and convenience.

2. The result is the angle between the ecliptic and mean equator of
   date date1+date2.

### Reference ###

- Explanatory Supplement to the Astronomical Almanac,
    P. Kenneth Seidelmann (ed), University Science Books (1992),
    Expression 3.222-1 (p114).

"""
obl80

for name in ("obl06",
             "obl80")
    f = Symbol(name)
    fc = "era" * uppercasefirst(name)
    @eval ($f)(d1, d2) = ccall(($fc, liberfa), Cdouble, (Cdouble, Cdouble), d1, d2)
end


text:
"""
    closest_pair_search(array::Array{Int64,1}, target::Int64)

Finding the closet pair of values for a given target in a sorted array. For this reason,
the distance between a pair of of values has to be minimazied with respect to the target.
For more information see: [https://en.wikipedia.org/wiki/Closest_pair_of_points_problem](https://en.wikipedia.org/wiki/Closest_pair_of_points_problem)

# Arguments
- `array::Array{Int64,1}`: Sorted array of integers
- `target::Int64`: Target-value to find the position

# Examples
```julia-repl
julia> import ClassicAlgorithmsCollections
julia> arr = [10, 22, 28, 29, 30, 40]
julia> target = 56
julia> ClassicAlgorithmsCollections.closest_pair_search(arr, target)
(28, 29)
```
"""
function closest_pair_search(array::Array{Int64,1}, target::Int64)

    # To store indexes of result pair
    res_left, res_right = 1, 1

    #Initialize left, right array boundaries, and their difference
    left, right, diff = 1, length(array), 999999

    # While there are elements between left and right array boundaries
    while right > left

        # Check if the distance between the current pair is closer than the closest
        # previous pair so far
        if abs(array[left] + array[right] - target) < diff
            res_left = left
            res_right = right
            # If yes update the distance
            diff = abs(array[left] + array[right] - target)
        end

        # If this pair has more sum than the target, shrink the array to a smaller value
        if array[left] + array[right] > target

            right -= 1
        # Otherwise, shrink the array to a larger value
        else
            left += 1
        end
    end
    return array[res_left], array[res_right]
end

max_stars_repo_name: Anselmoo/ClassicAlgorithmsCollections

max_issues_repo_name: Anselmoo/ClassicAlgorithmsCollections

max_forks_repo_name: Anselmoo/ClassicAlgorithmsCollections


text:
"Square the sum of the first `n` positive integers"
function square_of_sum(n)
    tmp=0
    for i in 1:n
        tmp+=i
    end
    return tmp^2
end

"Sum the squares of the first `n` positive integers"
function sum_of_squares(n)
    tmp=0
    for i in 1:n
        tmp+=i^2
    end
    return tmp
end

"Subtract the sum of squares from square of the sum of the first `n` positive ints"
function difference(n)
    return abs(sum_of_squares(n) - square_of_sum(n))
end

max_stars_repo_name: stepinski/julia-in

max_issues_repo_name: stepinski/julia-init

max_forks_repo_name: stepinski/julia-init


text:
using Test
using Bridge
using Bridge: expint
using LinearAlgebra

e1taylor(x) = @evalpoly(x,
-0.5772156649015329,
 1.0,
-0.25,
 0.05555555555555555,
-0.010416666666666666,
 0.0016666666666666666,
-0.0002314814814814815,
 2.834467120181406e-5,
-3.1001984126984127e-6,
 3.0619243582206544e-7,
-2.7557319223985888e-8) - log(x)

@test norm(e1taylor(1.0) - 0.21938393439552029) < 1e-8
@test norm(e1taylor(0.6) - 0.4543795031894021) < 1e-11
@test norm(e1taylor(0.05) - 2.467898488509974369559902) < eps()

@test norm(expint(3.0) - 0.013048381094197037) < eps()
@test norm(expint(1.0) - 0.21938393439552029) == 0
@test norm(expint(0.6) - 0.4543795031894021) == 0
@test norm(expint(0.05) - 2.467898488509974369559902)  == 0


text:
@testset "Binary to Decimal" begin

    arr = BitArray([1,0,0,0,0])
    out = GNSSDecoder.bin2dec(arr)
    @test out == 16

    arr = BitArray([1,0,1,0,0])
    out = GNSSDecoder.bin2dec(arr)
    @test out == 20

    arr = BitArray([1,0,0,0,0,0,0,1])
    out = GNSSDecoder.bin2dec(arr)
    @test out == 129
end

@testset "Binary to Decimal Two's complement" begin

    arr = BitArray([1,0,0,0,0])
    out = GNSSDecoder.bin2dec_twoscomp(arr)
    @test out == -16

    arr = BitArray([1,0,1,0,0])
    out = GNSSDecoder.bin2dec_twoscomp(arr)
    @test out == -12

    arr = BitArray([1,0,0,0,0,0,0,1])
    out = GNSSDecoder.bin2dec_twoscomp(arr)
    @test out == -127
end


text:
function base_method(::DescentMethod) end

argumentvec(M::Wrapper) = argumentvec(base_method(M))
gradientvec(M::Wrapper) = gradientvec(base_method(M))
step_origin(M::Wrapper) = step_origin(base_method(M))

__descent_dir!(M::Wrapper) = __descent_dir!(base_method(M))

@inline callfn!(M::Wrapper, fdf, x, α, d) = callfn!(base_method(M), fdf, x, α, d)

function init!(M::Wrapper, args...; kw...)
    init!(base_method(M), args...; kw...)
    return
end

"""
    reset!(M::DescentMethod, args...; kwargs...)

Reset the solver parameters to the default (or to specific value - see the documentation for
    the specific types).

Each method has to implement a parameter-free `reset!(M)` method.
"""
function reset!(M::Wrapper, args...; kw...)
    reset!(base_method(M), args...; kw...)
    return
end

step!(M::Wrapper, fn::F; kw...) where {F} = step!(base_method(M), fn; kw...)

stopcond(M::Wrapper) = stopcond(base_method(M))
@inline stopcond(M::CoreMethod) = false

conv_success(M::Wrapper) = conv_success(base_method(M))
@inline conv_success(M::CoreMethod) = false

iter_count(M::Wrapper) = iter_count(base_method(M))
call_count(M::Wrapper) = call_count(base_method(M))

iter_count(M::CoreMethod) = -1
call_count(M::CoreMethod) = -1

"""
    convstat(M::Wrapper)

For a converged state, return the statistics in the form of `NamedTuple`
  `(converged = true/false, argument, gradient, iterations, calls)`.
  Negative values of `calls` or `iterations` mean that the number has not been tracked.
"""
function convstat(M::Wrapper)
    return (
        converged = conv_success(M),
        argument = argumentvec(M),
        gradient = gradientvec(M),
        iterations = iter_count(M),
        calls = call_count(M)
    )
end

"""
    StopByGradient

Wrapper type to stop optimization once the magnitude of gradient
is less than the specified value.
"""
struct StopByGradient{T<:DescentMethod, F} <: Wrapper
    descent::T
    gtol::F
end

base_method(M::StopByGradient) = M.descent

function stopcond(M::StopByGradient)
    base = M.descent
    norm(gradientvec(base)) <= M.gtol ? true : stopcond(base)
end

function conv_success(M::StopByGradient)
    base = M.descent
    norm(gradientvec(base), Inf) <= M.gtol ? true : conv_success(base)
end

"""
    LimitCalls

Wrapper type to stop optimization once the number of
the objective function calls exceeds the specified value.
"""
mutable struct LimitCalls{T<:DescentMethod}<:Wrapper
    descent::T
    call_limit::Int
    call_count::Int
end

LimitCalls(M::DescentMethod) = LimitCalls(M, typemax(Int), 0)
LimitCalls(M::DescentMethod, maxcalls::Integer) = LimitCalls(M, maxcalls, 0)

base_method(M::LimitCalls) = M.descent

function init!(M::LimitCalls, args...; kw...)
    M.call_count = 0
    init!(M.descent, args...; kw...)
    return
end

function reset!(M::LimitCalls, args...; call_limit, kw...)
    M.call_count = 0
    M.call_limit = call_limit
    reset!(M.descent, args...; kw...)
    return
end

function callfn!(M::LimitCalls, fdf::F, x, α, d) where {F}
    fg = callfn!(M.descent, fdf, x, α, d)
    M.call_count += 1
    return fg
end

stopcond(M::LimitCalls) = M.call_count < M.call_limit ? stopcond(M.descent) : true
call_count(M::LimitCalls) = M.call_count

"""
    LimitIters

Wrapper type to stop optimization once the number of
the optimization iterations exceeds the specified value.
"""
mutable struct LimitIters{T<:DescentMethod}<:Wrapper
    descent::T
    iter_limit::Int
    iter_count::Int
end

LimitIters(M::DescentMethod) = LimitIters(M, typemax(Int), 0)
LimitIters(M::DescentMethod, maxiters::Integer) = LimitIters(M, maxiters, 0)

base_method(M::LimitIters) = M.descent

function init!(M::LimitIters, args...; kw...)
    M.iter_count = 0
    init!(M.descent, args...; kw...)
    return
end

function reset!(M::LimitIters, args...; iter_limit=M.iter_limit, kw...)
    M.iter_count = 0
    M.iter_limit = iter_limit
    reset!(M.descent, args...; kw...)
    return
end

function step!(M::LimitIters, fdf::F; kw...) where {F}
    s = step!(M.descent, fdf; kw...)
    M.iter_count += 1
    return s
end

stopcond(M::LimitIters) = M.iter_count < M.iter_limit ? stopcond(M.descent) : true

@inline iter_count(M::LimitIters) = M.iter_count

"""
    ConstrainStepSize

Wrapper type to limit step sizes attempted in optimization,
given a function `(origin, direction) -> max_step`.
"""
struct ConstrainStepSize{T<:DescentMethod, F} <: Wrapper
    descent::T
    constraint::F
end

ConstrainStepSize(M::DescentMethod) = ConstrainStepSize(M, infstep)

base_method(M::ConstrainStepSize) = M.descent

function init!(M::ConstrainStepSize, args...; kw...)
    init!(M.descent, args...; constrain_step=M.constraint, kw...)
    return
end

step!(M::ConstrainStepSize, optfn!) = step!(M.descent, optfn!, constrain_step=M.constraint)

"""
    Logger

Wrapper type to dump the steps during the optimization.
The first dumped value is argument, the second is function value, the third is gradient.
"""
struct Logger{T<:DescentMethod,F<:IO} <: Wrapper
    descent::T
    file::F
end

"""
    Logger(M::DescentMethod, name, args...; kw...)

Logger constructor from file name. `args` and `kw` are the same as for `open()` function.
"""
function Logger(M::DescentMethod, name::AbstractString, args...; kw...)
    Logger(M, open(name, args...; kw...))
end

base_method(M::Logger) = M.descent

function init!(M::Logger, args...; kw...)
    arg = argumentvec(M)
    n = length(arg)
    print(
        M.file,
        """
        # Optimization start
        # First $n value$(n == 1 ? "" : "s") - argument vector
        # next value - function value
        # last $n value$(n == 1 ? "" : "s") - gradient vector

        # Solver initialization:
        """
    )
    init!(M.descent, args...; kw...)
    return
end

function callfn!(M::Logger, fdf, x, α, d)
    print(M.file, join(x .+ α .* d, ' '))
    fg = callfn!(M.descent, fdf, x, α, d)
    y, g = fg
    println(M.file, ' ', y, ' ', join(g, ' '))
    return fg
end

function step!(M::Logger, args...; kw...)
    niter = iter_count(M.descent) + 1
    println(M.file, "\n# Iteration $niter")
    step!(M.descent, args...; kw...)
end

function convstat(M::Logger)
    converged = conv_success(M)
    gradient = gradientvec(M)
    argument = argumentvec(M)
    iterations = iter_count(M)
    calls = call_count(M)
    print(
        M.file,
        """

        # Final statistics:
        # converged: $(converged)
        # final gradient: $(gradient)
        # final argument: $(argument)
        # number of iterations: $(iterations)
        # number of function calls: $(calls)
        """
    )
    return (
        converged = converged,
        argument = argument,
        gradient = gradient,
        iterations = iterations,
        calls = calls
    )
end


text:
# Conventions for Cartesian components
# nw: direction of differentiation (∂w)
# nu: component of the input field (Fu)
# nv: component of the output field (Gv)

include("partial.jl")
include("curl.jl")
include("divergence.jl")
include("gradient.jl")


text:
function α_func(params, α, n)
    (; r, D, W, dim) = params

    m = length(D)
    bc1 = zeros(size(α))
    bc2 = zeros(size(α))

    for i = 1:length(α)
        bc = compute_bc(params, α[i], n)
        bc1[i] = bc[m, 1]
        bc2[i] = bc[m, 2]
    end

    rD = r[m] / √D[m]

    if dim == 2
        f1 = (
            √D[m] * α .* (besselj(n - 1, α * rD) - besselj(n + 1, α * rD)) / 2 +
            W[m] * besselj(n, α * rD)
        )
        f2 = (
            √D[m] * α .* (bessely(n - 1, α * rD) - bessely(n + 1, α * rD)) / 2 +
            W[m] * bessely(n, α * rD)
        )
    else
        f1 = (
            √D[m] * α .* (
                sphericalbesselj(n - 1, α * rD) - sphericalbesselj(n + 1, α * rD) -
                sphericalbesselj(n, α * rD) ./ (α * rD)
            ) / 2 + W[m] * sphericalbesselj(n, α * rD)
        )
        f2 = (
            √D[m] * α .* (
                sphericalbessely(n - 1, α * rD) - sphericalbessely(n + 1, α * rD) -
                sphericalbessely(n, α * rD) ./ (α * rD)
            ) / 2 + W[m] * sphericalbessely(n, α * rD)
        )
    end

    bc1 .* f1 + bc2 .* f2
end