mission = 
{
    ["trig"] = 
    {
        ["actions"] = 
        {
            [1] = "a_do_script(\"dcsCommon = {}\\\
dcsCommon.version = \\\"2.4.9\\\"\\\
--[[-- VERSION HISTORY\\\
 2.2.6 - compassPositionOfARelativeToB\\\
       - clockPositionOfARelativeToB\\\
 2.2.7 - isTroopCarrier \\\
       - distFlat\\\
 2.2.8 - fixed event2text \\\
 2.2.9 - getUnitAGL\\\
       - getUnitAlt\\\
       - getUnitSpeed \\\
       - getUnitHeading\\\
       - getUnitHeadingDegrees\\\
       - mag\\\
       - clockPositionOfARelativeToB with own heading \\\
 2.3.0 - unitIsInfantry\\\
 2.3.1 - bool2YesNo\\\
       - bool2Text\\\
 2.3.2 - getGroupAvgSpeed\\\
       - getGroupMaxSpeed\\\
 2.3.3 - getSizeOfTable\\\
 2.3.4 - isSceneryObject\\\
         coalition2county\\\
 2.3.5 - smallRandom\\\
         pickRandom uses smallRandom\\\
         airfield handling, parking \\\
         flight waypoint handling\\\
         landing waypoint creation\\\
         take-off waypoint creation\\\
 2.3.6 - createOverheadAirdromeRoutPintData(aerodrome)\\\
 2.3.7 - coalition2county - warning when creating UN \\\
 2.3.8 - improved headingOfBInDegrees, new getClockDirection\\\
 2.3.9 - getClosingVelocity\\\
       - dot product \\\
       - magSquare\\\
       - vMag\\\
 2.4.0 - libCheck\\\
 2.4.1 - grid/square/rect formation \\\
       - arrangeGroupInNColumns formation \\\
       - 2Columns formation deep and wide formation\\\
 2.4.2 - getAirbasesInRangeOfPoint\\\
 2.4.3 - lerp \\\
 2.4.4 - getClosestAirbaseTo\\\
       - fixed bug in containsString when strings equal\\\
 2.4.5 - added cargo and mass options to createStaticObjectData\\\
 2.4.6 - fixed randompercent \\\
 2.4.7 - smokeColor2Num(smokeColor)\\\
 2.4.8 - linkStaticDataToUnit()\\\
 2.4.9 - trim functions \\\
       - createGroundUnitData uses trim function to remove leading/trailing blanks\\\
         so now we can use blanks after comma to separate types \\\
       - dcsCommon.trimArray(\\\
       - createStaticObjectData uses trim for type \\\
       - getEnemyCoalitionFor understands strings, still returns number\\\
       - coalition2county also undertsands 'red' and 'blue'       \\\
--]]--\\\
\\\
    -- dcsCommon is a library of common lua functions \\\
    -- for easy access and simple mission programming\\\
    -- (c) 2021 by Chritian Franz and cf/x AG\\\
\\\
    dcsCommon.verbose = false -- set to true to see debug messages. Lots of them\\\
    dcsCommon.uuidStr = \\\"uuid-\\\"\\\
\\\
    -- globals\\\
    dcsCommon.cbID = 0 -- callback id for simple callback scheduling\\\
    dcsCommon.troopCarriers = {\\\"Mi-8MT\\\", \\\"UH-1H\\\", \\\"Mi-24P\\\"} -- Ka-50 and Gazelle can't carry troops\\\
\\\
    -- verify that a module is loaded. obviously not required\\\
    -- for dcsCommon, but all higher-order modules\\\
    function dcsCommon.libCheck(testingFor, requiredLibs)\\\
        local canRun = true \\\
        for idx, libName in pairs(requiredLibs) do \\\
            if not _G[libName] then \\\
                trigger.action.outText(\\\"*** \\\" .. testingFor .. \\\" requires \\\" .. libName, 30)\\\
                canRun = false \\\
            end\\\
        end\\\
        return canRun\\\
    end\\\
\\\
    -- taken inspiration from mist, as dcs lua has issues with\\\
    -- random numbers smaller than 50. Given a range of x numbers 1..x, it is \\\
    -- repeated a number of times until it fills an array of at least \\\
    -- 50 items (usually some more), and only then one itemis picked from \\\
    -- that array with a random number that is from a greater range (0..50+)\\\
    function dcsCommon.smallRandom(theNum) -- adapted from mist, only support ints\\\
        if theNum >= 50 then return math.random(theNum) end\\\
        \\\
        -- for small randoms (<50) \\\
        local lowNum, highNum\\\
        highNum = theNum\\\
        lowNum = 1\\\
        local total = 1\\\
        if math.abs(highNum - lowNum + 1) < 50 then -- if total values is less than 50\\\
            total = math.modf(50/math.abs(highNum - lowNum + 1)) -- number of times to repeat whole range to get above 50. e.g. 11 would be 5 times 1 .. 11, giving us 55 items total \\\
        end\\\
        local choices = {}\\\
        for i = 1, total do -- iterate required number of times\\\
            for x = lowNum, highNum do -- iterate between the range\\\
                choices[#choices +1] = x -- add each entry to a table\\\
            end\\\
        end\\\
        local rtnVal; -- = math.random(#choices) -- will now do a math.random of at least 50 choices\\\
        for i = 1, 15 do\\\
            rtnVal = math.random(#choices) -- iterate 15 times for randomization\\\
        end\\\
        return choices[rtnVal] -- return indexed\\\
    end\\\
    \\\
\\\
    function dcsCommon.getSizeOfTable(theTable)\\\
        local count = 0\\\
        for _ in pairs(theTable) do count = count + 1 end\\\
        return count\\\
    end\\\
\\\
    function dcsCommon.findAndRemoveFromTable(theTable, theElement) -- assumes array \\\
        if not theElement then return false end \\\
        if not theTable then return false end \\\
        for i=1, #theTable do \\\
            if theTable[i] == theElement then \\\
                -- this element found. remove from table \\\
                table.remove(theTable, i)\\\
                return true \\\
            end\\\
        end\\\
    end\\\
\\\
    function dcsCommon.pickRandom(theTable)\\\
        if not theTable then \\\
            trigger.action.outText(\\\"*** warning: nil table in pick random\\\", 30)\\\
        end\\\
        \\\
        if #theTable < 1 then \\\
            trigger.action.outText(\\\"*** warning: zero choice in pick random\\\", 30)\\\
            local k = i.ll \\\
            return nil\\\
        end\\\
        if #theTable == 1 then return theTable[1] end\\\
        r = dcsCommon.smallRandom(#theTable) --r = math.random(#theTable)\\\
        return theTable[r]\\\
    end\\\
\\\
    -- enumerateTable - make an array out of a table for indexed access\\\
    function dcsCommon.enumerateTable(theTable)\\\
        if not theTable then theTable = {} end\\\
        local array = {}\\\
        for key, value in pairs(theTable) do \\\
            table.insert(array, value)\\\
        end\\\
        return array\\\
    end\\\
\\\
-- \\\
-- A I R F I E L D S  A N D  F A R P S  \\\
--\\\
\\\
    -- airfield management \\\
    function dcsCommon.getAirbaseCat(aBase)\\\
        if not aBase then return nil end \\\
        \\\
        local airDesc = aBase:getDesc()\\\
        if not airDesc then return nil end \\\
        \\\
        local airCat = airDesc.category\\\
        return airCat \\\
    end\\\
\\\
    -- get free parking slot. optional parkingType can be used to \\\
    -- filter for a scpecific type, e.g. 104 = open field\\\
    function dcsCommon.getFirstFreeParkingSlot(aerodrome, parkingType) \\\
        if not aerodrome then return nil end \\\
        local freeSlots = aerodrome:getParking(true)\\\
        \\\
        for idx, theSlot in pairs(freeSlots) do \\\
            if not parkingType then \\\
                -- simply return the first we come across\\\
                return theSlot\\\
            end        \\\
            \\\
            if theSlot.Term_Type == parkingType then \\\
                return theSlot \\\
            end\\\
        end\\\
        \\\
        return nil \\\
    end\\\
\\\
    -- getAirbasesInRangeOfPoint: get airbases that are in range of point \\\
    function dcsCommon.getAirbasesInRangeOfPoint(center, range, filterCat, filterCoalition)\\\
        if not center then return {} end \\\
        if not range then range = 500 end -- 500m default \\\
        local basesInRange = {}\\\
        \\\
        local allAB = dcsCommon.getAirbasesWhoseNameContains(\\\"*\\\", filterCat, filterCoalition)\\\
        for idx, aBase in pairs(allAB) do             \\\
            local delta = dcsCommon.dist(center, aBase:getPoint())\\\
            if delta <= range then \\\
                table.insert(basesInRange, aBase)\\\
            end\\\
        end\\\
        return basesInRange\\\
    end\\\
\\\
    -- getAirbasesInRangeOfAirbase returns all airbases that \\\
    -- are in range of the given airbase \\\
    function dcsCommon.getAirbasesInRangeOfAirbase(airbase, includeCenter, range, filterCat, filterCoalition)\\\
        if not airbase then return {} end\\\
        if not range then range = 150000 end \\\
        local center = airbase:getPoint() \\\
        local centerName = airbase:getName() \\\
        \\\
        local ABinRange = {}\\\
        local allAB = dcsCommon.getAirbasesWhoseNameContains(\\\"*\\\", filterCat, filterCoalition)\\\
        \\\
        for idx, aBase in pairs(allAB) do \\\
            if aBase:getName() ~= centerName then \\\
                local delta = dcsCommon.dist(center, aBase:getPoint())\\\
                if delta <= range then \\\
                    table.insert(ABinRange, aBase)\\\
                end\\\
            end        \\\
        end\\\
        \\\
        if includeCenter then \\\
            table.insert(ABinRange, airbase)\\\
        end\\\
        \\\
        return ABinRange\\\
    end\\\
\\\
    function dcsCommon.getAirbasesInRangeOfAirbaseList(theCenterList, includeList, range, filterCat, filterCoalition)\\\
        local collectorDict = {}\\\
        for idx, aCenter in pairs(theCenterList) do \\\
            -- get all surrounding airbases. returns list of airfields \\\
            local surroundingAB = dcsCommon.getAirbasesInRangeOfAirbase(airbase, includeList, range, filterCat, filterCoalition)\\\
            \\\
            for idx2, theAirField in pairs (surroundingAB) do \\\
                collectorDict[airField] = theAirField \\\
            end\\\
        end\\\
        \\\
        -- make result an array\\\
        local theABList = dcsCommon.enumerateTable(collectorDict)\\\
        return theABList\\\
    end\\\
\\\
    -- getAirbasesWhoseNameContains - get all airbases containing \\\
    -- a name. filterCat is optional and can be aerodrome (0), farp (1), ship (2)\\\
    -- filterCoalition is optional and can be 0 (neutral), 1 (red), 2 (blue) \\\
    -- if no name given or aName = \\\"*\\\", then all bases are returned prior to filtering \\\
    function dcsCommon.getAirbasesWhoseNameContains(aName, filterCat, filterCoalition)\\\
        --trigger.action.outText(\\\"getAB(name): enter with \\\" .. aName, 30)\\\
        if not aName then aName = \\\"*\\\" end \\\
        local allYourBase = world.getAirbases() -- get em all \\\
        local areBelongToUs = {}\\\
        -- now iterate all bases\\\
        for idx, aBase in pairs(allYourBase) do\\\
            local airBaseName = aBase:getName() -- get display name\\\
            if aName == \\\"*\\\" or dcsCommon.containsString(airBaseName, aName) then \\\
                -- containsString is case insesitive unless told otherwise\\\
                --if aName ~= \\\"*\\\" then \\\
                --    trigger.action.outText(\\\"getAB(name): matched \\\" .. airBaseName, 30)\\\
                --end \\\
                local doAdd = true \\\
                if filterCat then \\\
                    -- make sure the airbase is of that category \\\
                    local airCat = dcsCommon.getAirbaseCat(aBase)\\\
                    doAdd = doAdd and airCat == filterCat \\\
                end\\\
                \\\
                if filterCoalition then \\\
                    doAdd = doAdd and filterCoalition == aBase:getCoalition()\\\
                end\\\
                \\\
                if doAdd then \\\
                    -- all good, add to table\\\
                    table.insert(areBelongToUs, aBase)\\\
                end            \\\
            end\\\
        end\\\
        return areBelongToUs\\\
    end\\\
\\\
    function dcsCommon.getFirstAirbaseWhoseNameContains(aName, filterCat, filterCoalition)\\\
        local allBases = dcsCommon.getAirbasesWhoseNameContains(aName, filterCat, filterCoalition)\\\
        for idx, aBase in pairs (allBases) do \\\
            -- simply return first \\\
            return aBase\\\
        end\\\
        return nil \\\
    end    \\\
\\\
    function dcsCommon.getClosestAirbaseTo(thePoint, filterCat, filterCoalition)\\\
        local delta = math.huge\\\
        local allYourBase = dcsCommon.getAirbasesWhoseNameContains(\\\"*\\\", filterCat, filterCoalition) -- get em all and filter\\\
        local closestBase = nil \\\
        for idx, aBase in pairs(allYourBase) do\\\
            -- iterate them all \\\
            local abPoint = aBase:getPoint()\\\
            newDelta = dcsCommon.dist(thePoint, {x=abPoint.x, y = 0, z=abPoint.z})\\\
            if newDelta < delta then \\\
                delta = newDelta\\\
                closestBase = aBase\\\
            end\\\
        end\\\
        return closestBase, delta \\\
    end\\\
\\\
-- \\\
-- U N I T S   M A N A G E M E N T \\\
--\\\
\\\
    -- number of living units in group\\\
    function dcsCommon.livingUnitsInGroup(group)\\\
        local living = 0\\\
        local allUnits = group:getUnits()\\\
        for key, aUnit in pairs(allUnits) do \\\
            if aUnit:isExist() and aUnit:getLife() >= 1 then \\\
                living = living + 1\\\
            end\\\
        end\\\
        return living\\\
    end\\\
\\\
    -- closest living unit in group to a point\\\
    function dcsCommon.getClosestLivingUnitToPoint(group, p)\\\
        if not p then return nil end\\\
        if not group then return nil end\\\
        local closestUnit = nil\\\
        local closestDist = math.huge\\\
        local allUnits = group:getUnits()\\\
        for key, aUnit in pairs(allUnits) do \\\
            if aUnit:isExist() and aUnit:getLife() >= 1 then \\\
                local thisDist = dcsCommon.dist(p, aUnit:getPoint())\\\
                if thisDist < closestDist then \\\
                    closestDist = thisDist\\\
                    closestUnit = aUnit \\\
                end\\\
            end\\\
        end\\\
        return closestUnit, closestDist\\\
    end\\\
    \\\
    -- closest living group to a point - cat can be nil or one of Group.Category = { AIRPLANE = 0, HELICOPTER = 1, GROUND = 2, SHIP = 3, TRAIN = 4}\\\
    function dcsCommon.getClosestLivingGroupToPoint(p, coal, cat) \\\
        if not cat then cat = 2 end -- ground is default \\\
        local closestGroup = nil;\\\
        local closestGroupDist = math.huge\\\
        local allGroups =  coalition.getGroups(coal, cat) -- get all groups from this coalition, perhaps filtered by cat \\\
        for key, grp in pairs(allGroups) do\\\
            local closestUnit, dist = dcsCommon.getClosestLivingUnitToPoint(grp, p)\\\
            if closestUnit then \\\
                if dist < closestGroupDist then \\\
                    closestGroup = grp\\\
                    closestGroupDist = dist\\\
                end\\\
            end            \\\
        end\\\
        return closestGroup, closestGroupDist\\\
    end\\\
\\\
    function dcsCommon.getLivingGroupsAndDistInRangeToPoint(p, range, coal, cat) \\\
        if not cat then cat = 2 end -- ground is default \\\
        local groupsInRange = {};\\\
        local allGroups = coalition.getGroups(coal, cat) -- get all groups from this coalition, perhaps filtered by cat \\\
        for key, grp in pairs(allGroups) do\\\
            local closestUnit, dist = dcsCommon.getClosestLivingUnitToPoint(grp, p)\\\
            if closestUnit then \\\
                if dist < range then \\\
                    table.insert(groupsInRange, {group = grp, dist = dist}) -- array\\\
                end\\\
            end            \\\
        end\\\
        -- sort the groups by distance\\\
        table.sort(groupsInRange, function (left, right) return left.dist < right.dist end )\\\
        return groupsInRange\\\
    end\\\
\\\
    -- distFlat ignores y, input must be xyz points, NOT xy points  \\\
    function dcsCommon.distFlat(p1, p2) \\\
        local point1 = {x = p1.x, y = 0, z=p1.z}\\\
        local point2 = {x = p2.x, y = 0, z=p2.z}\\\
        return dcsCommon.dist(point1, point2)\\\
    end\\\
    \\\
    -- distance between points\\\
    function dcsCommon.dist(point1, point2)     -- returns distance between two points\\\
      -- supports xyz and xy notations\\\
      if not point1 then \\\
        trigger.action.outText(\\\"+++ warning: nil point1 in common:dist\\\", 30)\\\
        point1 = {x=0, y=0, z=0}\\\
      end\\\
\\\
      if not point2 then \\\
        trigger.action.outText(\\\"+++ warning: nil point2 in common:dist\\\", 30)\\\
        point2 = {x=0, y=0, z=0}\\\
        stop.here.now = 1\\\
      end\\\
      \\\
      local p1 = {x = point1.x, y = point1.y}\\\
      if not point1.z then \\\
        p1.z = p1.y\\\
        p1.y = 0\\\
      else \\\
        p1.z = point1.z\\\
      end\\\
      \\\
      local p2 = {x = point2.x, y = point2.y}\\\
      if not point2.z then \\\
        p2.z = p2.y\\\
        p2.y = 0\\\
      else \\\
        p2.z = point2.z\\\
      end\\\
      \\\
      local x = p1.x - p2.x\\\
      local y = p1.y - p2.y \\\
      local z = p1.z - p2.z\\\
      \\\
      return (x*x + y*y + z*z)^0.5\\\
    end\\\
\\\
    function dcsCommon.delta(name1, name2) -- returns distance (in meters) of two named objects\\\
      local n1Pos = Unit.getByName(name1):getPosition().p\\\
      local n2Pos = Unit.getByName(name2):getPosition().p\\\
      return dcsCommon.dist(n1Pos, n2Pos)\\\
    end\\\
\\\
    -- lerp between a and b, x being 0..1 (percentage), clipped to [0..1]\\\
    function dcsCommon.lerp(a, b, x) \\\
        if not a then return 0 end\\\
        if not b then return 0 end\\\
        if not x then return a end\\\
        if x < 0 then x = 0 end \\\
        if x > 1 then x = 1 end \\\
        return a + (b - a ) * x\\\
    end\\\
\\\
    function dcsCommon.bearingFromAtoB(A, B) -- coords in x, z \\\
        dx = B.x - A.x\\\
        dz = B.z - A.z\\\
        bearing = math.atan2(dz, dx) -- in radiants\\\
        return bearing\\\
    end\\\
\\\
    function dcsCommon.bearingInDegreesFromAtoB(A, B)\\\
        local bearing = dcsCommon.bearingFromAtoB(A, B) -- in rads \\\
        bearing = math.floor(bearing / math.pi * 180)\\\
        if bearing < 0 then bearing = bearing + 360 end\\\
        if bearing > 360 then bearing = bearing - 360 end\\\
        return bearing\\\
    end\\\
    \\\
    function dcsCommon.compassPositionOfARelativeToB(A, B)\\\
        -- warning: is REVERSE in order for bearing, returns a string like 'Sorth', 'Southwest'\\\
        if not A then return \\\"***error:A***\\\" end\\\
        if not B then return \\\"***error:B***\\\" end\\\
        local bearing = dcsCommon.bearingInDegreesFromAtoB(B, A) -- returns 0..360\\\
        if bearing < 23 then return \\\"North\\\" end \\\
        if bearing < 68 then return \\\"NE\\\" end\\\
        if bearing < 112 then return \\\"East\\\" end \\\
        if bearing < 158 then return \\\"SE\\\" end \\\
        if bearing < 202 then return \\\"South\\\" end \\\
        if bearing < 248 then return \\\"SW\\\" end \\\
        if bearing < 292 then return \\\"West\\\" end\\\
        if bearing < 338 then return \\\"NW\\\" end \\\
        return \\\"North\\\"\\\
    end\\\
    \\\
    function dcsCommon.clockPositionOfARelativeToB(A, B, headingOfBInDegrees)\\\
        -- o'clock notation \\\
        if not A then return \\\"***error:A***\\\" end\\\
        if not B then return \\\"***error:B***\\\" end\\\
        if not headingOfBInDegrees then headingOfBInDegrees = 0 end \\\
        \\\
        local bearing = dcsCommon.bearingInDegreesFromAtoB(B, A) -- returns 0..360\\\
--        trigger.action.outText(\\\"+++comm: oclock - bearing = \\\" .. bearing .. \\\" and inHeading = \\\" .. headingOfBInDegrees, 30) \\\
        bearing = bearing - headingOfBInDegrees\\\
        return dcsCommon.getClockDirection(bearing)\\\
        \\\
    end \\\
    \\\
    -- given a heading, return clock with 0 being 12, 180 being 6 etc.\\\
    function dcsCommon.getClockDirection(direction) -- inspired by cws, improvements my own\\\
        if not direction then return 0 end\\\
        direction = math.fmod (direction, 360)\\\
        while direction < 0 do \\\
            direction = direction + 360\\\
        end\\\
        \\\
        if direction < 15 then -- special case 12 o'clock past 12 o'clock\\\
            return 12\\\
        end\\\
    \\\
        direction = direction + 15 -- add offset so we get all other times correct\\\
        return math.floor(direction/30)\\\
    \\\
    end\\\
\\\
    \\\
    function dcsCommon.randomDegrees()\\\
        local degrees = math.random(360) * 3.14152 / 180\\\
        return degrees\\\
    end\\\
\\\
    function dcsCommon.randomPercent()\\\
        local percent = math.random(100)/100\\\
        return percent\\\
    end\\\
\\\
    function dcsCommon.randomPointOnPerimeter(sourceRadius, x, z) \\\
        return dcsCommon.randomPointInCircle(sourceRadius, sourceRadius-1, x, z)\\\
    end\\\
\\\
    function dcsCommon.randomPointInCircle(sourceRadius, innerRadius, x, z)\\\
        if not x then x = 0 end\\\
        --local y = 0\\\
        if not innerRadius then innerRadius = 0 end        \\\
        if innerRadius < 0 then innerRadius = 0 end\\\
        \\\
        local percent = dcsCommon.randomPercent() -- 1 / math.random(100)\\\
        -- now lets get a random degree\\\
        local degrees = dcsCommon.randomDegrees() -- math.random(360) * 3.14152 / 180 -- ok, it's actually radiants. \\\
        local r = (sourceRadius-innerRadius) * percent \\\
        local x = x + (innerRadius + r) * math.cos(degrees)\\\
        local z = z + (innerRadius + r) * math.sin(degrees)\\\
    \\\
        local thePoint = {}\\\
        thePoint.x = x\\\
        thePoint.y = 0\\\
        thePoint.z = z \\\
        \\\
        return thePoint, degrees\\\
    end\\\
\\\
    -- get group location: get the group's location by \\\
    -- accessing the fist existing, alive member of the group that it finds\\\
    function dcsCommon.getGroupLocation(group)\\\
        -- nifty trick from mist: make this work with group and group name\\\
        if type(group) == 'string' then -- group name\\\
            group = Group.getByName(group)\\\
        end\\\
        \\\
        -- get all units\\\
        local allUnits = group:getUnits()\\\
\\\
        -- iterate through all members of group until one is alive and exists\\\
        for index, theUnit in pairs(allUnits) do \\\
            if (theUnit:isExist() and theUnit:getLife() > 0) then \\\
                return theUnit:getPosition().p \\\
            end;\\\
        end\\\
\\\
        -- if we get here, there was no live unit \\\
        --trigger.action.outText(\\\"+++cmn: A group has no live units. returning nil\\\", 10)\\\
        return nil \\\
        \\\
    end\\\
\\\
    -- get the group's first Unit that exists and is \\\
    -- alive \\\
    function dcsCommon.getGroupUnit(group)\\\
        if not group then return nil  end\\\
        \\\
        -- nifty trick from mist: make this work with group and group name\\\
        if type(group) == 'string' then -- group name\\\
            group = Group.getByName(group)\\\
        end\\\
        \\\
        if not group:isExist() then return nil end \\\
        \\\
        -- get all units\\\
        local allUnits = group:getUnits()\\\
\\\
        -- iterate through all members of group until one is alive and exists\\\
        for index, theUnit in pairs(allUnits) do \\\
            if (theUnit:isExist() and theUnit:getLife() > 0) then \\\
                return theUnit\\\
            end;\\\
        end\\\
\\\
        -- if we get here, there was no live unit \\\
        --trigger.action.outText(\\\"+++cmn A group has no live units. returning nil\\\", 10)\\\
        return nil \\\
        \\\
    end\\\
\\\
    -- and here the alias\\\
    function dcsCommon.getFirstLivingUnit(group)\\\
        return dcsCommon.getGroupUnit(group)\\\
    end\\\
    \\\
    -- isGroupAlive returns true if there is at least one unit in the group that isn't dead\\\
    function dcsCommon.isGroupAlive(group)\\\
        return (dcsCommon.getGroupUnit(group) ~= nil) \\\
    end\\\
\\\
    function dcsCommon.getLiveGroupUnits(group)\\\
        -- nifty trick from mist: make this work with group and group name\\\
        if type(group) == 'string' then -- group name\\\
            group = Group.getByName(group)\\\
        end\\\
        \\\
        local liveUnits = {}\\\
        -- get all units\\\
        local allUnits = group:getUnits()\\\
\\\
        -- iterate through all members of group until one is alive and exists\\\
        for index, theUnit in pairs(allUnits) do \\\
            if (theUnit:isExist() and theUnit:getLife() > 0) then \\\
                table.insert(liveUnits, theUnit) \\\
            end;\\\
        end\\\
\\\
        -- if we get here, there was no live unit \\\
        return liveUnits\\\
    end\\\
\\\
    function dcsCommon.getGroupTypeString(group) -- convert into comma separated types \\\
        if not group then \\\
            trigger.action.outText(\\\"+++cmn getGroupTypeString: nil group\\\", 30)\\\
            return \\\"\\\" \\\
        end\\\
        if not dcsCommon.isGroupAlive(group) then \\\
            trigger.action.outText(\\\"+++cmn getGroupTypeString: dead group\\\", 30)\\\
            return \\\"\\\" \\\
        end \\\
        local theTypes = \\\"\\\"\\\
        local liveUnits = dcsCommon.getLiveGroupUnits(group)\\\
        for i=1, #liveUnits do \\\
            if i > 1 then theTypes = theTypes .. \\\",\\\" end\\\
            theTypes = theTypes .. liveUnits[i]:getTypeName()\\\
        end\\\
        return theTypes\\\
    end\\\
\\\
    function dcsCommon.getGroupTypes(group) \\\
        if not group then \\\
            trigger.action.outText(\\\"+++cmn getGroupTypes: nil group\\\", 30)\\\
            return {}\\\
        end\\\
        if not dcsCommon.isGroupAlive(group) then \\\
            trigger.action.outText(\\\"+++cmn getGroupTypes: dead group\\\", 30)\\\
            return {}\\\
        end \\\
        local liveUnits = dcsCommon.getLiveGroupUnits(group)\\\
        local unitTypes = {}\\\
        for i=1, #liveUnits do \\\
            table.insert(unitTypes, liveUnits[i]:getTypeName())\\\
        end\\\
        return unitTypes\\\
    end\\\
\\\
    function dcsCommon.getEnemyCoalitionFor(aCoalition)\\\
        if aCoalition == 1 then return 2 end\\\
        if aCoalition == 2 then return 1 end\\\
        if type(aCoalition) == \\\"string\\\" then \\\
            aCoalition = aCoalition:lower()\\\
            if aCoalition == \\\"red\\\" then return 2 end\\\
            if aCoalition == \\\"blue\\\" then return 1 end\\\
        end\\\
        return nil\\\
    end\\\
\\\
    function dcsCommon.getACountryForCoalition(aCoalition)\\\
        -- scan the table of countries and get the first country that is part of aCoalition\\\
        -- this is useful if you want to create troops for a coalition but don't know the\\\
        -- coalition's countries \\\
        -- we start with id=0 (Russia), go to id=85 (Slovenia), but skip id = 14\\\
        local i = 0\\\
        while i < 86 do \\\
            if i ~= 14 then \\\
                if (coalition.getCountryCoalition(i) == aCoalition) then return i end\\\
            end\\\
            i = i + 1\\\
        end\\\
        \\\
        return nil\\\
    end\\\
--\\\
--\\\
-- C A L L B A C K   H A N D L E R \\\
--\\\
--\\\
\\\
    -- installing callbacks\\\
    -- based on mist, with optional additional hooks for pre- and post-\\\
    -- processing of the event\\\
    -- when filtering occurs in pre, an alternative 'rejected' handler can be called \\\
    function dcsCommon.addEventHandler(f, pre, post, rejected) -- returns ID \\\
        local handler = {} -- build a wrapper and connect the onEvent\\\
        --dcsCommon.cbID = dcsCommon.cbID + 1 -- increment unique count\\\
        handler.id = dcsCommon.uuid(\\\"eventHandler\\\")\\\
        handler.f = f -- the callback itself\\\
        if (rejected) then handler.rejected = rejected end\\\
        -- now set up pre- and post-processors. defaults are set in place\\\
        -- so pre and post are optional. If pre returns false, the callback will\\\
        -- not be invoked\\\
        if (pre) then handler.pre = pre else handler.pre = dcsCommon.preCall end\\\
        if (post) then handler.post = post else handler.post = dcsCommon.postCall end\\\
        function handler:onEvent(event)\\\
            if not self.pre(event) then \\\
                if dcsCommon.verbose then\\\
--                    trigger.action.outText(\\\"event \\\" .. event.id .. \\\" discarded by pre-processor\\\", 10)\\\
                end\\\
                if (self.rejected) then self.rejected(event) end \\\
                return\\\
            end\\\
            self.f(event) -- call the handler\\\
            self.post(event) -- do post-processing\\\
        end\\\
        world.addEventHandler(handler)\\\
        return handler.id\\\
    end\\\
\\\
    function dcsCommon.preCall(e)\\\
        -- we can filter here\\\
        -- if we return false, the call is abortet\\\
        if dcsCommon.verbose then\\\
            trigger.action.outText(\\\"event \\\" .. e.id .. \\\" received: PRE-PROCESSING\\\", 10)\\\
        end\\\
        return true;\\\
    end;\\\
\\\
    function dcsCommon.postCall(e)\\\
        -- we do pos proccing here \\\
        if dcsCommon.verbose then\\\
            trigger.action.outText(\\\"event \\\" .. e.id .. \\\" received: post proc\\\", 10)\\\
        end\\\
    end\\\
    \\\
    -- highly specific eventhandler for one event only\\\
    -- based on above, with direct filtering built in; skips pre\\\
    -- but does post\\\
    function dcsCommon.addEventHandlerForEventTypes(f, evTypes, post, rejected) -- returns ID \\\
        local handler = {} -- build a wrapper and connect the onEvent\\\
        dcsCommon.cbID = dcsCommon.cbID + 1 -- increment unique count\\\
        handler.id = dcsCommon.cbID\\\
        handler.what = evTypes\\\
        if (rejected) then handler.rejected = rejected end \\\
        \\\
        handler.f = f -- set the callback itself\\\
        -- now set up post-processor. pre is hard-coded to match evType\\\
        -- post is optional. If event.id is not in evTypes, the callback will\\\
        -- not be invoked\\\
        if (post) then handler.post = post else handler.post = dcsCommon.postCall end\\\
        function handler:onEvent(event)\\\
            hasMatch = false;\\\
            for key, evType in pairs(self.what) do\\\
                if evType == event.id then\\\
                    hasMatch = true;\\\
                    break;\\\
                end;\\\
            end;\\\
            if not hasMatch then \\\
                if dcsCommon.verbose then\\\
                    trigger.action.outText(\\\"event \\\" .. e.id .. \\\" discarded - not in whitelist evTypes\\\", 10)\\\
                end\\\
                if (self.rejected) then self.rejected(event) end \\\
                return;\\\
            end;\\\
            \\\
            self.f(event) -- call the actual handler as passed to us\\\
            self.post(event) -- do post-processing \\\
        end\\\
        world.addEventHandler(handler) -- add to event handlers\\\
        return handler.id\\\
    end\\\
    \\\
    \\\
    \\\
    -- remove event handler / callback, identical to Mist \\\
    -- note we don't call world.removeEventHandler, but rather directly \\\
    -- access world.eventHandlers directly and remove kvp directly.\\\
    function dcsCommon.removeEventHandler(id)\\\
        for key, handler in pairs(world.eventHandlers) do\\\
            if handler.id and handler.id == id then\\\
                world.eventHandlers[key] = nil\\\
                return true\\\
            end\\\
        end\\\
        return false\\\
    end\\\
\\\
--\\\
--\\\
-- C L O N I N G \\\
--\\\
--\\\
    -- topClone is a shallow clone of orig, only top level is iterated,\\\
    -- all values are ref-copied\\\
    function dcsCommon.topClone(orig)\\\
        local orig_type = type(orig)\\\
        local copy\\\
        if orig_type == 'table' then\\\
            copy = {}\\\
            for orig_key, orig_value in pairs(orig) do\\\
                copy[orig_key] = orig_value\\\
            end\\\
        else -- number, string, boolean, etc\\\
            copy = orig\\\
        end\\\
        return copy\\\
    end\\\
\\\
    -- clone is a recursive clone which will also clone\\\
    -- deeper levels, as used in units \\\
    function dcsCommon.clone(orig)\\\
        local orig_type = type(orig)\\\
        local copy\\\
        if orig_type == 'table' then\\\
            copy = {}\\\
            for orig_key, orig_value in next, orig, nil do\\\
                copy[dcsCommon.clone(orig_key)] = dcsCommon.clone(orig_value)\\\
            end\\\
            setmetatable(copy, dcsCommon.clone(getmetatable(orig)))\\\
        else -- number, string, boolean, etc\\\
            copy = orig\\\
        end\\\
        return copy\\\
    end\\\
\\\
\\\
--\\\
-- \\\
-- S P A W N I N G \\\
-- \\\
-- \\\
\\\
    function dcsCommon.createEmptyGroundGroupData (name)\\\
        local theGroup = {} -- empty group\\\
        theGroup.visible = false\\\
        theGroup.taskSelected = true\\\
        -- theGroup.route = {}\\\
        -- theGroup.groupId = id\\\
        theGroup.tasks = {}\\\
        -- theGroup.hidden = false -- hidden on f10?\\\
\\\
        theGroup.units = { } -- insert units here! -- use addUnitToGroupData\\\
\\\
        theGroup.x = 0\\\
        theGroup.y = 0\\\
        theGroup.name = name\\\
        -- theGroup.start_time = 0\\\
        theGroup.task = \\\"Ground Nothing\\\"\\\
        \\\
        return theGroup\\\
    end;\\\
\\\
    function dcsCommon.createEmptyAircraftGroupData (name)\\\
        local theGroup = dcsCommon.createEmptyGroundGroupData(name)--{} -- empty group\\\
\\\
        theGroup.task = \\\"Nothing\\\" -- can be others, like Transport, CAS, etc\\\
        -- returns with empty route\\\
        theGroup.route = dcsCommon.createEmptyAircraftRouteData() -- we can add points here \\\
        return theGroup\\\
    end;\\\
\\\
    function dcsCommon.createAircraftRoutePointData(x, z, altitudeInFeet, knots, altType, action)\\\
        local rp = {}\\\
        rp.x = x\\\
        rp.y = z\\\
        rp.action = \\\"Turning Point\\\"\\\
        rp.type = \\\"Turning Point\\\"\\\
        if action then rp.action = action; rp.type = action end -- warning: may not be correct, need to verify later\\\
        rp.alt = altitudeInFeet * 0.3048\\\
        rp.speed = knots * 0.514444 -- we use \\\
        rp.alt_type = \\\"BARO\\\"\\\
        if (altType) then rp.alt_type = altType end \\\
        return rp\\\
    end\\\
\\\
    function dcsCommon.addRoutePointDataToRouteData(inRoute, x, z, altitudeInFeet, knots, altType, action)\\\
        local p = dcsCommon.createAircraftRoutePointData(x, z, altitudeInFeet, knots, altType, action)\\\
        local thePoints = inRoute.points \\\
        table.insert(thePoints, p)\\\
    end\\\
    \\\
    function dcsCommon.addRoutePointDataToGroupData(group, x, z, altitudeInFeet, knots, altType, action)\\\
        if not group.route then group.route = dcsCommon.createEmptyAircraftRouteData() end\\\
        local theRoute = group.route \\\
        dcsCommon.addRoutePointDataToRouteData(theRoute, x, z, altitudeInFeet, knots, altType, action)\\\
    end\\\
\\\
    function dcsCommon.addRoutePointForGroupData(theGroup, theRP)\\\
        if not theGroup then return end \\\
        if not theGroup.route then theGroup.route = dcsCommon.createEmptyAircraftRouteData() end\\\
        \\\
        local theRoute = theGroup.route \\\
        local thePoints = theRoute.points \\\
        table.insert(thePoints, theRP)\\\
    end\\\
    \\\
    function dcsCommon.createEmptyAircraftRouteData()\\\
        local route = {}\\\
        route.points = {}\\\
        return route\\\
    end\\\
\\\
    function dcsCommon.createTakeOffFromParkingRoutePointData(aerodrome)\\\
        if not aerodrome then return nil end \\\
            \\\
        local rp = {}    \\\
        local freeParkingSlot = dcsCommon.getFirstFreeParkingSlot(aerodrome, 104) -- get big slot first \\\
        if not freeParkingSlot then \\\
            freeParkingSlot = dcsCommon.getFirstFreeParkingSlot(aerodrome) -- try any size\\\
        end\\\
            \\\
        if not freeParkingSlot then \\\
            trigger.action.outText(\\\"civA: no free parking at \\\" .. aerodrome:getName(), 30)\\\
            return nil \\\
        end\\\
            \\\
        local p = freeParkingSlot.vTerminalPos\\\
            \\\
        rp.airdromeId = aerodrome:getID() \\\
        rp.x = p.x\\\
        rp.y = p.z\\\
        rp.alt = p.y \\\
        rp.action = \\\"From Parking Area\\\"\\\
        rp.type = \\\"TakeOffParking\\\"\\\
            \\\
        rp.speed = 100; -- in m/s? If so, that's 360 km/h \\\
        rp.alt_type = \\\"BARO\\\"\\\
        return rp\\\
    end\\\
\\\
    function dcsCommon.createOverheadAirdromeRoutPintData(aerodrome)\\\
        if not aerodrome then return nil end \\\
        local rp = {}            \\\
        local p = aerodrome:getPoint()\\\
        rp.x = p.x\\\
        rp.y = p.z\\\
        rp.alt = p.y + 2000 -- 6000 ft overhead\\\
        rp.action = \\\"Turning Point\\\"\\\
        rp.type = \\\"Turning Point\\\"\\\
            \\\
        rp.speed = 133; -- in m/s? If so, that's 360 km/h \\\
        rp.alt_type = \\\"BARO\\\"\\\
        return rp\\\
    end\\\
    \\\
\\\
    function dcsCommon.createLandAtAerodromeRoutePointData(aerodrome)\\\
        if not aerodrome then return nil end \\\
            \\\
        local rp = {}            \\\
        local p = aerodrome:getPoint()\\\
        rp.airdromeId = aerodrome:getID() \\\
        rp.x = p.x\\\
        rp.y = p.z\\\
        rp.alt = p.y \\\
        rp.action = \\\"Landing\\\"\\\
        rp.type = \\\"Land\\\"\\\
            \\\
        rp.speed = 100; -- in m/s? If so, that's 360 km/h \\\
        rp.alt_type = \\\"BARO\\\"\\\
        return rp\\\
    end\\\
\\\
    \\\
    function dcsCommon.createRPFormationData(findex) -- must be added as \\\"task\\\" to an RP. use 4 for Echelon right\\\
        local task = {}\\\
        task.id = \\\"ComboTask\\\"\\\
        local params = {}\\\
        task.params = params\\\
        local tasks = {}\\\
        params.tasks = tasks\\\
        local t1 = {}\\\
        tasks[1] = t1\\\
        t1.number = 1\\\
        t1.auto = false \\\
        t1.id = \\\"WrappedAction\\\"\\\
        t1.enabled = true\\\
        local t1p = {}\\\
        t1.params = t1p\\\
        local action = {}\\\
        t1p.action = action \\\
        action.id = \\\"Option\\\"\\\
        local ap = {}\\\
        action.params = ap\\\
        ap.variantIndex = 3\\\
        ap.name = 5 -- AI.Option.Air.ID 5 = Formation \\\
        ap.formationIndex = findex -- 4 is echelon_right\\\
        ap.value = 262147\\\
        \\\
        return task \\\
    end\\\
\\\
    function dcsCommon.addTaskDataToRP(theTask, theGroup, rpIndex)\\\
        local theRoute = theGroup.route\\\
        local thePoints = theRoute.points\\\
        local rp = thePoints[rpIndex]\\\
        rp.task = theTask\\\
    end\\\
    \\\
    -- create a minimal payload table that is compatible with creating \\\
    -- a unit. you may need to alter this before adding the unit to\\\
    -- the mission. all params optional \\\
    function dcsCommon.createPayload(fuel, flare, chaff, gun) \\\
        local payload = {}\\\
        payload.pylons = {}\\\
        if not fuel then fuel = 1000 end -- in kg. check against fuelMassMax in type desc\\\
        if not flare then flare = 0 end\\\
        if not chaff then chaff = 0 end\\\
        if not gun then gun = 0 end\\\
        return payload \\\
        \\\
    end\\\
\\\
    function dcsCommon.createCallsign(cs) \\\
        local callsign = {}\\\
        callsign[1] = 1\\\
        callsign[2] = 1\\\
        callsign[3] = 1\\\
        if not cs then cs = \\\"Enfield11\\\" end\\\
        callsign.name = cs\\\
        return callsign\\\
    end\\\
    \\\
\\\
    -- create the data table required to spawn a unit.\\\
    -- unit types are defined in https://github.com/mrSkortch/DCS-miscScripts/tree/master/ObjectDB\\\
    function dcsCommon.createGroundUnitData(name, unitType, transportable)\\\
        local theUnit = {}\\\
        unitType = dcsCommon.trim(unitType)\\\
        theUnit.type = unitType -- e.g. \\\"LAV-25\\\",\\\
        if not transportable then transportable = false end -- elaborate, not requried code\\\
        theUnit.transportable = {[\\\"randomTransportable\\\"] = transportable} \\\
        -- theUnit.unitId = id \\\
        theUnit.skill = \\\"Average\\\" -- always average \\\
        theUnit.x = 0 -- make it zero, zero!\\\
        theUnit.y = 0\\\
        theUnit.name = name\\\
        theUnit.playerCanDrive = false\\\
        theUnit.heading = 0\\\
        return theUnit\\\
    end \\\
\\\
    function dcsCommon.createAircraftUnitData(name, unitType, transportable, altitude, speed, heading)\\\
        local theAirUnit = dcsCommon.createGroundUnitData(name, unitType, transportable)\\\
        theAirUnit.alt = 100 -- make it 100m\\\
        if altitude then theAirUnit.alt = altitude end \\\
        theAirUnit.alt_type = \\\"RADIO\\\" -- AGL\\\
        theAirUnit.speed = 77 -- m/s --> 150 knots\\\
        if speed then theAirUnit.speed = speed end \\\
        if heading then theAirUnit.heading = heading end \\\
        theAirUnit.payload = dcsCommon.createPayload()\\\
        theAirUnit.callsign = dcsCommon.createCallsign()\\\
        return theAirUnit\\\
    end\\\
    \\\
\\\
    function dcsCommon.addUnitToGroupData(theUnit, theGroup, dx, dy, heading)\\\
        -- add a unit to a group, and place it at dx, dy of group's position,\\\
        -- taking into account unit's own current location\\\
        if not dx then dx = 0 end\\\
        if not dy then dy = 0 end\\\
        if not heading then heading = 0 end\\\
        theUnit.x = theUnit.x + dx + theGroup.x\\\
        theUnit.y = theUnit.y + dy + theGroup.y \\\
        theUnit.heading = heading\\\
        table.insert(theGroup.units, theUnit)\\\
    end;\\\
\\\
    function dcsCommon.createSingleUnitGroup(name, theUnitType, x, z, heading) \\\
        -- create the container \\\
        local theNewGroup = dcsCommon.createEmptyGroundGroupData(name)\\\
        local aUnit = {}\\\
        aUnit = dcsCommon.createGroundUnitData(name .. \\\"-1\\\", theUnitType, false)\\\
--        trigger.action.outText(\\\"dcsCommon - unit name retval \\\" .. aUnit.name, 30)\\\
        dcsCommon.addUnitToGroupData(aUnit, theNewGroup, x, z, heading)\\\
        return theNewGroup\\\
    end\\\
    \\\
\\\
    function dcsCommon.arrangeGroupDataIntoFormation(theNewGroup, radius, minDist, formation, innerRadius)\\\
        -- formations:\\\
        --    (default) \\\"line\\\" (left to right along x) -- that is Y direction\\\
        --    \\\"line_v\\\" a line top to bottom -- that is X direction\\\
        --    \\\"chevron\\\" - left to right middle too top\\\
        --    \\\"scattered\\\", \\\"random\\\" -- random, innerRadius used to clear area in center\\\
        --       \\\"circle\\\", \\\"circle_forward\\\" -- circle, forward facing\\\
        --    \\\"circle_in\\\" -- circle, inwarf facing\\\
        --    \\\"circle_out\\\" -- circle, outward facing\\\
        --    \\\"grid\\\", \\\"square\\\", \\\"rect\\\" -- optimal rectangle\\\
        --    \\\"2cols\\\", \\\"2deep\\\" -- 2 columns, n deep \\\
        --    \\\"2wide\\\" -- 2 columns wide, 2 deep \\\
\\\
        local num = #theNewGroup.units \\\
        \\\
        -- now do the formation stuff\\\
        -- make sure that they keep minimum  distance \\\
--        trigger.action.outText(\\\"dcsCommon - processing formation \\\" .. formation .. \\\" with radius = \\\" .. radius, 30)\\\
        if formation == \\\"LINE_V\\\" then \\\
            -- top to bottom in zone (heding 0). -- will run through x-coordinate \\\
            -- use entire radius top to bottom \\\
            local currX = -radius\\\
            local increment = radius * 2/(num - 1) -- MUST NOT TRY WITH 1 UNIT!\\\
            for i=1, num do\\\
            \\\
                local u = theNewGroup.units[i]\\\
--                trigger.action.outText(\\\"formation unit \\\" .. u.name .. \\\" currX = \\\" .. currX, 30)\\\
                u.x = currX\\\
                currX = currX + increment\\\
            end\\\
        \\\
        elseif formation == \\\"LINE\\\" then \\\
            -- left to right in zone. runs through Y\\\
            -- left and right are y because at heading 0, forward is x (not y as expected)\\\
            local currY = -radius\\\
            local increment = radius * 2/(num - 1) -- MUST NOT TRY WITH 1 UNIT!\\\
            for i=1, num do\\\
                local u = theNewGroup.units[i]\\\
--                trigger.action.outText(\\\"formation unit \\\" .. u.name .. \\\" currX = \\\" .. currY, 30)\\\
                u.y = currY\\\
                currY = currY + increment\\\
            end    \\\
        \\\
        elseif formation == \\\"CHEVRON\\\" then \\\
            -- left to right in zone. runs through Y\\\
            -- left and right are y because at heading 0, forward is x (not y as expected)\\\
            local currY = -radius\\\
            local currX = 0\\\
            local incrementY = radius * 2/(num - 1) -- MUST NOT TRY WITH 1 UNIT!\\\
            local incrementX = radius * 2/(num - 1) -- MUST NOT TRY WITH 1 UNIT!\\\
            for i=1, num do\\\
                local u = theNewGroup.units[i]\\\
--                trigger.action.outText(\\\"formation unit \\\" .. u.name .. \\\" currX = \\\" .. currX .. \\\" currY = \\\" .. currY, 30)\\\
                u.x = currX\\\
                u.y = currY\\\
                -- calc coords for NEXT iteration\\\
                currY = currY + incrementY -- march left to right\\\
                if i < num / 2 then -- march up\\\
                    currX = currX + incrementX \\\
                elseif i == num / 2 then -- even number, keep height\\\
                    currX = currX + 0 \\\
                else \\\
                    currX = currX - incrementX -- march down \\\
                end \\\
                -- note: when unit number even, the wedge is sloped. may need an odd/even test for better looks\\\
            end    \\\
\\\
        elseif formation == \\\"SCATTERED\\\" or formation == \\\"RANDOM\\\" then \\\
            -- use randomPointInCircle and tehn iterate over all vehicles for mindelta\\\
            processedUnits = {}\\\
            for i=1, num do\\\
                local emergencyBreak = 1 -- prevent endless loop\\\
                local lowDist = 10000\\\
                local uPoint = {}\\\
                local thePoint = {}\\\
                repeat     -- get random point intil mindistance to all is kept or emergencybreak\\\
                    for idx, rUnit in pairs(processedUnits) do -- get min dist to all positioned units\\\
                        thePoint = dcsCommon.randomPointInCircle(radius, innerRadius) -- returns x, 0, z\\\
                        uPoint.x = rUnit.x\\\
                        uPoint.y = 0\\\
                        uPoint.z = rUnit.y \\\
                        local dist = dcsCommon.dist(thePoint, uPoint) -- measure distance to unit\\\
                        if (dist < lowDist) then lowDist = dist end\\\
                    end\\\
                    emergencyBreak = emergencyBreak + 1\\\
                until (emergencyBreak > 20) or (lowDist > minDist)\\\
                -- we have random x, y \\\
                local u = theNewGroup.units[i] -- get unit to position\\\
                u.x = thePoint.x\\\
                u.y = thePoint.z -- z --> y mapping! \\\
                -- now add the unit to the 'processed' set \\\
                table.insert(processedUnits, u)\\\
            end    \\\
\\\
        elseif dcsCommon.stringStartsWith(formation, \\\"CIRCLE\\\") then\\\
            -- units are arranged on perimeter of circle defined by radius \\\
--            trigger.action.outText(\\\"formation circle detected\\\", 30)\\\
            local currAngle = 0\\\
            local angleInc = 2 * 3.14157 / num -- increase per spoke \\\
            for i=1, num do\\\
                local u = theNewGroup.units[i] -- get unit \\\
                u.x = radius * math.cos(currAngle)\\\
                u.y = radius * math.sin(currAngle)\\\
                \\\
                -- now baldower out heading \\\
                -- circle, circle_forward no modifier of heading\\\
                if dcsCommon.stringStartsWith(formation, \\\"CIRCLE_IN\\\") then \\\
                    -- make the heading inward faceing - that's angle + pi\\\
                    u.heading = u.heading + currAngle + 3.14157\\\
                elseif dcsCommon.stringStartsWith(formation, \\\"CIRCLE_OUT\\\") then \\\
                    u.heading = u.heading + currAngle + 0\\\
                end\\\
\\\
                currAngle = currAngle + angleInc\\\
            end\\\
        elseif formation == \\\"GRID\\\" or formation == \\\"SQUARE\\\" or formation == \\\"RECT\\\" then \\\
            if num < 2 then return end \\\
            -- arrange units in an w x h grid\\\
            -- e-g- 12 units = 4 x 3. \\\
            -- calculate w \\\
            local w = math.floor(num^(0.5) + 0.5)\\\
            dcsCommon.arrangeGroupInNColumns(theNewGroup, w, radius)\\\
            --[[--\\\
            local h = math.floor(num / w)\\\
            --trigger.action.outText(\\\"AdcsC: num=\\\" .. num .. \\\" w=\\\" .. w .. \\\"h=\\\" .. h .. \\\" -- num%w=\\\" .. num%w, 30)\\\
            if (num % w) > 0 then \\\
                h = h + 1\\\
            end\\\
            \\\
            --trigger.action.outText(\\\"BdcsC: num=\\\" .. num .. \\\" w=\\\" .. w .. \\\"h=\\\" .. h, 30)\\\
            \\\
            -- now w * h always >= num and num items fir in that grid\\\
            -- w is width, h is height, of course :) \\\
            -- now calculat xInc and yInc\\\
            local i = 1\\\
            local xInc = 0 \\\
            if w > 1 then xInc = 2 * radius / (w-1) end\\\
            local yInc = 0\\\
            if h > 1 then yInc = 2 * radius / (h-1) end \\\
            local currY = radius \\\
            if h < 2 then currY = 0 end -- special:_ place in Y middle if only one row)\\\
            while h > 0 do \\\
                local currX = radius \\\
                local wCnt = w \\\
                while wCnt > 0 and (i <= num) do \\\
                    local u = theNewGroup.units[i] -- get unit \\\
                    u.x = currX\\\
                    u.y = currY\\\
                    currX = currX - xInc\\\
                    wCnt = wCnt - 1\\\
                    i = i + 1\\\
                end\\\
                currY = currY - yInc \\\
                h = h - 1\\\
            end\\\
            --]]--\\\
        elseif formation == \\\"2DEEP\\\" or formation == \\\"2COLS\\\" then\\\
            if num < 2 then return end \\\
            -- arrange units in an 2 x h grid\\\
            local w = 2\\\
            dcsCommon.arrangeGroupInNColumnsDeep(theNewGroup, w, radius)\\\
\\\
        elseif formation == \\\"2WIDE\\\" then\\\
            if num < 2 then return end \\\
            -- arrange units in an 2 x h grid\\\
            local w = 2\\\
            dcsCommon.arrangeGroupInNColumns(theNewGroup, w, radius)\\\
        else \\\
            trigger.action.outText(\\\"dcsCommon - unknown formation: \\\" .. formation, 30)\\\
        end\\\
    \\\
    end\\\
    \\\
    function dcsCommon.arrangeGroupInNColumns(theNewGroup, w, radius)\\\
        local num = #theNewGroup.units\\\
        local h = math.floor(num / w)\\\
        if (num % w) > 0 then \\\
            h = h + 1\\\
        end\\\
        local i = 1\\\
        local xInc = 0 \\\
        if w > 1 then xInc = 2 * radius / (w-1) end\\\
        local yInc = 0\\\
        if h > 1 then yInc = 2 * radius / (h-1) end \\\
        local currY = radius \\\
        if h < 2 then currY = 0 end -- special:_ place in Y middle if only one row)\\\
        while h > 0 do \\\
            local currX = radius \\\
            local wCnt = w \\\
            while wCnt > 0 and (i <= num) do \\\
                local u = theNewGroup.units[i] -- get unit \\\
                u.x = currX\\\
                u.y = currY\\\
                currX = currX - xInc\\\
                wCnt = wCnt - 1\\\
                i = i + 1\\\
            end\\\
            currY = currY - yInc \\\
            h = h - 1\\\
        end\\\
    end\\\
    \\\
    function dcsCommon.arrangeGroupInNColumnsDeep(theNewGroup, w, radius)\\\
        local num = #theNewGroup.units\\\
        local h = math.floor(num / w)\\\
        if (num % w) > 0 then \\\
            h = h + 1\\\
        end\\\
        local i = 1\\\
        local yInc = 0 \\\
        if w > 1 then yInc = 2 * radius / (w-1) end\\\
        local xInc = 0\\\
        if h > 1 then xInc = 2 * radius / (h-1) end \\\
        local currX = radius \\\
        if h < 2 then currX = 0 end -- special:_ place in Y middle if only one row)\\\
        while h > 0 do \\\
            local currY = radius \\\
            local wCnt = w \\\
            while wCnt > 0 and (i <= num) do \\\
                local u = theNewGroup.units[i] -- get unit \\\
                u.x = currX\\\
                u.y = currY\\\
                currY = currY - yInc\\\
                wCnt = wCnt - 1\\\
                i = i + 1\\\
            end\\\
            currX = currX - xInc \\\
            h = h - 1\\\
        end\\\
    end\\\
    \\\
    \\\
    function dcsCommon.createGroundGroupWithUnits(name, theUnitTypes, radius, minDist, formation, innerRadius)\\\
        if not minDist then mindist = 4 end -- meters\\\
        if not formation then formation = \\\"line\\\" end \\\
        if not radius then radius = 30 end -- meters \\\
        if not innerRadius then innerRadius = 0 end\\\
        formation = formation:upper()\\\
        -- theUnitTypes can be either a single string or a table of strings\\\
        -- see here for TypeName https://github.com/mrSkortch/DCS-miscScripts/tree/master/ObjectDB\\\
        -- formation defines how the units are going to be arranged in the\\\
        -- formation specified. \\\
        -- formations:\\\
        --    (default) \\\"line\\\" (left to right along x) -- that is Y direction\\\
        --    \\\"line_V\\\" a line top to bottom -- that is X direction\\\
        --    \\\"chevron\\\" - left to right middle too top\\\
        --    \\\"scattered\\\", \\\"random\\\" -- random, innerRadius used to clear area in center\\\
        --       \\\"circle\\\", \\\"circle_forward\\\" -- circle, forward facing\\\
        --    \\\"circle_in\\\" -- circle, inwarf facing\\\
        --    \\\"circle_out\\\" -- circle, outward facing\\\
\\\
        -- first, we create a group\\\
        local theNewGroup = dcsCommon.createEmptyGroundGroupData(name)\\\
        \\\
        -- now add a single unit or multiple units\\\
        if type(theUnitTypes) ~= \\\"table\\\" then \\\
--            trigger.action.outText(\\\"dcsCommon - i am here\\\", 30)\\\
--            trigger.action.outText(\\\"dcsCommon - name \\\" .. name, 30)\\\
--            trigger.action.outText(\\\"dcsCommon - unit type \\\" .. theUnitTypes, 30)\\\
            \\\
            local aUnit = {}\\\
            aUnit = dcsCommon.createGroundUnitData(name .. \\\"-1\\\", theUnitTypes, false)\\\
--            trigger.action.outText(\\\"dcsCommon - unit name retval \\\" .. aUnit.name, 30)\\\
            dcsCommon.addUnitToGroupData(aUnit, theNewGroup, 0, 0) -- create with data at location (0,0)\\\
            return theNewGroup\\\
        end \\\
\\\
        -- if we get here, theUnitTypes is a table\\\
        -- now loop and create a unit for each table\\\
        local num = 1\\\
        for key, theType in pairs(theUnitTypes) do \\\
--            trigger.action.outText(\\\"creating unit \\\" .. name .. \\\"-\\\" .. num, 30)\\\
            local aUnit = dcsCommon.createGroundUnitData(name .. \\\"-\\\"..num, theType, false)\\\
            dcsCommon.addUnitToGroupData(aUnit, theNewGroup, 0, 0)\\\
            num = num + 1\\\
        end\\\
        \\\
        dcsCommon.arrangeGroupDataIntoFormation(theNewGroup, radius, minDist, formation, innerRadius)\\\
        return theNewGroup\\\
\\\
    \\\
    end\\\
\\\
-- create a new group, based on group in mission. Groups coords are 0,0 for group and all\\\
-- x,y and heading\\\
    function dcsCommon.createGroupDataFromLiveGroup(name, newName) \\\
        if not newName then newName = dcsCommon.uuid(\\\"uniqName\\\") end\\\
        -- get access to the group\\\
        local liveGroup = Group.getByName(name)\\\
        if not liveGroup then return nil end\\\
        -- get the categorty\\\
        local cat = liveGroup:getCategory()\\\
        local theNewGroup = {}\\\
        \\\
        -- create a new empty group at (0,0) \\\
        if cat == Group.Category.AIRPLANE or cat == Group.Category.HELICOPTER then \\\
            theNewGroup = dcsCommon.createEmptyAircraftGroupData(newName)\\\
        elseif cat == Group.Category.GROUND then\\\
            theNewGroup = dcsCommon.createEmptyGroudGroupData(newName)\\\
        else \\\
            trigger.action.outText(\\\"dcsCommon - unknown category: \\\" .. cat, 30)\\\
            return nil\\\
        end\\\
        \\\
\\\
        -- now get all units from live group and create data units\\\
        -- note that unit data for group has x=0, y=0\\\
        liveUnits = liveGroup:getUnits()\\\
        \\\
        for index, theUnit in pairs(liveUnits) do \\\
            -- for each unit we get the desc \\\
            local desc = theUnit:getDesc() -- of interest is only typename \\\
            local newUnit = dcsCommon.createGroundUnitData(dcsCommon.uuid(newName),\\\
                                                           desc.typeName,\\\
                                                           false)\\\
            -- we now basically have a ground unit at (0,0) \\\
            -- add mandatory fields by type\\\
            if cat == Group.Category.AIRPLANE or cat == Group.Category.HELICOPTER then \\\
                newUnit.alt = 100 -- make it 100m\\\
                newUnit.alt_type = \\\"RADIO\\\" -- AGL\\\
                newUnit.speed = 77 -- m/s --> 150 knots\\\
                newUnit.payload = dcsCommon.createPayload() -- empty payload\\\
                newUnit.callsign = dcsCommon.createCallsign() -- 'enfield11'\\\
                \\\
            elseif cat == Group.Category.GROUND then\\\
                -- we got all we need\\\
            else \\\
                -- trigger.action.outText(\\\"dcsCommon - unknown category: \\\" .. cat, 30)\\\
                -- return nil\\\
                -- we also got all we need\\\
            end            \\\
            \\\
        end\\\
    \\\
    end;\\\
    \\\
\\\
    function dcsCommon.rotatePointAroundOrigin(inX, inY, angle) -- angle in degrees\\\
        local degrees =  3.14152 / 180 -- ok, it's actually radiants. \\\
        angle = angle * degrees -- turns into rads\\\
        local c = math.cos(angle)\\\
        local s = math.sin(angle)\\\
        local px\\\
        local py \\\
        px = inX * c - inY * s\\\
        py = inX * s + inY * c\\\
        return px, py        \\\
    end\\\
\\\
    function dcsCommon.rotateGroupData(theGroup, degrees, cx, cz)\\\
        if not cx then cx = 0 end\\\
        if not cy then cy = 0 end\\\
        local rads = degrees *  3.14152 / 180\\\
        -- turns all units in group around the group's center by degrees.\\\
        -- may also need to turn individual units by same amount\\\
        for i, theUnit in pairs (theGroup.units) do\\\
            theUnit.x = theUnit.x - cx -- MOVE TO ORIGIN OF ROTATION\\\
            theUnit.y = theUnit.y - cy                 \\\
            theUnit.x, theUnit.y = dcsCommon.rotatePointAroundOrigin(theUnit.x, theUnit.y, degrees)\\\
            theUnit.x = theUnit.x + cx -- MOVE BACK \\\
            theUnit.y = theUnit.y + cy                 \\\
\\\
            -- may also want to increase heading by degreess\\\
            theUnit.heading = theUnit.heading + rads \\\
        end\\\
    end\\\
\\\
    function dcsCommon.offsetGroupData(theGroup, dx, dy)\\\
        -- add dx and dy to group's and all unit's coords\\\
        for i, theUnit in pairs (theGroup.units) do \\\
            theUnit.x = theUnit.x + dx\\\
            theUnit.y = theUnit.y + dy\\\
        end\\\
        \\\
        theGroup.x = theGroup.x + dx\\\
        theGroup.y = theGroup.y + dy \\\
    end\\\
    \\\
    function dcsCommon.moveGroupDataTo(theGroup, xAbs, yAbs)\\\
        local dx = xAbs-theGroup.x\\\
        local dy = yAbs-theGroup.y\\\
        dcsCommon.offsetGroupData(theGroup, dx, dy)\\\
    end\\\
    \\\
    -- static objectr shapes and types are defined here\\\
    -- https://github.com/mrSkortch/DCS-miscScripts/tree/master/ObjectDB/Statics\\\
    \\\
    function dcsCommon.createStaticObjectData(name, objType, heading, dead, cargo, mass)\\\
        local staticObj = {}\\\
        if not heading then heading = 0 end \\\
        if not dead then dead = false end \\\
        if not cargo then cargo = false end \\\
        objType = dcsCommon.trim(objType) \\\
        \\\
        staticObj.heading = 0\\\
        -- staticObj.groupId = 0\\\
        -- staticObj.shape_name = shape -- e.g. H-Windsock_RW\\\
        staticObj.type = objType  -- e.g. Windsock\\\
        -- [\\\"unitId\\\"] = 3,\\\
        staticObj.rate = 1 -- score when killed\\\
        staticObj.name = name\\\
        -- staticObj.category = \\\"Fortifications\\\",\\\
        staticObj.y = 0\\\
        staticObj.x = 0\\\
        staticObj.dead = dead\\\
        staticObj.canCargo = cargo -- to cargo\\\
        if cargo then \\\
            if not mass then mass = 1234 end \\\
            staticObj.mass = mass -- to cargo\\\
        end\\\
        return staticObj\\\
    end\\\
    \\\
    function dcsCommon.createStaticObjectDataAt(loc, name, objType, heading, dead)\\\
        local theData = dcsCommon.createStaticObjectData(name, objType, heading, dead)\\\
        theData.x = loc.x\\\
        theData.y = loc.z \\\
        return theData\\\
    end\\\
    \\\
    function dcsCommon.createStaticObjectForCoalitionAtLocation(theCoalition, loc, name, objType, heading, dead) \\\
        if not heading then heading = math.random(360) * 3.1415 / 180 end\\\
        local theData = dcsCommon.createStaticObjectDataAt(loc, name, objType, heading, dead)\\\
        local theStatic = coalition.addStaticObject(theCoalition, theData)\\\
        return theStatic\\\
    end\\\
    \\\
    function dcsCommon.createStaticObjectForCoalitionInRandomRing(theCoalition, objType, x, z, innerRadius, outerRadius, heading, alive) \\\
        if not outerRadius then outerRadius = innerRadius end\\\
        if not heading then heading = math.random(360) * 3.1415 / 180 end\\\
        local dead = not alive\\\
        local p = dcsCommon.randomPointInCircle(outerRadius, innerRadius, x, z)\\\
        local theData = dcsCommon.createStaticObjectData(dcsCommon.uuid(\\\"static\\\"), objType, heading, dead)\\\
        theData.x = p.x\\\
        theData.y = p.z \\\
        \\\
        local theStatic = coalition.addStaticObject(theCoalition, theData)\\\
        return theStatic\\\
    end\\\
    \\\
    \\\
    \\\
    function dcsCommon.linkStaticDataToUnit(theStatic, theUnit, dx, dy, heading)\\\
        if not theStatic then \\\
            trigger.action.OutText(\\\"+++dcsC: NIL theStatic on linkStatic!\\\", 30)\\\
            return \\\
        end\\\
        -- NOTE: we may get current heading and subtract/add \\\
        -- to original heading \\\
        local rotX, rotY = dcsCommon.rotatePointAroundOrigin(dx, dy, -heading)\\\
        \\\
        if not theUnit then return end\\\
        if not theUnit:isExist() then return end \\\
        theStatic.linkOffset = true \\\
        theStatic.linkUnit = theUnit:getID()\\\
        local unitPos = theUnit:getPoint()\\\
        local offsets = {}\\\
        offsets.x = rotX  \\\
        offsets.y = rotY \\\
        offsets.angle = 0\\\
        theStatic.offsets = offsets\\\
    end\\\
    \\\
    function dcsCommon.offsetStaticData(theStatic, dx, dy)\\\
        theStatic.x = theStatic.x + dx\\\
        theStatic.y = theStatic.y + dy\\\
        -- now check if thre is a route (for linked objects)\\\
        if theStatic.route then \\\
            -- access points[1] x and y and copy from main\\\
            theStatic.route.points[1].x = theStatic.x\\\
            theStatic.route.points[1].y = theStatic.y\\\
        end\\\
    end\\\
    \\\
    function dcsCommon.moveStaticDataTo(theStatic, x, y)\\\
        theStatic.x = x\\\
        theStatic.y = y\\\
        -- now check if thre is a route (for linked objects)\\\
        if theStatic.route then \\\
            -- access points[1] x and y and copy from main\\\
            theStatic.route.points[1].x = theStatic.x\\\
            theStatic.route.points[1].y = theStatic.y\\\
        end\\\
\\\
    end\\\
    \\\
--\\\
--\\\
-- M I S C   M E T H O D S \\\
--\\\
--\\\
\\\
    function dcsCommon.arrayContainsString(theArray, theString) \\\
        if not theArray then return false end\\\
        if not theString then return false end\\\
        for i = 1, #theArray do \\\
            if theArray[i] == theString then return true end \\\
        end\\\
        return false \\\
    end\\\
    \\\
    function dcsCommon.splitString(inputstr, sep) \\\
        if sep == nil then\\\
            sep = \\\"%s\\\"\\\
        end\\\
        if inputstr == nil then \\\
            inputstr = \\\"\\\"\\\
        end\\\
        \\\
        local t={}\\\
        for str in string.gmatch(inputstr, \\\"([^\\\"..sep..\\\"]+)\\\") do\\\
            table.insert(t, str)\\\
        end\\\
        return t\\\
    \\\
    end\\\
    \\\
    function dcsCommon.trimFront(inputstr) \\\
        if not inputstr then return nil end \\\
        local s = inputstr\\\
        while string.len(s) > 1 and string.sub(s, 1, 1) == \\\" \\\" do \\\
            local snew = string.sub(s, 2) -- all except first\\\
            s = snew\\\
        end\\\
        return s\\\
    end\\\
    \\\
    function dcsCommon.trimBack(inputstr)\\\
        if not inputstr then return nil end \\\
        local s = inputstr\\\
        while string.len(s) > 1 and string.sub(s, -1) == \\\" \\\" do \\\
            local snew = string.sub(s, 1, -2) -- all except last\\\
            s = snew\\\
        end\\\
        return s\\\
    end\\\
    \\\
    function dcsCommon.trim(inputstr) \\\
        local t1 = dcsCommon.trimFront(inputstr)\\\
        local t2 = dcsCommon.trimBack(t1)\\\
        return t2\\\
    end\\\
    \\\
    function dcsCommon.trimArray(theArray)\\\
        local trimmedArray = {}\\\
        for idx, element in pairs(theArray) do \\\
            local tel = dcsCommon.trim(element)\\\
            table.insert(trimmedArray, tel)\\\
        end\\\
        return trimmedArray\\\
    end\\\
    \\\
    -- same as cfxZones, this is the commonly used, may need to remove from zones\\\
    function dcsCommon.stringStartsWith(theString, thePrefix)\\\
        return theString:find(thePrefix) == 1\\\
    end\\\
    \\\
    function dcsCommon.removePrefix(theString, thePrefix)\\\
        if not dcsCommon.stringStartsWith(theString, thePrefix) then \\\
            return theString\\\
        end;\\\
        return theString:sub(1 + #thePrefix)\\\
    end\\\
    \\\
    function dcsCommon.stringEndsWith(theString, theEnding)\\\
        return theEnding == \\\"\\\" or str:sub(-#theEnding) == theEnding\\\
    end\\\
    \\\
    function dcsCommon.removeEnding(theString, theEnding) \\\
        if not dcsCommon.stringEndsWith(theString, theEnding) then \\\
            return theString\\\
        end\\\
        return theString:sub(1, #theString - #theEnding)\\\
    end\\\
    \\\
    function dcsCommon.containsString(inString, what, caseSensitive)\\\
        if (not caseSensitive) then \\\
            inString = string.upper(inString)\\\
            what = string.upper(what)\\\
        end\\\
        if inString == what then return true end -- when entire match \\\
        return string.find(inString, what)\\\
    end\\\
    \\\
    function dcsCommon.bool2Text(theBool) \\\
        if not theBool then theBool = false end \\\
        if theBool then return \\\"true\\\" end \\\
        return \\\"false\\\"\\\
    end\\\
    \\\
    function dcsCommon.bool2YesNo(theBool)\\\
        if not theBool then theBool = false end \\\
        if theBool then return \\\"yes\\\" end \\\
        return \\\"no\\\"\\\
    end\\\
\\\
    -- recursively show the contents of a variable\\\
    function dcsCommon.dumpVar(key, value, prefix, inrecursion)\\\
        if not inrecursion then \\\
            -- output a marker to find in the log / screen\\\
            env.info(\\\"*** dcsCommon vardump START\\\")\\\
        end\\\
        if not value then value = \\\"nil\\\" end\\\
        if not prefix then prefix = \\\"\\\" end\\\
        prefix = \\\" \\\" .. prefix\\\
        if type(value) == \\\"table\\\" then \\\
            env.info(prefix .. key .. \\\": [ \\\")\\\
            -- iterate through all kvp\\\
            for k,v in pairs (value) do\\\
                dcsCommon.dumpVar(k, v, prefix, true)\\\
            end\\\
            env.info(prefix .. \\\" ] - end \\\" .. key)\\\
            \\\
        elseif type(value) == \\\"boolean\\\" then \\\
            local b = \\\"false\\\"\\\
            if value then b = \\\"true\\\" end\\\
            env.info(prefix .. key .. \\\": \\\" .. b)\\\
            \\\
        else -- simple var, show contents, ends recursion\\\
            env.info(prefix .. key .. \\\": \\\" .. value)\\\
        end\\\
        \\\
        if not inrecursion then \\\
            -- output a marker to find in the log / screen\\\
            trigger.action.outText(\\\"=== dcsCommon vardump END\\\", 30)\\\
            env.info(\\\"=== dcsCommon vardump END\\\")\\\
        end\\\
    end\\\
    \\\
    function dcsCommon.dumpVar2Str(key, value, prefix, inrecursion)\\\
        if not inrecursion then \\\
            -- output a marker to find in the log / screen\\\
            trigger.action.outText(\\\"*** dcsCommon vardump START\\\",30)\\\
        end\\\
        if not value then value = \\\"nil\\\" end\\\
        if not prefix then prefix = \\\"\\\" end\\\
        prefix = \\\" \\\" .. prefix\\\
        if type(value) == \\\"table\\\" then \\\
            trigger.action.outText(prefix .. key .. \\\": [ \\\", 30)\\\
            -- iterate through all kvp\\\
            for k,v in pairs (value) do\\\
                dcsCommon.dumpVar2Str(k, v, prefix, true)\\\
            end\\\
            trigger.action.outText(prefix .. \\\" ] - end \\\" .. key, 30)\\\
            \\\
        elseif type(value) == \\\"boolean\\\" then \\\
            local b = \\\"false\\\"\\\
            if value then b = \\\"true\\\" end\\\
            trigger.action.outText(prefix .. key .. \\\": \\\" .. b, 30)\\\
            \\\
        else -- simple var, show contents, ends recursion\\\
            trigger.action.outText(prefix .. key .. \\\": \\\" .. value, 30)\\\
        end\\\
        \\\
        if not inrecursion then \\\
            -- output a marker to find in the log / screen\\\
            trigger.action.outText(\\\"=== dcsCommon vardump END\\\", 30)\\\
            --env.info(\\\"=== dcsCommon vardump END\\\")\\\
        end\\\
    end\\\
    \\\
\\\
    dcsCommon.simpleUUID = 76543 -- a number to start. as good as any\\\
    function dcsCommon.numberUUID()\\\
        dcsCommon.simpleUUID = dcsCommon.simpleUUID + 1\\\
        return dcsCommon.simpleUUID\\\
    end\\\
\\\
    function dcsCommon.uuid(prefix)\\\
        dcsCommon.uuIdent = dcsCommon.uuIdent + 1\\\
        if not prefix then prefix = dcsCommon.uuidStr end\\\
        return prefix .. \\\"-\\\" .. dcsCommon.uuIdent\\\
    end\\\
    \\\
    function dcsCommon.event2text(id) \\\
        if not id then return \\\"error\\\" end\\\
        if id == 0 then return \\\"invalid\\\" end\\\
        -- translate the event id to text\\\
        local events = {\\\"shot\\\", \\\"hit\\\", \\\"takeoff\\\", \\\"land\\\",\\\
                        \\\"crash\\\", \\\"eject\\\", \\\"refuel\\\", \\\"dead\\\",\\\
                        \\\"pilot dead\\\", \\\"base captured\\\", \\\"mission start\\\", \\\"mission end\\\", -- 12\\\
                        \\\"took control\\\", \\\"refuel stop\\\", \\\"birth\\\", \\\"human failure\\\", \\\
                        \\\"det. failure\\\", \\\"engine start\\\", \\\"engine stop\\\", \\\"player enter unit\\\",\\\
                        \\\"player leave unit\\\", \\\"player comment\\\", \\\"start shoot\\\", \\\"end shoot\\\",\\\
                        \\\"mark add\\\", \\\"mark changed\\\", \\\"makr removed\\\", \\\"kill\\\", \\\
                        \\\"score\\\", \\\"unit lost\\\", \\\"land after eject\\\", \\\"Paratrooper land\\\", \\\
                        \\\"chair discard after eject\\\", \\\"weapon add\\\", \\\"trigger zone\\\", \\\"landing quality mark\\\",\\\
                        \\\"BDA\\\", \\\"max\\\"}\\\
        if id > #events then return \\\"Unknown (ID=\\\" .. id .. \\\")\\\" end\\\
        return events[id]\\\
    end\\\
\\\
    function dcsCommon.smokeColor2Text(smokeColor)\\\
        if (smokeColor == 0) then return \\\"Green\\\" end\\\
        if (smokeColor == 1) then return \\\"Red\\\" end\\\
        if (smokeColor == 2) then return \\\"White\\\" end\\\
        if (smokeColor == 3) then return \\\"Orange\\\" end\\\
        if (smokeColor == 4) then return \\\"Blue\\\" end\\\
        \\\
        return (\\\"unknown: \\\" .. smokeColor)\\\
    end\\\
    \\\
    function dcsCommon.smokeColor2Num(smokeColor)\\\
        if not smokeColor then smokeColor = \\\"green\\\" end \\\
        if type(smokeColor) ~= \\\"string\\\" then return 0 end \\\
        smokeColor = smokeColor:lower()\\\
        if (smokeColor == \\\"green\\\") then return 0 end \\\
        if (smokeColor == \\\"red\\\") then return 1 end \\\
        if (smokeColor == \\\"white\\\") then return 2 end \\\
        if (smokeColor == \\\"orange\\\") then return 3 end \\\
        if (smokeColor == \\\"blue\\\") then return 4 end \\\
        return 0\\\
    end\\\
    \\\
    function dcsCommon.markPointWithSmoke(p, smokeColor)\\\
        local x = p.x \\\
        local z = p.z -- do NOT change the point directly\\\
        -- height-correct\\\
        local y = land.getHeight({x = x, y = z})\\\
        local newPoint= {x = x, y = y + 2, z = z}\\\
        trigger.action.smoke(newPoint, smokeColor)\\\
    end\\\
\\\
--\\\
--\\\
-- V E C T O R   M A T H \\\
--\\\
--\\\
function dcsCommon.vAdd(a, b) \\\
    local r = {}\\\
    if not a then a = {x = 0, y = 0, z = 0} end\\\
    if not b then b = {x = 0, y = 0, z = 0} end\\\
    r.x = a.x + b.x \\\
    r.y = a.y + b.y \\\
    r.z = a.z + b.z \\\
    return r \\\
end\\\
\\\
function dcsCommon.vSub(a, b) \\\
    local r = {}\\\
    if not a then a = {x = 0, y = 0, z = 0} end\\\
    if not b then b = {x = 0, y = 0, z = 0} end\\\
    r.x = a.x - b.x \\\
    r.y = a.y - b.y \\\
    r.z = a.z - b.z \\\
    return r \\\
end\\\
\\\
function dcsCommon.vMultScalar(a, f) \\\
    local r = {}\\\
    if not a then a = {x = 0, y = 0, z = 0} end\\\
    if not f then f = 0 end\\\
    r.x = a.x * f \\\
    r.y = a.y * f \\\
    r.z = a.z * f \\\
    return r \\\
end\\\
\\\
function dcsCommon.vLerp (a, b, t)\\\
    if not a then a = {x = 0, y = 0, z = 0} end\\\
    if not b then b = {x = 0, y = 0, z = 0} end\\\
    \\\
    local d = dcsCommon.vSub(b, a)\\\
    local dt = dcsCommon.vMultScalar(d, t)\\\
    local r = dcsCommon.vAdd(a, dt)\\\
    return r\\\
end\\\
\\\
function dcsCommon.mag(x, y, z) \\\
    if not x then x = 0 end\\\
    if not y then y = 0 end \\\
    if not z then z = 0 end \\\
    \\\
    return (x * x + y * y + z * z)^0.5\\\
end\\\
\\\
function dcsCommon.vMag(a) \\\
    if not a then return 0 end \\\
    if not a.x then a.x = 0 end \\\
    if not a.y then a.y = 0 end \\\
    if not a.z then a.z = 0 end\\\
    return dcsCommon.mag(a.x, a.y, a.z) \\\
end\\\
\\\
function dcsCommon.magSquare(x, y, z) \\\
    if not x then x = 0 end\\\
    if not y then y = 0 end \\\
    if not z then z = 0 end \\\
    \\\
    return (x * x + y * y + z * z)\\\
end\\\
\\\
function dcsCommon.dot (a, b) \\\
    if not a then a = {} end \\\
    if not a.x then a.x = 0 end \\\
    if not a.y then a.y = 0 end \\\
    if not a.z then a.z = 0 end\\\
    if not b then b = {} end \\\
    if not b.x then b.x = 0 end \\\
    if not b.y then b.y = 0 end \\\
    if not b.z then b.z = 0 end \\\
    \\\
    return a.x * b.x + a.y * b.y + a.z * b.z \\\
end\\\
--\\\
-- UNIT MISC\\\
-- \\\
function dcsCommon.isSceneryObject(theUnit)\\\
    if not theUnit then return false end\\\
    return theUnit.getCoalition == nil -- scenery objects do not return a coalition \\\
end\\\
\\\
function dcsCommon.isTroopCarrier(theUnit)\\\
    -- return true if conf can carry troups\\\
    if not theUnit then return false end \\\
    local uType = theUnit:getTypeName()\\\
    if dcsCommon.arrayContainsString(dcsCommon.troopCarriers, uType) then \\\
        -- may add additional tests before returning true\\\
        return true\\\
    end\\\
    return false\\\
end\\\
\\\
function dcsCommon.getUnitAlt(theUnit)\\\
    if not theUnit then return 0 end\\\
    if not theUnit:isExist() then return 0 end \\\
    local p = theUnit:getPoint()\\\
    return p.y \\\
end\\\
\\\
function dcsCommon.getUnitAGL(theUnit)\\\
    if not theUnit then return 0 end\\\
    if not theUnit:isExist() then return 0 end \\\
    local p = theUnit:getPoint()\\\
    local alt = p.y \\\
    local loc = {x = p.x, y = p.z}\\\
    local landElev = land.getHeight(loc)\\\
    return alt - landElev\\\
end \\\
\\\
function dcsCommon.getUnitSpeed(theUnit)\\\
    if not theUnit then return 0 end\\\
    if not theUnit:isExist() then return 0 end \\\
    local v = theUnit:getVelocity()\\\
    return dcsCommon.mag(v.x, v.y, v.z)\\\
end\\\
\\\
-- closing velocity of u1 and u2, seen from u1\\\
function dcsCommon.getClosingVelocity(u1, u2)\\\
    if not u1 then return 0 end \\\
    if not u2 then return 0 end \\\
    if not u1:isExist() then return 0 end \\\
    if not u2:isExist() then return 0 end \\\
    local v1 = u1:getVelocity()\\\
    local v2 = u2:getVelocity()\\\
    local dV = dcsCommon.vSub(v1,v2)\\\
    local a = u1:getPoint()\\\
    local b = u2:getPoint() \\\
    local aMinusB = dcsCommon.vSub(a,b) -- vector from u2 to u1\\\
    local abMag = dcsCommon.vMag(aMinusB) -- distance u1 to u2 \\\
    if abMag < .0001 then return 0 end \\\
    -- project deltaV onto vector from u2 to u1 \\\
    local vClose = dcsCommon.dot(dV, aMinusB) / abMag \\\
    return vClose \\\
end\\\
\\\
function dcsCommon.getGroupAvgSpeed(theGroup)\\\
    if not theGroup then return 0 end \\\
    if not dcsCommon.isGroupAlive(theGroup) then return 0 end \\\
    local totalSpeed = 0\\\
    local cnt = 0 \\\
    local livingUnits = theGroup:getUnits()\\\
    for idx, theUnit in pairs(livingUnits) do \\\
        cnt = cnt + 1\\\
        totalSpeed = totalSpeed + dcsCommon.getUnitSpeed(theUnit)\\\
    end \\\
    if cnt == 0 then return 0 end \\\
    return totalSpeed / cnt \\\
end\\\
 \\\
function dcsCommon.getGroupMaxSpeed(theGroup)\\\
    if not theGroup then return 0 end \\\
    if not dcsCommon.isGroupAlive(theGroup) then return 0 end \\\
    local maxSpeed = 0\\\
    local livingUnits = theGroup:getUnits()\\\
    for idx, theUnit in pairs(livingUnits) do \\\
        currSpeed = dcsCommon.getUnitSpeed(theUnit)\\\
        if currSpeed > maxSpeed then maxSpeed = currSpeed end \\\
    end \\\
    return maxSpeed\\\
end \\\
\\\
function dcsCommon.getUnitHeading(theUnit)\\\
    if not theUnit then return 0 end \\\
    if not theUnit:isExist() then return 0 end \\\
    local pos = theUnit:getPosition() -- returns three vectors, p is location\\\
\\\
    local heading = math.atan2(pos.x.z, pos.x.x)\\\
    -- make sure positive only, add 260 degrees\\\
    if heading < 0 then\\\
        heading = heading + 2 * math.pi    -- put heading in range of 0 to 2*pi\\\
    end\\\
    return heading \\\
end\\\
\\\
function dcsCommon.getUnitHeadingDegrees(theUnit)\\\
    local heading = dcsCommon.getUnitHeading(theUnit)\\\
    return heading * 57.2958 -- 180 / math.pi \\\
end\\\
\\\
function dcsCommon.unitIsInfantry(theUnit)\\\
    if not theUnit then return false end \\\
    if not theUnit:isExist() then return end\\\
    local theType = theUnit:getTypeName()\\\
    local isInfantry =  \\\
                dcsCommon.containsString(theType, \\\"infantry\\\", false) or \\\
                dcsCommon.containsString(theType, \\\"paratrooper\\\", false) or\\\
                dcsCommon.containsString(theType, \\\"stinger\\\", false) or\\\
                dcsCommon.containsString(theType, \\\"manpad\\\", false) or\\\
                dcsCommon.containsString(theType, \\\"soldier\\\", false)\\\
    return isInfantry\\\
end\\\
\\\
function dcsCommon.coalition2county(inCoalition)\\\
    -- simply return UN troops for 0 neutral,\\\
    -- joint red for 1  red\\\
    -- joint blue for 2 blue \\\
    if inCoalition == 1 then return 81 end -- cjtf red\\\
    if inCoalition == 2 then return 80 end -- blue \\\
    if type(inCoalition) == \\\"string\\\" then \\\
            inCoalition = inCoalition:lower()\\\
            if inCoalition == \\\"red\\\" then return 81 end\\\
            if inCoalition == \\\"blue\\\" then return 80 end\\\
    end\\\
        \\\
    trigger.action.outText(\\\"+++dcsC: coalition2county in (\\\" .. inCoalition .. \\\") converts to UN (82)!\\\", 30)\\\
    return 82 -- UN \\\
    \\\
end\\\
\\\
--\\\
--\\\
-- INIT\\\
--\\\
--\\\
    -- init any variables the lib requires internally\\\
    function dcsCommon.init()\\\
        cbID = 0\\\
        dcsCommon.uuIdent = 0\\\
        if (dcsCommon.verbose) then\\\
          trigger.action.outText(\\\"dcsCommon v\\\" .. dcsCommon.version .. \\\" loaded successfully\\\", 10)\\\
        end\\\
    end\\\
\\\
    \\\
-- do init. \\\
dcsCommon.init()\\\
\\\
--[[--\\\
\\\
to do: \\\
- formation 2Column\\\
- formation 3Column\\\
\\\
-]]--\\\
\");a_do_script(\"-- cf/x zone management module\\\
-- reads dcs zones and makes them accessible and mutable \\\
-- by scripting.\\\
--\\\
-- Copyright (c) 2021 by Christian Franz and cf/x AG\\\
--\\\
\\\
cfxZones = {}\\\
cfxZones.version = \\\"2.4.10\\\"\\\
--[[-- VERSION HISTORY\\\
 - 2.2.4 - getCoalitionFromZoneProperty\\\
         - getStringFromZoneProperty\\\
 - 2.2.5 - createGroundUnitsInZoneForCoalition corrected coalition --> country \\\
 - 2.2.6 - getVectorFromZoneProperty(theZone, theProperty, defaultVal)\\\
 - 2.2.7 - allow 'yes' as 'true' for boolean attribute \\\
 - 2.2.8 - getBoolFromZoneProperty supports default \\\
         - cfxZones.hasProperty\\\
 - 2.3.0 - property names are case insensitive \\\
 - 2.3.1 - getCoalitionFromZoneProperty allows 0, 1, 2 also\\\
 - 2.4.0 - all zones look for owner attribute, and set it to 0 (neutral) if not present \\\
 - 2.4.1 - getBoolFromZoneProperty upgraded by expected bool \\\
         - markZoneWithSmoke raised by 3 meters\\\
 - 2.4.2 - getClosestZone also returns delta \\\
 - 2.4.3 - getCoalitionFromZoneProperty() accepts 'all' as neutral \\\
           createUniqueZoneName()\\\
           getStringFromZoneProperty returns default if property value = \\\"\\\"\\\
           corrected bug in addZoneToManagedZones\\\
 - 2.4.4 - getPoint(aZone) returns uip-to-date pos for linked and normal zones\\\
         - linkUnit can use \\\"useOffset\\\" property to keep relative position\\\
 - 2.4.5 - updated various methods to support getPoint when referencing \\\
           zone.point  \\\
 - 2.4.6 - corrected spelling in markZoneWithSmoke\\\
 - 2.4.7 - copy reference to dcs zone into cfx zone \\\
 - 2.4.8 - getAllZoneProperties\\\
 - 2.4.9 - createSimpleZone no longer requires location \\\
         - parse dcs adds empty .properties = {} if none tehre \\\
         - createCircleZone adds empty properties \\\
         - createPolyZone adds empty properties \\\
 - 2.4.10 - pickRandomZoneFrom now defaults to all cfxZones.zones\\\
          - getBoolFromZoneProperty also recognizes 0, 1\\\
          - removed autostart\\\
 \\\
--]]--\\\
cfxZones.verbose = true\\\
cfxZones.caseSensitiveProperties = false -- set to true to make property names case sensitive \\\
cfxZones.ups = 1 -- updates per second. updates moving zones\\\
\\\
cfxZones.zones = {} -- these are the zone as retrieved from the mission.\\\
                    -- ALWAYS USE THESE, NEVER DCS's ZONES!!!!\\\
\\\
-- a zone has the following attributes\\\
-- x, z -- coordinate of center. note they have correct x, 0, z coordinates so no y-->z mapping\\\
-- radius (zero if quad zone)\\\
-- isCircle (true if quad zone)\\\
-- poly the quad coords are in the poly attribute and are a \\\
-- 1..n, wound counter-clockwise as (currently) in DCS:\\\
-- lower left, lower right upper left, upper right, all coords are x, 0, z \\\
-- bounds - contain the AABB coords for the zone: ul (upper left), ur, ll (lower left), lr \\\
--          for both circle and poly, all (x, 0, z)\\\
\\\
-- zones can carry information in their names that can get processed into attributes\\\
-- use \\\
-- zones can also carry information in their 'properties' tag that ME allows to \\\
-- edit. cfxZones provides an easy method to access these properties \\\
--  - getZoneProperty (returns as string)\\\
--  - getMinMaxFromZoneProperty\\\
--  - getBoolFromZoneProperty\\\
--  - getNumberFromZoneProperty\\\
\\\
\\\
-- SUPPORTED PROPERTIES\\\
-- - \\\"linkedUnit\\\" - zone moves with unit of that name. must be exact match\\\
--   can be combined with other attributes that extend (e.g. scar manager and\\\
--   limited pilots/airframes \\\
--\\\
\\\
--\\\
-- readZonesFromDCS is executed exactly once at the beginning\\\
-- from then on, use only the cfxZones.zones table \\\
-- WARNING: cfxZones is NOT case-sensitive. All zone names are \\\
-- indexed by upper case. If you have two zones with same name but \\\
-- different case, one will be replaced\\\
--\\\
\\\
function cfxZones.readFromDCS(clearfirst)\\\
    if (clearfirst) then\\\
        cfxZones.zones = {}\\\
    end\\\
    -- not all missions have triggers or zones\\\
    if not env.mission.triggers then \\\
        if cfxZones.verbose then \\\
            trigger.action.outText(\\\"cf/x zones: no env.triggers defined\\\", 10)\\\
        end\\\
        return\\\
    end\\\
    \\\
    if not env.mission.triggers.zones then \\\
        if cfxZones.verbose then \\\
            trigger.action.outText(\\\"cf/x zones: no zones defined\\\", 10)\\\
        end\\\
        return;\\\
    end\\\
\\\
    -- we only retrive the data we need. At this point it is name, location and radius\\\
    -- and put this in our own little  structure. we also convert to all upper case name for index\\\
    -- and assume that the name may also carry meaning, e.g. 'LZ:' defines a landing zone\\\
    -- so we can quickly create other sets from this\\\
    -- zone object. DCS 2.7 introduced quads, so this is supported as well\\\
    --   name - name in upper case\\\
    --   isCircle - true if circular zone \\\
    --   isPoly - true if zone is defined by convex polygon, e.g. quad \\\
    --   point - vec3 (x 0 z) - zone's in-world center, used to place the coordinate\\\
    --   radius - number, zero when quad\\\
    --   bounds - aabb with attributes ul, ur, ll, lr (upper left .. lower right) as (x, 0, z)\\\
    --   poly - array 1..n of poly points, wound counter-clockwise \\\
    \\\
    for i, dcsZone in pairs(env.mission.triggers.zones) do\\\
        if type(dcsZone) == 'table' then -- hint taken from MIST: verify type when reading from dcs\\\
                                         -- dcs data is like a box of chocolates...\\\
            local newZone = {}\\\
            -- name, converted to upper is used only for indexing\\\
            -- the original name remains untouched\\\
            newZone.dcsZone = dcsZone\\\
            newZone.name = dcsZone.name\\\
            newZone.isCircle = false\\\
            newZone.isPoly = false\\\
            newZone.radius = 0\\\
            newZone.poly = {}\\\
            newZone.bounds = {}\\\
            newZone.properties = {} -- dcs has this too, copy if present\\\
            if dcsZone.properties then \\\
                newZone.properties = dcsZone.properties \\\
            else\\\
                newZone.properties = {}\\\
            end -- WARNING: REF COPY. May need to clone \\\
            \\\
            local upperName = newZone.name:upper()\\\
            \\\
            -- location as 'point'\\\
            -- WARNING: zones locs are 2D (x,y) pairs, whily y in DCS is altitude.\\\
            --          so we need to change (x,y) into (x, 0, z). Since Zones have no\\\
            --          altitude (they are an infinite cylinder) this works. Remember to \\\
            --          drop y from zone calculations to see if inside. \\\
            newZone.point = cfxZones.createPoint(dcsZone.x, 0, dcsZone.y)\\\
\\\
\\\
            -- start type processing. if zone.type exists, we have a mission \\\
            -- created with 2.7 or above, else earlier \\\
            local zoneType = 0\\\
            if (dcsZone.type) then \\\
                zoneType = dcsZone.type \\\
            end\\\
            \\\
            if zoneType == 0 then \\\
                -- circular zone \\\
                newZone.isCircle = true \\\
                newZone.radius = dcsZone.radius\\\
    \\\
            elseif zoneType == 2 then\\\
                -- polyZone\\\
                newZone.isPoly = true \\\
                newZone.radius = dcsZone.radius -- radius is still written in DCS, may change later\\\
                -- now transfer all point in the poly\\\
                -- note: DCS in 2.7 misspells vertices as 'verticies'\\\
                -- correct vor this \\\
                local verts = {}\\\
                if dcsZone.verticies then verts = dcsZone.verticies \\\
                else \\\
                    -- in later versions, this was corrected\\\
                    verts = dcsZone.vertices -- see if this is ever called\\\
                end\\\
                \\\
                for v=1, #verts do\\\
                    local dcsPoint = verts[v]\\\
                    local polyPoint = cfxZones.createPointFromDCSPoint(dcsPoint) -- (x, y) -- (x, 0, y-->z)\\\
                    newZone.poly[v] = polyPoint\\\
                end\\\
            else \\\
                \\\
                trigger.action.outText(\\\"cf/x zones: malformed zone #\\\" .. i .. \\\" unknown type \\\" .. zoneType, 10)\\\
            end\\\
            \\\
\\\
            -- calculate bounds\\\
            cfxZones.calculateZoneBounds(newZone) \\\
\\\
            -- add to my table\\\
            cfxZones.zones[upperName] = newZone -- WARNING: UPPER ZONE!!!\\\
        else\\\
            if cfxZones.verbose then \\\
                trigger.action.outText(\\\"cf/x zones: malformed zone #\\\" .. i .. \\\" dropped\\\", 10)\\\
            end\\\
        end -- else var not a table\\\
        \\\
    end -- for all zones kvp\\\
end -- readFromDCS\\\
\\\
function cfxZones.calculateZoneBounds(theZone)\\\
    if not (theZone) then return \\\
    end\\\
    \\\
    local bounds = theZone.bounds -- copy ref!\\\
    \\\
    if theZone.isCircle then \\\
        -- aabb are easy: center +/- radius \\\
        local center = theZone.point\\\
        local radius = theZone.radius \\\
        -- dcs uses z+ is down on map\\\
        -- upper left is center - radius \\\
        bounds.ul = cfxZones.createPoint(center.x - radius, 0, center.z - radius)\\\
        bounds.ur = cfxZones.createPoint(center.x + radius, 0, center.z - radius)\\\
        bounds.ll = cfxZones.createPoint(center.x - radius, 0, center.z + radius)\\\
        bounds.lr = cfxZones.createPoint(center.x + radius, 0, center.z + radius)\\\
        \\\
    elseif theZone.isPoly then\\\
        local poly = theZone.poly -- ref copy!\\\
        -- create the four points\\\
        local ll = cfxZones.createPointFromPoint(poly[1])\\\
        local lr = cfxZones.createPointFromPoint(poly[1])\\\
        local ul = cfxZones.createPointFromPoint(poly[1])\\\
        local ur = cfxZones.createPointFromPoint(poly[1])\\\
\\\
        -- now iterate through all points and adjust bounds accordingly \\\
        for v=2, #poly do \\\
             local vertex = poly[v]\\\
             if (vertex.x < ll.x) then ll.x = vertex.x; ul.x = vertex.x end \\\
             if (vertex.x > lr.x) then lr.x = vertex.x; ur.x = vertex.x end \\\
             if (vertex.z < ul.z) then ul.z = vertex.z; ur.z = vertex.z end\\\
             if (vertex.z > ll.z) then ll.z = vertex.z; lr.z = vertex.z end \\\
            \\\
        end\\\
        \\\
        -- now keep the new point references\\\
        -- and store them in the zone's bounds\\\
        bounds.ll = ll\\\
        bounds.lr = lr\\\
        bounds.ul = ul\\\
        bounds.ur = ur \\\
    else \\\
        -- huston, we have a problem\\\
        if cfxZones.verbose then \\\
            trigger.action.outText(\\\"cf/x zones: calc bounds: zone \\\" .. theZone.name .. \\\" has unknown type\\\", 30)\\\
        end\\\
    end\\\
    \\\
end\\\
\\\
function cfxZones.createPoint(x, y, z)\\\
    local newPoint = {}\\\
    newPoint.x = x\\\
    newPoint.y = y\\\
    newPoint.z = z \\\
    return newPoint\\\
end\\\
\\\
function cfxZones.copyPoint(inPoint) \\\
    local newPoint = {}\\\
    newPoint.x = inPoint.x\\\
    newPoint.y = inPoint.y\\\
    newPoint.z = inPoint.z \\\
    return newPoint    \\\
end\\\
\\\
function cfxZones.createHeightCorrectedPoint(inPoint) -- this should be in dcsCommon\\\
    local cP = cfxZones.createPoint(inPoint.x, land.getHeight({x=inPoint.x, y=inPoint.z}),inPoint.z)\\\
    return cP\\\
end\\\
\\\
function cfxZones.getHeightCorrectedZonePoint(theZone)\\\
    return cfxZones.createHeightCorrectedPoint(theZone.point)\\\
end\\\
\\\
function cfxZones.createPointFromPoint(inPoint)\\\
    return cfxZones.copyPoint(inPoint)\\\
end\\\
\\\
function cfxZones.createPointFromDCSPoint(inPoint) \\\
    return cfxZones.createPoint(inPoint.x, 0, inPoint.y)\\\
end\\\
\\\
\\\
function cfxZones.createRandomPointInsideBounds(bounds)\\\
    local x = math.random(bounds.ll.x, ur.x)\\\
    local z = math.random(bounds.ll.z, ur.z)\\\
    return cfxZones.createPoint(x, 0, z)\\\
end\\\
\\\
function cfxZones.addZoneToManagedZones(theZone)\\\
    local upperName = string.upper(theZone.name) -- newZone.name:upper()\\\
    cfxZones.zones[upperName] = theZone\\\
end\\\
\\\
function cfxZones.createUniqueZoneName(inName, searchSet)\\\
    if not inName then return nil end \\\
    if not searchSet then searchSet = cfxZones.zones end \\\
    inName = inName:upper()\\\
    while searchSet[inName] ~= nil do \\\
        inName = inName .. \\\"X\\\"\\\
    end\\\
    return inName\\\
end\\\
\\\
function cfxZones.createSimpleZone(name, location, radius, addToManaged)\\\
    if not radius then radius = 10 end\\\
    if not addToManaged then addToManaged = false end \\\
    if not location then \\\
        location = {}\\\
    end\\\
    if not location.x then location.x = 0 end \\\
    if not location.z then location.z = 0 end \\\
    \\\
    local newZone = cfxZones.createCircleZone(name, location.x, location.z, radius)\\\
    \\\
    if addToManaged then \\\
        cfxZones.addZoneToManagedZones(newZone)\\\
    end\\\
    return newZone\\\
end\\\
\\\
function cfxZones.createCircleZone(name, x, z, radius) \\\
    local newZone = {}\\\
    newZone.isCircle = true\\\
    newZone.isPoly = false\\\
    newZone.poly = {}\\\
    newZone.bounds = {}\\\
            \\\
    newZone.name = name\\\
    newZone.radius = radius\\\
    newZone.point = cfxZones.createPoint(x, 0, z)\\\
 \\\
    -- props \\\
    newZone.properties = {}\\\
    \\\
    -- calculate my bounds\\\
    cfxZones.calculateZoneBounds(newZone)\\\
    \\\
    return newZone\\\
end\\\
\\\
function cfxZones.createPolyZone(name, poly) -- poly must be array of point type\\\
local newZone = {}\\\
    newZone.isCircle = false\\\
    newZone.isPoly = true\\\
    newZone.poly = {}\\\
    newZone.bounds = {}\\\
            \\\
    newZone.name = name\\\
    newZone.radius = 0\\\
    -- copy poly\\\
    for v=1, #poly do \\\
        local theVertex = poly[v] \\\
        newZone.poly[v] = cfxZones.createPointFromPoint(theVertex) \\\
    end\\\
    \\\
    -- properties \\\
    newZone.properties = {}\\\
    \\\
    cfxZones.calculateZoneBounds(newZone)\\\
end\\\
\\\
\\\
\\\
function cfxZones.createRandomZoneInZone(name, inZone, targetRadius, entirelyInside)\\\
    -- create a new circular zone with center placed inside inZone\\\
    -- if entirelyInside is false, only the zone's center is guaranteed to be inside\\\
    -- inZone.\\\
    \\\
--    trigger.action.outText(\\\"Zones: creating rZiZ with tr = \\\" .. targetRadius .. \\\" for \\\" .. inZone.name .. \\\" that as r = \\\" .. inZone.radius, 10)\\\
    \\\
    if inZone.isCircle then \\\
        local sourceRadius = inZone.radius\\\
        if entirelyInside and targetRadius > sourceRadius then targetRadius = sourceRadius end\\\
        if entirelyInside then sourceRadius = sourceRadius - targetRadius end\\\
    \\\
        -- ok, let's first create a random percentage value for the new radius\\\
        local percent = 1 / math.random(100)\\\
        -- now lets get a random degree\\\
        local degrees = math.random(360) * 3.14152 / 180 -- ok, it's actually radiants. \\\
        local r = sourceRadius * percent \\\
        local x = inZone.point.x + r * math.cos(degrees)\\\
        local z = inZone.point.z + r * math.sin(degrees)\\\
        -- construct new zone\\\
        local newZone = cfxZones.createCircleZone(name, x, z, targetRadius)\\\
        return newZone\\\
    \\\
    elseif inZone.isPoly then \\\
        -- we have a poly zone. the way we do this is simple:\\\
        -- generate random x, z with ranges of the bounding box \\\
        -- until the point falls within the polygon.\\\
        local newPoint = {}\\\
        local emergencyBrake = 0\\\
        repeat\\\
            newPoint = cfxZones.createRandomPointInsideBounds(inZone.bounds)\\\
            emergencyBrake = emergencyBrake + 1\\\
            if (emergencyBrake > 100) then \\\
                newPoint = cfxZones.copyPoint(inZone.Point)\\\
                trigger.action.outText(\\\"CreateZoneInZone: mergency brake for inZone\\\" .. inZone.name,  10)\\\
                break\\\
            end\\\
        until cfxZones.isPointInsidePoly(newPoint, inZone.poly)\\\
        \\\
        -- construct new zone\\\
        local newZone = cfxZones.createCircleZone(name, newPoint.x, newPoint.z, targetRadius)\\\
        return newZone\\\
        \\\
    else \\\
        -- zone type unknown\\\
        trigger.action.outText(\\\"CreateZoneInZone: unknown zone type for inZone =\\\" .. inZone.name ,  10)\\\
        return nil \\\
    end\\\
end\\\
\\\
-- polygon inside zone calculations\\\
\\\
\\\
-- isleft returns true if point P is to the left of line AB \\\
-- by determining the sign (up or down) of the normal vector of \\\
-- the two vectors PA and PB in the y coordinate. We arbitrarily define\\\
-- left as being > 0, so right is <= 0. As long as we always use the \\\
-- same comparison, it does not matter what up or down mean.\\\
-- this is important because we don't know if dcs always winds quads\\\
-- the same way, we must simply assume that they are wound as a polygon \\\
function cfxZones.isLeftXZ(A, B, P)\\\
    return ((B.x - A.x)*(P.z - A.z) - (B.z - A.z)*(P.x - A.x)) > 0\\\
end\\\
\\\
-- returns true/false for inside\\\
function cfxZones.isPointInsideQuad(thePoint, A, B, C, D) \\\
    -- Inside test (only convex polygons): \\\
    -- point lies on the same side of each quad's vertex AB, BC, CD, DA\\\
    -- how do we find out which side a point lies on? via the cross product\\\
    -- see isLeft below\\\
    \\\
    -- so all we need to do is make sure all results of isLeft for all\\\
    -- four sides are the same\\\
    mustMatch = isLeftXZ(A, B, thePoint) -- all test results must be the same and we are ok\\\
                                       -- they just must be the same side.\\\
    if (cfxZones.isLeftXZ(B, C, thePoint ~= mustMatch)) then return false end -- on other side than all before\\\
    if (cfxZones.isLeftXZ(C, D, thePoint ~= mustMatch)) then return false end \\\
    if (cfxZones.isLeftXZ(D, A, thePoint ~= mustMatch)) then return false end\\\
    return true\\\
end\\\
\\\
-- generalized version of insideQuad, assumes winding of poly, poly convex, poly closed\\\
function cfxZones.isPointInsidePoly(thePoint, poly)\\\
    local mustMatch = cfxZones.isLeftXZ(poly[1], poly[2], thePoint)\\\
    for v=2, #poly-1 do \\\
        if cfxZones.isLeftXZ(poly[v], poly[v+1], thePoint) ~= mustMatch then return false end\\\
    end\\\
    -- final test\\\
    if cfxZones.isLeftXZ(poly[#poly], poly[1], thePoint) ~= mustMatch then return false end\\\
    \\\
    return true\\\
end;\\\
\\\
function cfxZones.isPointInsideZone(thePoint, theZone)\\\
    local p = {x=thePoint.x, y = 0, z = thePoint.z} -- zones have no altitude\\\
    if (theZone.isCircle) then \\\
        local d = dcsCommon.dist(p, theZone.point)\\\
        return d < theZone.radius\\\
    end \\\
    \\\
    if (theZone.isPoly) then \\\
        return (cfxZones.isPointInsidePoly(p, theZone.poly))\\\
    end\\\
\\\
    trigger.action.outText(\\\"isPointInsideZone: Unknown zone type for \\\" .. outerZone.name, 10)\\\
end\\\
\\\
-- isZoneInZone returns true if center of innerZone is inside  outerZone\\\
function cfxZones.isZoneInsideZone(innerZone, outerZone) \\\
    return cfxZones.isPointInsideZone(innerZone.point, outerZone)\\\
\\\
    \\\
end\\\
\\\
function cfxZones.getZonesContainingPoint(thePoint, testZones) -- return array \\\
    if not testZones then \\\
        testZones = cfxZones.zones \\\
    end \\\
    \\\
    local containerZones = {}\\\
    for tName, tData in pairs(testZones) do \\\
        if cfxZones.isPointInsideZone(thePoint, tData) then \\\
            table.insert(containerZones, tData)\\\
        end\\\
    end\\\
\\\
    return containerZones\\\
end\\\
\\\
function cfxZones.getFirstZoneContainingPoint(thePoint, testZones)\\\
    if not testZones then \\\
        testZones = cfxZones.zones \\\
    end \\\
    \\\
    for tName, tData in pairs(testZones) do \\\
        if cfxZones.isPointInsideZone(thePoint, tData) then \\\
            return tData\\\
        end\\\
    end\\\
\\\
    return nil\\\
end\\\
\\\
function cfxZones.getAllZonesInsideZone(superZone, testZones) -- returnes array!\\\
    if not testZones then \\\
        testZones = cfxZones.zones \\\
    end \\\
    \\\
    local containedZones = {}\\\
    for zName, zData in pairs(testZones) do\\\
        if cfxZones.isZoneInsideZone(zData, superZone) then \\\
            if zData ~= superZone then \\\
                -- we filter superzone because superzone usually resides \\\
                -- inside itself \\\
                table.insert(containedZones, zData)\\\
            end\\\
        end\\\
    end\\\
    return containedZones \\\
end\\\
\\\
function cfxZones.getZonesWithAttributeNamed(attributeName, testZones)\\\
    if not testZones then testZones = cfxZones.zones end \\\
    local attributZones = {}\\\
    for aName,aZone in pairs(testZones) do\\\
        local attr = cfxZones.getZoneProperty(aZone, attributeName)\\\
        if attr then \\\
            -- this zone has the requested attribute\\\
            table.insert(attributZones, aZone)\\\
        end\\\
    end\\\
    return attributZones\\\
end\\\
\\\
--\\\
-- units / groups in zone\\\
--\\\
function cfxZones.groupsOfCoalitionPartiallyInZone(coal, theZone, categ) -- categ is optional\\\
    local groupsInZone = {}\\\
    local allGroups = coalition.getGroups(coal, categ)\\\
    for key, group in pairs(allGroups) do -- iterate all groups\\\
        if group:isExist() then\\\
            \\\
            \\\
            if cfxZones.isGroupPartiallyInZone(group, theZone) then\\\
                \\\
                table.insert(groupsInZone, group)\\\
            else \\\
                \\\
            \\\
            end\\\
        end\\\
    end\\\
    return groupsInZone\\\
end\\\
\\\
function cfxZones.isGroupPartiallyInZone(aGroup, aZone)\\\
    if not aGroup then return false end \\\
    if not aZone then return false end \\\
    \\\
    \\\
    -- needs to be implemented\\\
    if not aGroup:isExist() then return false end \\\
    local allUnits = aGroup:getUnits()\\\
    for uk, aUnit in pairs (allUnits) do \\\
        if aUnit:isExist() and aUnit:getLife() > 1 then \\\
        \\\
            local p = aUnit:getPoint()\\\
--            p.y = 0 -- zones have no altitude\\\
            -- modification of isPointInsideZone now takes care of this\\\
            if cfxZones.isPointInsideZone(p, aZone) then             \\\
                return true\\\
            else \\\
                        \\\
            end \\\
        end\\\
    end\\\
    return false\\\
end\\\
\\\
function cfxZones.isEntireGroupInZone(aGroup, aZone)\\\
    if not aGroup then return false end \\\
    if not aZone then return false end \\\
    -- needs to be implemented\\\
    if not aGroup:isExist() then return false end \\\
    local allUnits = aGroup:getUnits()\\\
    for uk, aUnit in pairs (allUnits) do \\\
        if aUnit:isExist() and aUnit:getLife() > 1 then \\\
            local p = aUnit:getPoint()\\\
            if not cfxZones.isPointInsideZone(p, aZone) then \\\
                return false\\\
            end\\\
        end\\\
    end\\\
    return true\\\
end\\\
\\\
\\\
--\\\
-- Zone Manipulation\\\
--\\\
\\\
function cfxZones.offsetZone(theZone, dx, dz)\\\
    -- first, update center \\\
    theZone.point.x = theZone.point.x + dx\\\
    theZone.point.z = theZone.point.z + dz \\\
    \\\
    -- now process all polygon points - it's empty for circular, so don't worry\\\
    for v=1, #theZone.poly do \\\
        theZone.poly[v].x = theZone.poly[v].x + dx\\\
        theZone.poly[v].z = theZone.poly[v].z + dz \\\
    end\\\
end\\\
\\\
function cfxZones.moveZoneTo(theZone, x, z)\\\
    local dx = x - theZone.point.x\\\
    local dz = z - theZone.point.z \\\
    cfxZones.offsetZone(theZone, dx, dz)\\\
end;\\\
\\\
function cfxZones.centerZoneOnUnit(theZone, theUnit) \\\
    local thePoint = theUnit:getPoint()\\\
    cfxZones.moveZoneTo(theZone, thePoint.x, thePoint.z)\\\
end\\\
\\\
\\\
--[[\\\
-- no longer makes sense with poly zones\\\
function cfxZones.isZoneEntirelyInsideZone(innerZone, outerZone)\\\
    if (innerZone.radius > outerZone.radius) then return false end -- cant fit inside\\\
    local d = dcsCommon.dist(innerZone.point, outerZone.point)\\\
    local reducedR = outerZone.radius - innerZone.radius\\\
    return d < reducedR\\\
end;\\\
--]]\\\
\\\
function cfxZones.dumpZones(zoneTable)\\\
    if not zoneTable then zoneTable = cfxZones.zones end \\\
    \\\
    trigger.action.outText(\\\"Zones START\\\", 10)\\\
    for i, zone in pairs(zoneTable) do \\\
        local myType = \\\"unknown\\\"\\\
        if zone.isCircle then myType = \\\"Circle\\\" end\\\
        if zone.isPoly then myType = \\\"Poly\\\" end \\\
        \\\
        trigger.action.outText(\\\"#\\\".. i .. \\\": \\\" .. zone.name .. \\\" of type \\\" .. myType, 10)\\\
    end\\\
    trigger.action.outText(\\\"Zones END\\\", 10)\\\
end\\\
\\\
function cfxZones.stringStartsWith(theString, thePrefix)\\\
    return theString:find(thePrefix) == 1\\\
end\\\
\\\
function cfxZones.keysForTable(theTable)\\\
    local keyset={}\\\
    local n=0\\\
\\\
    for k,v in pairs(tab) do\\\
        n=n+1\\\
        keyset[n]=k\\\
    end\\\
    return keyset\\\
end\\\
\\\
\\\
--\\\
-- return all zones that have a specific named property\\\
--\\\
function cfxZones.zonesWithProperty(propertyName, searchSet)\\\
    if not searchSet then searchSet = cfxZones.zones end \\\
    local theZones = {}\\\
    for k, aZone in pairs(searchSet) do \\\
        local lU = cfxZones.getZoneProperty(aZone, propertyName)\\\
        if lU then \\\
            table.insert(theZones, aZone)\\\
        end\\\
    end    \\\
    return theZones\\\
end\\\
\\\
--\\\
-- return all zones from the zone table that begin with string prefix\\\
--\\\
function cfxZones.zonesStartingWithName(prefix, searchSet)\\\
    \\\
    if not searchSet then searchSet = cfxZones.zones end \\\
    \\\
--    trigger.action.outText(\\\"Enter: zonesStartingWithName for \\\" .. prefix , 30)\\\
    local prefixZones = {}\\\
    prefix = prefix:upper() -- all zones have UPPERCASE NAMES! THEY SCREAM AT YOU\\\
    for name, zone in pairs(searchSet) do\\\
--        trigger.action.outText(\\\"testing \\\" .. name:upper() .. \\\" starts with \\\" .. prefix , 30)\\\
        if cfxZones.stringStartsWith(name:upper(), prefix) then\\\
            prefixZones[name] = zone -- note: ref copy!\\\
            --trigger.action.outText(\\\"zone with prefix <\\\" .. prefix .. \\\"> found: \\\" .. name, 10)\\\
        end\\\
    end\\\
    \\\
    return prefixZones\\\
end\\\
\\\
--\\\
-- return all zones from the zone table that begin with the string or set of strings passed in prefix \\\
-- if you pass 'true' as second (optional) parameter, it will first look for all zones that begin\\\
-- with '+' and return only those. Use during debugging to force finding a specific zone\\\
--\\\
function cfxZones.zonesStartingWith(prefix, searchSet, debugging)\\\
    -- you can force zones by having their name start with \\\"+\\\"\\\
    -- which will force them to return immediately if debugging is true for this call\\\
\\\
    if (debugging) then \\\
        local debugZones = cfxZones.zonesStartingWithName(\\\"+\\\", searchSet)\\\
        if not (next(debugZones) == nil) then -- # operator only works on array elements \\\
            --trigger.action.outText(\\\"returning zones with prefix <\\\" .. prefix .. \\\">\\\", 10)\\\
            return debugZones \\\
        end \\\
    end\\\
    \\\
    --trigger.action.outText(\\\"#debugZones is  <\\\" .. #debugZones .. \\\">\\\", 10)\\\
\\\
    if (type(prefix) == \\\"string\\\") then \\\
        return cfxZones.zonesStartingWithName(prefix, searchSet)\\\
    end\\\
    \\\
    local allZones = {}\\\
    for i=1, #prefix do \\\
        -- iterate through all names in prefix set\\\
        local theName = prefix[i]\\\
        local newZones = cfxZones.zonesStartingWithName(theName, searchSet)\\\
        -- add them all to current table\\\
        for zName, zInfo in pairs(newZones) do \\\
            allZones[zName] = zInfo -- will also replace doublets\\\
        end\\\
    end\\\
    \\\
    return allZones\\\
end\\\
\\\
function cfxZones.getZoneByName(aName, searchSet) \\\
    if not searchSet then searchSet = cfxZones.zones end \\\
    aName = aName:upper()\\\
    return searchSet[aName] -- the joys of key value pairs\\\
end\\\
\\\
function cfxZones.getZonesContainingString(aString, searchSet) \\\
    if not searchSet then searchSet = cfxZones.zones end\\\
    aString = string.upper(aString)\\\
    resultSet = {}\\\
    for zName, zData in pairs(searchSet) do \\\
        if aString == string.upper(zData.name) then \\\
            resultSet[zName] = zData\\\
        end\\\
    end\\\
    \\\
end;\\\
\\\
-- filter zones by range to a point. returns indexed set\\\
function cfxZones.getZonesInRange(point, range, theZones)\\\
    if not theZones then theZones = cfxZones.zones end\\\
    \\\
    local inRangeSet = {}\\\
    for zName, zData in pairs (theZones) do \\\
        if dcsCommon.dist(point, zData.point) < range then \\\
            table.insert(inRangeSet, zData)\\\
        end\\\
    end\\\
    return inRangeSet \\\
end\\\
\\\
-- get closest zone returns the zone that is closest to point \\\
function cfxZones.getClosestZone(point, theZones)\\\
    if not theZones then theZones = cfxZones.zones end\\\
    local currDelta = math.huge \\\
    local closestZone = nil\\\
    for zName, zData in pairs(theZones) do \\\
        local zPoint = cfxZone.getPoint(zData)\\\
        local delta = dcsCommon.dist(point, zPoint)\\\
        if (delta < currDelta) then \\\
            currDelta = delta\\\
            closestZone = zData\\\
        end\\\
    end\\\
    return closestZone, currDelta \\\
end\\\
\\\
-- return a random zone from the table passed in zones\\\
function cfxZones.pickRandomZoneFrom(zones)\\\
    if not zones then zones = cfxZones.zones end\\\
    local indexedZones = dcsCommon.enumerateTable(zones)\\\
    local r = math.random(#indexedZones)\\\
    return indexedZones[r]\\\
end\\\
\\\
-- return an zone element by index \\\
function cfxZones.getZoneByIndex(theZones, theIndex) \\\
    local enumeratedZones = dcsCommon.enumerateTable(theZones)\\\
    if (theIndex > #enumeratedZones) then\\\
        trigger.action.outText(\\\"WARNING: zone index \\\" .. theIndex .. \\\" out of bounds - max = \\\" .. #enumeratedZones, 30)\\\
        return nil end\\\
    if (theIndex < 1) then return nil end\\\
    \\\
    return enumeratedZones[theIndex]\\\
end\\\
\\\
-- place a smoke marker in center of zone, offset by dx, dy \\\
function cfxZones.markZoneWithSmoke(theZone, dx, dz, smokeColor)\\\
    local point = cfxZones.getPoint(theZone) --{} -- theZone.point\\\
    point.x = point.x + dx -- getpoint updates and returns copy \\\
    point.z = point.z + dz \\\
    -- get height at point \\\
    point.y = land.getHeight({x = point.x, y = point.z}) + 5\\\
    -- height-correct\\\
    --local newPoint= {x = point.x, y = land.getHeight({x = point.x, y = point.z}) + 3, z= point.z}\\\
    trigger.action.smoke(point, smokeColor)\\\
end\\\
\\\
-- place a smoke marker in center of zone, offset by radius and degrees \\\
function cfxZones.markZoneWithSmokePolar(theZone, radius, degrees, smokeColor)\\\
    local rads = degrees * math.pi / 180\\\
    local dx = radius * math.sin(rads)\\\
    local dz = radius * math.cos(rads)\\\
    cfxZones.markZoneWithSmoke(theZone, dx, dz, smokeColor)\\\
end\\\
\\\
-- place a smoke marker in center of zone, offset by radius and randomized degrees \\\
function cfxZones.markZoneWithSmokePolarRandom(theZone, radius, smokeColor)\\\
    local degrees = math.random(360)\\\
    cfxZones.markZoneWithSmokePolar(theZone, radius, degrees, smokeColor)\\\
end\\\
\\\
\\\
-- unitInZone returns true if theUnit is inside the zone \\\
-- the second value returned is the percentage of distance\\\
-- from center to rim, with 100% being entirely in center, 0 = outside\\\
-- the third value returned is the distance to center\\\
function cfxZones.pointInZone(thePoint, theZone)\\\
    if not (theZone) then return false, 0, 0 end\\\
        \\\
    local pflat = {x = thePoint.x, y = 0, z = thePoint.z}\\\
    \\\
    local zpoint = cfxZones.getPoint(theZone) -- updates zone if linked \\\
    local ppoint = thePoint -- xyz\\\
    local pflat = {x = ppoint.x, y = 0, z = ppoint.z}\\\
    local dist = dcsCommon.dist(zpoint, pflat)\\\
    \\\
    if theZone.isCircle then \\\
        if theZone.radius <= 0 then \\\
            return false, 0, 0\\\
        end\\\
\\\
        local success = dist < theZone.radius\\\
        local percentage = 0\\\
        if (success) then \\\
            percentage = 1 - dist / theZone.radius \\\
        end\\\
        return success, percentage, dist \\\
    \\\
    elseif theZone.isPoly then\\\
        local success = cfxZones.isPointInsidePoly(pflat, theZone.poly)\\\
        return success, 0, dist\\\
    else \\\
        trigger.action.outText(\\\"pointInZone: Unknown zone type for \\\" .. theZone.name, 10)\\\
    end\\\
\\\
    return false\\\
end\\\
\\\
function cfxZones.unitInZone(theUnit, theZone)\\\
    if not (theUnit) then return false, 0, 0 end\\\
    if not (theUnit:isExist()) then return false, 0, 0 end\\\
    -- force zone update if it is linked to another zone \\\
    -- pointInZone does update\\\
    local thePoint = theUnit:getPoint()\\\
    return cfxZones.pointInZone(thePoint, theZone)\\\
    \\\
end\\\
\\\
-- returns all units of the input set that are inside the zone \\\
function cfxZones.unitsInZone(theUnits, theZone)\\\
    if not theUnits then return {} end\\\
    if not theZone then return {} end\\\
    \\\
    local zoneUnits = {}\\\
    for index, aUnit in pairs(theUnits) do \\\
        if cfxZones.unitInZone(aUnit, theZone) then \\\
            table.insert( zoneUnits, aUnit)\\\
        end\\\
    end\\\
    return zoneUnits\\\
end\\\
\\\
function cfxZones.closestUnitToZoneCenter(theUnits, theZone)\\\
    -- does not care if they really are in zone. call unitsInZone first\\\
    -- if you need to have them filtered\\\
    -- theUnits MUST BE ARRAY\\\
    if not theUnits then return nil end\\\
    if #theUnits == 0 then return nil end\\\
    local closestUnit = theUnits[1]\\\
    for i=2, #theUnits do\\\
        local aUnit = theUnits[i]\\\
        if dcsCommon.dist(theZone.point, closestUnit:getPoint()) > dcsCommon.dist(theZone.point, aUnit:getPoint()) then \\\
            closestUnit = aUnit\\\
        end\\\
    end\\\
    return closestUnit\\\
end\\\
\\\
function cfxZones.anyPlayerInZone(theZone) -- returns first player it finds\\\
    for pname, pinfo in pairs(cfxPlayer.playerDB) do\\\
        local playerUnit = pinfo.unit\\\
        if (cfxZones.unitInZone(playerUnit, theZone)) then \\\
            return true, playerUnit\\\
        end\\\
    end -- for all players \\\
    return false, nil\\\
end\\\
\\\
\\\
-- grow zone\\\
function cfxZones.growZone()\\\
    -- circular zones simply increase radius\\\
    -- poly zones: not defined \\\
    \\\
end\\\
\\\
\\\
-- creating units in a zone\\\
function cfxZones.createGroundUnitsInZoneForCoalition (theCoalition, groupName, theZone, theUnits, formation, heading) \\\
    -- theUnits can be string or table of string \\\
    if not groupName then groupName = \\\"G_\\\"..theZone.name end \\\
    -- group name will be taken from zone name and prependend with \\\"G_\\\"\\\
    local theGroup = dcsCommon.createGroundGroupWithUnits(groupName, theUnits, theZone.radius, nil, formation)\\\
    \\\
    -- turn the entire formation to heading\\\
    if (not heading) then heading = 0 end\\\
    dcsCommon.rotateGroupData(theGroup, heading) -- currently, group is still at origin, no cx, cy\\\
    \\\
    \\\
    -- now move the group to center of theZone\\\
    dcsCommon.moveGroupDataTo(theGroup, \\\
                          theZone.point.x, \\\
                          theZone.point.z) -- watchit: Z!!!\\\
\\\
\\\
    -- create the group in the world and return it\\\
    -- first we need to translate the coalition to a legal \\\
    -- country. we use UN for neutral, cjtf for red and blue \\\
    local theSideCJTF = dcsCommon.coalition2county(theCoalition)\\\
    return coalition.addGroup(theSideCJTF, Group.Category.GROUND, theGroup)\\\
\\\
end\\\
\\\
-- parsing zone names. The first part of the name until the first blank \\\" \\\" \\\
-- is the prefix and is dropped unless keepPrefix is true. \\\
-- all others are regarded as key:value pairs and are then added \\\
-- to the zone \\\
-- separated by equal sign \\\"=\\\" AND MUST NOT CONTAIN BLANKS\\\
--\\\
-- example usage \\\"followZone unit=rotary-1 dx=30 dy=25 rotateWithHeading=true\\\
--\\\
-- OLD DEPRECATED TECH -- TO BE DECOMMISSIONED SOON, DO NOT USE\\\
-- \\\
--[[--\\\
function cfxZones.parseZoneNameIntoAttributes(theZone, keepPrefix)\\\
--    trigger.action.outText(\\\"Parsing zone:  \\\".. theZone.name, 30)\\\
    if not keepPrefix then keepPrefix = false end -- simply for clarity\\\
    -- now split the name into space-separated strings\\\
    local attributes = dcsCommon.splitString(theZone.name, \\\" \\\")\\\
    if not keepPrefix then table.remove(attributes, 1) end -- pop prefix\\\
\\\
    -- now parse all substrings and add them as attributes to theZone\\\
    for i=1, #attributes do \\\
        local a = attributes[i]\\\
        local kvp = dcsCommon.splitString(a, \\\"=\\\")\\\
        if #kvp == 2 then \\\
            -- we have key value pair\\\
            local theKey = kvp[1]\\\
            local theValue = kvp[2]\\\
            theZone[theKey] = theValue \\\
--            trigger.action.outText(\\\"Zone \\\".. theZone.name .. \\\" parsed: Key = \\\" .. theKey .. \\\", Value = \\\" .. theValue, 30)\\\
        else \\\
--            trigger.action.outText(\\\"Zone \\\".. theZone.name .. \\\": dropped attribute \\\" .. a, 30)\\\
        end\\\
    end \\\
end\\\
--]]--\\\
-- OLD DEPRECATED TECH -- TO BE DECOMMISSIONED SOON, DO NOT USE\\\
--[[--\\\
function cfxZones.processCraterZones ()\\\
    local craters = cfxZones.zonesStartingWith(\\\"crater\\\")\\\
\\\
    \\\
\\\
    -- all these zones need to be processed and their name infor placed into attributes\\\
    for cName, cZone in pairs(craters) do\\\
        cfxZones.parseZoneNameIntoAttributes(cZone)\\\
        \\\
        -- blow stuff up at the location of the zone \\\
        local cPoint = cZone.point\\\
        cPoint.y = land.getHeight({x = cPoint.x, y = cPoint.z})  -- compensate for ground level\\\
        trigger.action.explosion(cPoint, 900)\\\
         \\\
        -- now interpret and act on the crater info \\\
        -- to destroy and place fire. \\\
        \\\
        -- fire has small, medium, large \\\
        -- eg. fire=large\\\
        \\\
    end\\\
end\\\
--]]--\\\
\\\
--\\\
-- PROPERTY PROCESSING \\\
--\\\
\\\
function cfxZones.getAllZoneProperties(theZone, caseInsensitive) -- return as dict \\\
    if not caseInsensitive then caseInsensitive = false end \\\
    if not theZone then return {} end \\\
    \\\
    local dcsProps = theZone.properties -- zone properties in dcs format \\\
    local props = {}\\\
    -- dcs has all properties as array with values .key and .value \\\
    -- so convert them into a dictionary \\\
    for i=1, #dcsProps do \\\
        local theProp = dcsProps[i]\\\
        local theKey = \\\"dummy\\\"\\\
        if string.len(theProp.key) > 0 then theKey = theProp.key end \\\
        if caseInsensitive then theKey = theKey:upper() end \\\
        props[theKey] = theProp.value\\\
    end\\\
    return props \\\
end\\\
\\\
function cfxZones.extractPropertyFromDCS(theKey, theProperties)\\\
--    make lower case conversion if not case sensitive\\\
    if not cfxZones.caseSensitiveProperties then \\\
        theKey = string.lower(theKey)\\\
    end\\\
\\\
-- iterate all keys and compare to what we are looking for     \\\
    for i=1, #theProperties do\\\
        local theP = theProperties[i]\\\
        local existingKey = theP.key \\\
        if not cfxZones.caseSensitiveProperties then \\\
            existingKey = string.lower(existingKey)\\\
        end\\\
        if existingKey == theKey then \\\
            return theP.value\\\
        end\\\
    end\\\
    return nil \\\
end\\\
\\\
function cfxZones.getZoneProperty(cZone, theKey)\\\
    local props = cZone.properties\\\
    local theVal = cfxZones.extractPropertyFromDCS(theKey, props)\\\
    return theVal\\\
end\\\
\\\
function cfxZones.getStringFromZoneProperty(theZone, theProperty, default)\\\
    if not default then default = \\\"\\\" end\\\
    local p = cfxZones.getZoneProperty(theZone, theProperty)\\\
    if not p then return default end\\\
    if type(p) == \\\"string\\\" then \\\
        if p == \\\"\\\" then p = default end \\\
        return p\\\
    end\\\
    return default -- warning. what if it was a number first?\\\
end\\\
\\\
function cfxZones.getMinMaxFromZoneProperty(theZone, theProperty)\\\
    local p = cfxZones.getZoneProperty(theZone, theProperty)\\\
    local theNumbers = dcsCommon.splitString(p, \\\" \\\")\\\
\\\
    return tonumber(theNumbers[1]), tonumber(theNumbers[2])\\\
    \\\
end\\\
\\\
function cfxZones.hasProperty(theZone, theProperty) \\\
    return cfxZones.getZoneProperty(theZone, theProperty) ~= nil \\\
end\\\
\\\
\\\
function cfxZones.getBoolFromZoneProperty(theZone, theProperty, defaultVal)\\\
    if not defaultVal then defaultVal = false end \\\
    if type(defaultVal) ~= \\\"boolean\\\" then \\\
        defaultVal = false \\\
    end\\\
\\\
    if not theZone then \\\
        trigger.action.outText(\\\"WARNING: NIL Zone in getBoolFromZoneProperty\\\", 30)\\\
        return defaultVal\\\
    end\\\
\\\
\\\
    local p = cfxZones.getZoneProperty(theZone, theProperty)\\\
    if not p then return defaultVal end\\\
\\\
    -- make sure we compare so default always works when \\\
    -- answer isn't exactly the opposite\\\
    p = p:lower() \\\
    if defaultVal == false then \\\
        -- only go true if exact match to yes or true \\\
        theBool = false \\\
        theBool = (p == 'true') or (p == 'yes') or p == \\\"1\\\"\\\
        return theBool\\\
    end\\\
    \\\
    local theBool = true \\\
    -- only go false if exactly no or false or \\\"0\\\"\\\
    theBool = (p ~= 'false') and (p ~= 'no') and (p ~= \\\"0\\\") \\\
    return theBool\\\
end\\\
\\\
function cfxZones.getCoalitionFromZoneProperty(theZone, theProperty, default)\\\
    if not default then default = 0 end\\\
    local p = cfxZones.getZoneProperty(theZone, theProperty)\\\
    if not p then return default end  \\\
    if type(p) == \\\"number\\\" then -- can't currently really happen\\\
        if p == 1 then return 1 end \\\
        if p == 2 then return 2 end \\\
        return 0\\\
    end\\\
    \\\
    if type(p) == \\\"string\\\" then \\\
        if p == \\\"1\\\" then return 1 end \\\
        if p == \\\"2\\\" then return 2 end \\\
        if p == \\\"0\\\" then return 0 end \\\
        \\\
        p = p:lower()\\\
        \\\
        if p == \\\"red\\\" then return 1 end \\\
        if p == \\\"blue\\\" then return 2 end \\\
        if p == \\\"neutral\\\" then return 0 end\\\
        if p == \\\"all\\\" then return 0 end \\\
        return default \\\
    end\\\
    \\\
    return default \\\
end\\\
\\\
function cfxZones.getNumberFromZoneProperty(theZone, theProperty, default)\\\
--TODO: trim string \\\
    if not default then default = 0 end\\\
    local p = cfxZones.getZoneProperty(theZone, theProperty)\\\
    p = tonumber(p)\\\
    if not p then return default else return p end\\\
end\\\
\\\
function cfxZones.getVectorFromZoneProperty(theZone, theProperty, minDims, defaultVal)\\\
    if not minDims then minDims = 0 end \\\
    if not defaultVal then defaultVal = 0 end \\\
    local s = cfxZones.getStringFromZoneProperty(theZone, theProperty, \\\"\\\")\\\
    local sVec = dcsCommon.splitString(s, \\\",\\\")\\\
    local nVec = {}\\\
    for idx, numString in pairs (sVec) do \\\
        local n = tonumber(numString)\\\
        if not n then n = defaultVal end\\\
        table.insert(nVec, n)\\\
    end\\\
    -- make sure vector contains at least minDims values \\\
    while #nVec < minDims do \\\
        table.insert(nVec, defaultVal)\\\
    end\\\
    \\\
    return nVec \\\
end\\\
\\\
\\\
--\\\
-- Moving Zones. They contain a link to their unit\\\
-- they are always located at an offset (x,z) or delta, phi \\\
-- to their master unit. delta phi allows adjustment for heading\\\
-- The cool thing about moving zones in cfx is that they do not\\\
-- require special handling, they are always updated \\\
-- and work with 'pointinzone' etc automatically\\\
\\\
-- Always works on cfx Zones, NEVER on DCS zones.\\\
--\\\
-- requires that readFromDCS has been done\\\
--\\\
function cfxZones.getPoint(aZone) -- always works, wven linked, point can be reused \\\
    if aZone.linkedUnit then \\\
        local theUnit = aZone.linkedUnit\\\
        -- has a link. is link existing?\\\
        if theUnit:isExist() then \\\
            -- updates zone position \\\
            cfxZones.centerZoneOnUnit(aZone, theUnit)\\\
            cfxZones.offsetZone(aZone, aZone.dx, aZone.dy)\\\
        end\\\
    end\\\
    local thePos = {}\\\
    thePos.x = aZone.point.x\\\
    thePos.y = 0 -- aZone.y \\\
    thePos.z = aZone.point.z\\\
    return thePos \\\
end\\\
\\\
function cfxZones.linkUnitToZone(theUnit, theZone, dx, dy) -- note: dy is really Z, don't get confused!!!!\\\
    theZone.linkedUnit = theUnit\\\
    if not dx then dx = 0 end\\\
    if not dy then dy = 0 end \\\
    theZone.dx = dx\\\
    theZone.dy = dy \\\
end\\\
\\\
function cfxZones.updateMovingZones()\\\
    cfxZones.updateSchedule = timer.scheduleFunction(cfxZones.updateMovingZones, {}, timer.getTime() + 1/cfxZones.ups)\\\
    -- simply scan all cfx zones for the linkedUnit property and if there\\\
    -- update the zone's points\\\
    for aName,aZone in pairs(cfxZones.zones) do\\\
        if aZone.linkedUnit then \\\
            local theUnit = aZone.linkedUnit\\\
            -- has a link. is link existing?\\\
            if theUnit:isExist() then \\\
                cfxZones.centerZoneOnUnit(aZone, theUnit)\\\
                cfxZones.offsetZone(aZone, aZone.dx, aZone.dy)\\\
                --trigger.action.outText(\\\"cf/x zones update \\\" .. aZone.name, 30)\\\
            end\\\
        end\\\
    end\\\
end\\\
\\\
function cfxZones.startMovingZones()\\\
    -- read all zoness, and look for a property called 'linkedUnit'\\\
    -- which will make them a linked zone if there is a unit that exists\\\
    for aName,aZone in pairs(cfxZones.zones) do\\\
        local lU = cfxZones.getZoneProperty(aZone, \\\"linkedUnit\\\")\\\
        if lU then \\\
            -- this zone is linked to a unit\\\
            theUnit = Unit.getByName(lU)\\\
            local useOffset = cfxZones.getBoolFromZoneProperty(aZone, \\\"useOffset\\\", false)\\\
            if useOffset then aZone.useOffset = true end\\\
            if theUnit then\\\
                local dx = 0\\\
                local dz = 0\\\
                if useOffset then \\\
                    local delta = dcsCommon.vSub(aZone.point,theUnit:getPoint()) -- delta = B - A \\\
                    dx = delta.x \\\
                    dz = delta.z\\\
                end\\\
                cfxZones.linkUnitToZone(theUnit, aZone, dx, dz)\\\
                --trigger.action.outText(\\\"cf/x zones: linked \\\" .. aZone.name .. \\\" to \\\" .. theUnit:getName(), 30)\\\
                if useOffset then \\\
                    --trigger.action.outText(\\\"and dx = \\\" .. dx .. \\\" dz = \\\" .. dz, 30)\\\
                end\\\
            end\\\
 \\\
        end\\\
    end\\\
end\\\
\\\
--\\\
-- init\\\
--\\\
\\\
function cfxZones.init()\\\
    -- read all zones into my own db\\\
    cfxZones.readFromDCS(true) -- true: erase old\\\
    \\\
    -- now, pre-read zone owner for all zones\\\
    -- note, all zones with this property are by definition owned zones.\\\
    -- and hence will be read anyway. this will merely ensure that the \\\
    -- ownership is established right away\\\
    local pZones = cfxZones.zonesWithProperty(\\\"owner\\\")\\\
    for n, aZone in pairs(pZones) do\\\
        aZone.owner = cfxZones.getCoalitionFromZoneProperty(aZone, \\\"owner\\\", 0)\\\
    end\\\
        \\\
    \\\
    -- now initialize moving zones\\\
    cfxZones.startMovingZones()\\\
    cfxZones.updateMovingZones() -- will auto-repeat\\\
    \\\
    trigger.action.outText(\\\"cf/x Zones v\\\".. cfxZones.version .. \\\": loaded\\\", 10)\\\
end\\\
\\\
-- get everything rolling\\\
cfxZones.init()\\\
\");a_do_script(\"-- cfx player handler for DCS Missions by cf/x AG\\\
-- \\\
-- a module that provides easy access to a mission's player data\\\
-- multi-player only\\\
--\\\
\\\
cfxPlayer = {}\\\
                           -- a call to cfxPlayer.start()\\\
cfxPlayer.version = \\\"3.0.0\\\"\\\
--[[-- VERSION HISTORY\\\
\\\
- 2.2.3 - fixed isPlayerUnit() wrong return of true instead of nil\\\
- 2.2.4 - getFirstGroupPlayer\\\
- 2.3.0 - added event filtering for monitors\\\
        - limited code clean-up\\\
        - removed XXXmatchUnitToPlayer\\\
        - corrected isPlayerUnit once more\\\
        - removed autostart option\\\
        - removed detectPlayersLeaving option \\\
- 3.0.0 - added detection of network players \\\
        - added new events newPlayer, changePlayer \\\
        - and leavePlayer (never called)\\\
--]]--\\\
\\\
cfxPlayer.verbose = false;\\\
cfxPlayer.running = false \\\
cfxPlayer.ups = 1 -- updates per second: how often do we query the players \\\
                  -- a good value is 1\\\
cfxPlayer.playerDB = {} -- the list of all player UNITS\\\
        -- attributes\\\
            -- name - name of unit occupied by player\\\
            -- unit - unit this player is controlling\\\
            -- unitName - same as name\\\
            -- group - group this unit belongs to. can't change without also changing unit\\\
            -- groupName - name of group\\\
            -- coalition\\\
cfxPlayerGroups = {} -- GLOBAL VAR \\\
-- list of all current groups that have players in them \\\
-- can call out to handlers if group is added or removed\\\
-- use this in MP games to organise messaging and keep score\\\
-- by default, groupinfo merely contains the .group reference \\\
-- and is accessed by name as key which is also accessible by .name\\\
            \\\
cfxPlayer.netPlayers = {} -- new for version 3: real player detection\\\
-- a dict sorted by player name that containts the unit name for last pass \\\
\\\
cfxPlayer.updateSchedule = 0 -- ID used for scheduling update\\\
cfxPlayer.coalitionSides = {0, 1, 2} -- we currently have neutral, red, blue\\\
\\\
cfxPlayer.monitors = {} -- callbacks for events\\\
\\\
---\\\
-- structure of playerInfo\\\
--   - name - player's unit name\\\
--   - unit - the unit the player is occupying. Multi-Crew: many people can be in same unit\\\
--   - unitName same as name \\\
\\\
--   - coalition - the side the unit is on, as a number \\\
function cfxPlayer.dumpRawPlayers()\\\
    trigger.action.outText(\\\"+++ debug: raw player dump ---\\\", 30)\\\
    for i=1, #cfxPlayer.coalitionSides do \\\
        local theSide = cfxPlayer.coalitionSides[i] \\\
        -- get all players for this side\\\
        local thePlayers = coalition.getPlayers(theSide) \\\
        for p=1, #thePlayers do \\\
            aPlayerUnit = thePlayers[p] -- docs say this is a unit table, not a person table!\\\
            trigger.action.outText(i .. \\\"-\\\" .. p ..\\\": unit: \\\" .. aPlayerUnit:getName() .. \\\" controlled by \\\" .. aPlayerUnit:getPlayerName() , 30)\\\
        end\\\
    end\\\
    trigger.action.outText(\\\"+++ debug: END DUMP ----\\\", 30)\\\
end\\\
\\\
\\\
function cfxPlayer.getAllPlayers()\\\
    return cfxPlayer.playerDB -- get entire db. make sure not to screw around with it\\\
end\\\
\\\
\\\
function cfxPlayer.getPlayerInfoByName(theUnitName) -- note: UNIT name\\\
    thePlayer = cfxPlayer.playerDB[theUnitName] -- access the entry, not we are accessing by unit name\\\
    return thePlayer\\\
end\\\
\\\
function cfxPlayer.getPlayerInfoByIndex(theIndex) \\\
    local enumeratedInfo = dcsCommon.enumerateTable(cfxPlayer.playerDB)\\\
    if (theIndex > #enumeratedInfo) then\\\
        trigger.action.outText(\\\"WARNING: player index \\\" .. theIndex .. \\\" out of bounds - max = \\\" .. #enumeratedInfo, 30)\\\
        return nil end\\\
    if (theIndex < 1) then return nil end\\\
    \\\
    return enumeratedInfo[theIndex]\\\
end\\\
\\\
-- this is now a true/false function that returns true if unit is player \\\
function cfxPlayer.XXXmatchUnitToPlayer(theUnit) -- what's difference to getPlayerInfo? GetPlayerInfo ALLOCATES if not exists \\\
\\\
    if not (theUnit) then return false end\\\
    if not (theUnit:isExist()) then return false end \\\
    \\\
    -- PATCH: if theUnit:getPlayerName() returns anything but nil\\\
    -- this is a player unit\\\
    -- unfortunately, this can sometimes fail\\\
    -- so make sure the function existst\\\
    -- it failed because the next level up function \\\
    -- returned true if i returned anything but nil, and I return \\\
    -- true or false, both not nil \\\
    -- this proc works \\\
    if not theUnit.getPlayerName then return false end \\\
    \\\
    local pName = theUnit:getPlayerName()\\\
    if pName ~= nil then \\\
        -- trigger.action.outText(\\\"+++matchUnit: player name \\\" .. pName .. \\\" for unit \\\" .. theUnit:getName(), 30)\\\
        return true \\\
    end \\\
    \\\
    if (true) then \\\
        return false\\\
    end \\\
    \\\
    -- ignmore old code below\\\
\\\
    for pname, pInfo in pairs(cfxPlayer.playerDB) do \\\
        if (pInfo.unit == theUnit) then \\\
            return pInfo\\\
        end\\\
    end\\\
    return nil\\\
end\\\
\\\
function cfxPlayer.XXXisPlayerUnitAlt(theUnit)\\\
    for pname, pInfo in pairs(cfxPlayer.playerDB) do \\\
        if (pInfo.unit == theUnit) then \\\
            return true\\\
        end\\\
    end\\\
    return false\\\
end\\\
\\\
function cfxPlayer.isPlayerUnit(theUnit)\\\
    -- new patch. simply check if getPlayerName returns something\\\
    if not theUnit then return false end \\\
    local pName = theUnit:getPlayerName()\\\
    if pName then return true end \\\
    return false \\\
    --\\\
    -- fixed, erroneously expected a nil from matchUnitToPlayer \\\
    --return (cfxPlayer.matchUnitToPlayer(theUnit)) -- was: ~=nil, wrong because match returns true/false\\\
end\\\
\\\
\\\
\\\
function cfxPlayer.getPlayerUnitType(thePlayerInfo) -- \\\
    if (thePlayerInfo) then \\\
        theUnit = thePlayerInfo.unit\\\
        if (theUnit) and (theUnit:isExist()) then \\\
            return theUnit:getTypeName()\\\
        end\\\
    end\\\
    return nil \\\
end\\\
\\\
\\\
-- get player's unit info\\\
-- accesses player DB and returns the player's info record for the\\\
-- player's Unit. If record does not exist in db, a new record is allocated\\\
-- returns true if verification succeeeds: player unit existed before, and\\\
-- false otherwise. in the latter case, A NEW playerInfo object is returned\\\
function cfxPlayer.getPlayerInfo(theUnit)\\\
    local playerName = theUnit:getPlayerName() -- retrieve the name \\\
    --- PATCH!!!!!!!\\\
    --- on multi-crew, we only have the pilot as getPlayerName. \\\
    --- we now switch to the unit's name instead \\\
    playerName = theUnit:getName() \\\
    \\\
    -- trigger.action.outText(\\\"Player: \\\".. playerName, 10)\\\
\\\
    local existingPlayer = cfxPlayer.getPlayerInfoByName(playerName) -- try and access DB\\\
    if existingPlayer then\\\
        -- this player exists in the db. return the record\\\
        return true, existingPlayer;\\\
\\\
    else\\\
        -- this is a new player.\\\
        -- set up a new playerinfo record for this name\\\
        local newPlayerInfo = {}\\\
        newPlayerInfo.name = playerName\\\
        newPlayerInfo.unit = theUnit\\\
        newPlayerInfo.unitName = theUnit:getName()\\\
        newPlayerInfo.group = theUnit:getGroup()\\\
        newPlayerInfo.groupName = newPlayerInfo.group:getName()\\\
        newPlayerInfo.coalition = theUnit:getCoalition() -- seems to work when first param is class self\\\
        -- note that this record did not exist, and return record\\\
        return false, newPlayerInfo\\\
    end\\\
    \\\
end;\\\
\\\
function cfxPlayer.getSinglePlayerAirframe()\\\
    -- ALWAYS return a string! This is for debugging purposes\\\
    local thePlayers = {}\\\
    local count = 0\\\
    local theAirframe = \\\"(none)\\\"\\\
    for pname, pinfo in pairs(cfxPlayer.playerDB) do \\\
        count = count + 1\\\
        theAirframe = pinfo.unit:getTypeName()\\\
    end\\\
    if count < 2 then return theAirframe end -- also returns if count == 0\\\
    return \\\"<Multiplayer Not Yet Supported>\\\"\\\
end\\\
\\\
function cfxPlayer.getAnyPlayerAirframe()\\\
    -- use this for debugging, in single-player missions, or where it \\\
    -- is unimportant which player, just a player\\\
    -- assumes that all players use the same airframe or are in the \\\
    -- same group / unit \\\
    for pname, pinfo in pairs(cfxPlayer.playerDB) do \\\
        if (pinfo.unit:isExist()) then \\\
            -- player may just have crashed or left\\\
            local theAirframe = pinfo.unit:getTypeName()\\\
            return theAirframe -- we simply stop after first successfuly access\\\
        end\\\
    end\\\
    return \\\"error: no player\\\"\\\
end\\\
\\\
function cfxPlayer.getFirstGroupPlayerName(theGroup)\\\
 -- get the name of player of the first \\\
 -- player-controlled unit I come across in \\\
 -- this group \\\
    local allGroupUnits = theGroup:getUnits()\\\
    for ukey, uvalue in pairs(allGroupUnits) do \\\
        -- iterate units in group\\\
        if (uvalue:isExist())  then -- and cfxPlayer.isPlayerUnit(uvalue)) \\\
            -- player may just have crashed or left\\\
            -- but all units in the same group have the same type when they are aircraft\\\
            if cfxPlayer.isPlayerUnit(uvalue) then \\\
                return uvalue:getPlayerName(), uvalue \\\
            end\\\
        end\\\
    end\\\
    return nil \\\
end\\\
\\\
function cfxPlayer.getAnyGroupPlayerAirframe(theGroup)\\\
    -- get the first player-driven unit in the group\\\
    -- and pass back the airframe that is being used \\\
    local allGroupUnits = theGroup:getUnits()\\\
    for ukey, uvalue in pairs(allGroupUnits) do \\\
        \\\
        if (uvalue:isExist())  then -- and cfxPlayer.isPlayerUnit(uvalue)) \\\
            -- player may just have crashed or left\\\
            -- but all units in the same group have the same type when they are aircraft\\\
            local theAirframe = uvalue:getTypeName()\\\
            return theAirframe -- we simply stop after first successfuly access\\\
        end\\\
    end\\\
    return \\\"error: no live player in group \\\"\\\
end\\\
\\\
\\\
\\\
function cfxPlayer.getAnyPlayerPosition()\\\
    -- use this for debugging, in single-player missions, or where it \\\
    -- is unimportant which player, just a player\\\
    -- will cause issues when you derive location info or group info \\\
    -- from that player\\\
    for pname, pinfo in pairs(cfxPlayer.playerDB) do\\\
        if (pinfo.unit:isExist()) then \\\
            local thePoint = pinfo.unit:getPoint()\\\
            return thePoint -- we simply stop after first successfuly access\\\
        end\\\
    end\\\
    return nil\\\
end\\\
\\\
function cfxPlayer.getAnyGroupPlayerPosition(theGroup)\\\
    -- enter with dcs group to search for player units within\\\
    -- step one: get all units that belong to that group\\\
    local allGroupUnits = theGroup:getUnits()\\\
    -- we now iterate all returned units and look for \\\
    -- a unit that is a player unit.\\\
    for ukey, uvalue in pairs(allGroupUnits) do \\\
        -- we currently assume single-unit groups for players\\\
        if (uvalue:isExist()) then -- and cfxPlayer.isPlayerUnit(uvalue))\\\
            -- player may just have crashed or left\\\
            local thePoint = uvalue:getPoint()\\\
            return thePoint -- we simply stop after first successfuly access\\\
        end\\\
    \\\
    end\\\
    return nil\\\
end\\\
\\\
function cfxPlayer.getAnyGroupPlayerInfo(theGroup)\\\
    for pname, pinfo in pairs(cfxPlayer.playerDB) do \\\
        if (pinfo.unit:isExist() and pinfo.group == theGroup) then \\\
            return pinfo -- we simply stop after first successfuly access\\\
        end\\\
    end\\\
    return \\\"error: no player\\\"\\\
end\\\
\\\
\\\
function cfxPlayer.getAllPlayerGroups()\\\
    -- merely accessot. better would be returning a copy \\\
    return cfxPlayerGroups    \\\
end\\\
\\\
function cfxPlayer.getGroupDataForGroupNamed(name)\\\
    if not name then return nil end \\\
    return cfxPlayerGroups[name]\\\
end\\\
\\\
function cfxPlayer.getPlayersInGroup(theGroup)\\\
    if not theGroup then return {} end\\\
    if not theGroup:isExist() then return {} end \\\
    local gName = theGroup:getName()\\\
    local thePlayers = {}\\\
    \\\
    for pname, pinfo in pairs(cfxPlayer.playerDB) do         \\\
        local pgName = \\\"\\\"\\\
        if pinfo.group:isExist() then pgName = pinfo.group:getName() end \\\
        if (gName == pgName) then \\\
            table.insert(thePlayers, pinfo)\\\
        end\\\
    end\\\
    return thePlayers\\\
end\\\
\\\
-- update() is called regularly to check up on the players\\\
-- when a mismatch to last player state is found, callbacks \\\
-- can be invoked\\\
\\\
function cfxPlayer.update()\\\
    \\\
    -- first, re-schedule my next invocation\\\
    cfxPlayer.updateSchedule = timer.scheduleFunction(cfxPlayer.update, {}, timer.getTime() + 1/cfxPlayer.ups)\\\
    \\\
    -- now scan the coalitions for all players\\\
    local currCount = 0 -- number of players found this pass\\\
    local currDB = {} -- db of player units this pass\\\
    local currPlayerUnitsByNames = {}    \\\
    -- iterate over all colaitions \\\
    for i=1, #cfxPlayer.coalitionSides do \\\
        local theSide = cfxPlayer.coalitionSides[i] \\\
        -- get all player units for this side\\\
        local thePlayers = coalition.getPlayers(theSide) -- returns UNITs!!!\\\
\\\
        for p=1, #thePlayers do \\\
            -- we now iterate the Units and compare what we find\\\
            local thePlayerUnit = thePlayers[p]\\\
            local isExistingPlayerUnit, theInfo = cfxPlayer.getPlayerInfo(thePlayerUnit)\\\
            \\\
            if (not isExistingPlayerUnit) then \\\
                -- add Unit (not player!) to db\\\
                cfxPlayer.playerDB [theInfo.name] = theInfo\\\
                cfxPlayer.invokeMonitorsForEvent(\\\"new\\\", \\\"Player Unit \\\" .. theInfo.name .. \\\" entered mission\\\", theInfo, {})\\\
\\\
            else\\\
                -- player's unit existed last time around\\\
                -- see if something changed:\\\
    \\\
-- currently, we track units, not players. side changes for units can't happen AT ALL \\\
                \\\
                if theInfo.coalition ~= thePlayerUnit:getCoalition() then    \\\
                    local theData = {}\\\
                    theData.old = theInfo.coalition\\\
                    theData.new = thePlayerUnit:getCoalition()\\\
\\\
                    -- we invoke a callback\\\
                    cfxPlayer.invokeMonitorsForEvent(\\\"side\\\", \\\"Player \\\" .. theInfo.name .. \\\" switched sides to \\\" .. thePlayerUnit:getCoalition(), theInfo, theData)\\\
\\\
                end;\\\
\\\
-- we now check if the player has changed groups\\\
-- sinced we track units, this CANT HAPPEN AT ALL \\\
\\\
                if theInfo.group ~= thePlayerUnit:getGroup() then \\\
                    local theData = {}\\\
                    theData.old = theInfo.group\\\
                    theData.new = thePlayerUnit:getGroup()\\\
                    cfxPlayer.invokeMonitorsForEvent(\\\"group\\\", \\\"Player changed group to \\\" .. thePlayerUnit:getGroup():getName(), theInfo, theData)\\\
                    trigger.action.outText(\\\"+++ debug: Player \\\" .. theInfo.name .. \\\" changed GROUP to: \\\" .. thePlayerUnit:getGroup():getName(), 30)\\\
                end\\\
\\\
                -- we should now check if the player has changed units\\\
-- since we track units, this cant happen at all\\\
                if theInfo.unit ~= thePlayerUnit then\\\
                    -- player changed unit \\\
                    local theData = {}\\\
                    theData.old = theInfo.unit\\\
                    -- the old unit's name is still available in theInfo.unitName \\\
                    theData.oldUnitName = theInfo.unitName \\\
                    theData.new = thePlayerUnit\\\
                    -- update Player Info\\\
                    cfxPlayer.invokeMonitorsForEvent(\\\"unit\\\", \\\"Player changed unit to \\\" .. thePlayerUnit:getName(), theInfo, theData)\\\
                    \\\
                end\\\
                -- update the playerEntry. always done\\\
                theInfo.unit = thePlayerUnit\\\
                theInfo.unitName = thePlayerUnit:getName()\\\
                theInfo.coalition = thePlayerUnit:getCoalition()\\\
                theInfo.group = thePlayerUnit:getGroup()        \\\
            end;\\\
            \\\
            -- add this entry to current pass db so we can detect\\\
            -- any discrepancies to last pass\\\
            currDB[theInfo.name] = theInfo \\\
            \\\
            -- now update current network player name db\\\
            local playerUnitName = thePlayerUnit:getName()\\\
            if not thePlayerUnit:isExist() then playerUnitName = \\\"<none>\\\" end \\\
            currPlayerUnitsByNames[thePlayerUnit:getPlayerName()] = playerUnitName\\\
        end -- for all player units of this side\\\
    end -- for all sides\\\
    \\\
    -- we can now check if a player unit has disappeared    \\\
    -- we do this by checking that all old entries from cfxPlayer.playerDB\\\
    -- have an existing counterpart in new currDB\\\
    for name, info in pairs(cfxPlayer.playerDB) do\\\
        local matchingEntry = currDB[name]\\\
        if matchingEntry then \\\
            -- allright nothing to do\\\
        else\\\
            -- whoa, this record is missing!\\\
            -- do we care?\\\
            if true then -- (cfxPlayer.detectPlayersLeaving) then\\\
                -- yes! trigger an event\\\
                cfxPlayer.invokeMonitorsForEvent(\\\"leave\\\", \\\"Player left mission\\\", info, {})\\\
                -- we don't need to destroy entry, as we simply replace the\\\
                -- playerDB with currDB at end of update\\\
            else \\\
                -- no, just copy old data over. They'll be back\\\
                currDB[name] = info\\\
            end\\\
        end \\\
    end;\\\
    \\\
    -- we now perform a group check and update all groups for players \\\
    local currPlayerGroups = {}\\\
    for pName, pInfo in pairs(currDB) do \\\
        -- retrieve player unit and make sure it still exists\\\
        local theUnit = pInfo.unit\\\
        if theUnit:isExist() then \\\
            -- yeah, it exists allright. let's get to the group\\\
            local theGroup = theUnit:getGroup()\\\
            local gName = theGroup:getName()\\\
            -- see if this group is new\\\
            local thePGroup = cfxPlayerGroups[gName]\\\
            if not thePGroup then \\\
                -- allocate new group\\\
                thePGroup = {}\\\
                thePGroup.group = theGroup\\\
                thePGroup.name = gName \\\
                thePGroup.primeUnit = theUnit -- may be used as fallback\\\
                thePGroup.primeUnitName = theUnit:getName() -- also fallback only\\\
                thePGroup.id = theGroup:getID()\\\
                cfxPlayer.invokeMonitorsForEvent(\\\"newGroup\\\", \\\"New Player Group \\\" .. gName .. \\\" appeared\\\", nil, thePGroup)\\\
            end\\\
            currPlayerGroups[gName] = thePGroup -- update group table\\\
        end\\\
    end\\\
\\\
    -- now check if a player group has disappeared\\\
    for gkey, gval in pairs(cfxPlayerGroups) do \\\
        if not currPlayerGroups[gkey] then \\\
            cfxPlayer.invokeMonitorsForEvent(\\\"removeGroup\\\", \\\"A Player Group \\\" .. gkey .. \\\" vanished\\\", nil, gval) -- gval is OLD set, contains group \\\
        end\\\
    end\\\
    \\\
    -- version 3 addion: track network players\\\
    -- see if a new player has appeared \\\
    for aPlayerName, aPlayerUnitName in pairs(currPlayerUnitsByNames) do \\\
        -- see if this name was already in last \\\
        if cfxPlayer.netPlayers[aPlayerName] then \\\
            -- yes. but was it the same unit?\\\
            if cfxPlayer.netPlayers[aPlayerName] == currPlayerUnitsByNames[aPlayerName] then \\\
                -- all is well, no change \\\
            else \\\
                -- player has changed units \\\
                -- since they can't disappear, \\\
                -- this event can happen \\\
                local data = {}\\\
                data.oldUnitName = cfxPlayer.netPlayers[aPlayerName]\\\
                data.newUnitName = aPlayerUnitName\\\
                data.playerName = aPlayerName\\\
                if aPlayerUnitName == \\\"\\\" then aPlayerUnitName = \\\"<none>\\\" end \\\
                if aPlayerUnitName == \\\"<none>\\\" then \\\
                    -- unit no longer exists, player probably dead,\\\
                    -- parachuting or spectating. Maybe even left game\\\
                    -- resgisters as 'change' -- is 'left unit'\\\
                    cfxPlayer.invokeMonitorsForEvent(\\\"changePlayer\\\", \\\"A Player left unit \\\" .. data.oldUnitName, nil, data)\\\
                else \\\
                    -- changed to new unit\\\
                    cfxPlayer.invokeMonitorsForEvent(\\\"changePlayer\\\", \\\"A Player changed to unit \\\" .. aPlayerUnitName, nil, data)\\\
                end \\\
            end\\\
        else \\\
            -- this is a new player\\\
            local data = {}\\\
            data.playerName = aPlayerName\\\
            data.newUnitName = aPlayerUnitName\\\
            cfxPlayer.invokeMonitorsForEvent(\\\"newPlayer\\\", \\\"New Player appeared \\\" .. aPlayerName .. \\\" in unit \\\" .. aPlayerUnitName, nil, data)\\\
        end\\\
    end\\\
\\\
    -- version 3: detect if a player left \\\
    for oldPlayerName, oldUnitName in pairs(cfxPlayer.netPlayers) do \\\
        if not currPlayerUnitsByNames[oldPlayerName] then \\\
            --local data = {}\\\
            --data.playerName = oldPlayerName\\\
            --data.oldUnitName = oldUnitName\\\
            --cfxPlayer.invokeMonitorsForEvent(\\\"leavePlayer\\\", \\\"Player \\\" .. oldPlayerName .. \\\" disappeared from unit \\\" .. oldUnitName, nil, data)\\\
            --\\\
            -- we keep the player in the db by copying \\\
            -- it over and set the unit name to \\\"\\\"\\\
            -- will cause at least once 'change' event later \\\
            -- probably two in MP\\\
            currPlayerUnitsByNames[oldPlayerName] = \\\"<none>\\\"\\\
        end\\\
    end\\\
    \\\
    -- update playerGroups for this cycle\\\
    cfxPlayerGroups = currPlayerGroups\\\
    \\\
    -- update network player for this c<cle \\\
    cfxPlayer.netPlayers = currPlayerUnitsByNames\\\
    \\\
    -- finally, we simply replace the old db with the new one\\\
    cfxPlayer.playerDB = currDB;\\\
end\\\
\\\
function cfxPlayer.getAllNetPlayerNames ()\\\
    local themAll = {}\\\
    for aName, aUnitName in cfxPlayer.netPlayers do \\\
        table.insert(themAll, aName)\\\
    end\\\
    return themAll\\\
end\\\
\\\
function cfxPlayer.getPlayerUnitName(aPlayerName) \\\
    if not aPlayerName then return nil end \\\
    return cfxPlayer.netPlayers[aPlayerName]\\\
end\\\
\\\
function cfxPlayer.isPlayerSeated(aPlayerName)\\\
    local unitName = cfxPlayer.getPlayerUnitName(aPlayerName)\\\
    if not unitName then return false end \\\
    if unitName == \\\"\\\" or unitName == \\\"<none>\\\" then return false end \\\
    return true \\\
end\\\
\\\
-- add a monitor to be notified of player events\\\
-- may provide a whitelist of events as array of strings\\\
function cfxPlayer.addMonitor(callback, events)\\\
    local newMonitor = {}\\\
    newMonitor.callback = callback\\\
    newMonitor.events = events \\\
    cfxPlayer.monitors[callback] = newMonitor\\\
end;\\\
\\\
function cfxPlayer.removeMonitor(callback) \\\
    if (cfxMonitos[callback]) then \\\
        cfxMonitos[callback] = nil \\\
    end\\\
end\\\
\\\
function cfxPlayer.invokeMonitorsForEvent(evType, description, player, data)\\\
    for callback, monitor in pairs(cfxPlayer.monitors) do\\\
        -- should filter if evType is in monitor.events\\\
        if monitor.events and #monitor.events > 0 then \\\
            -- only invoke if this event is listed\\\
            if dcsCommon.arrayContainsString(monitor.events, evType) then \\\
                monitor.callback(evType, description, player, data)\\\
            end\\\
        else \\\
            monitor.callback(evType, description, player, data)\\\
        end\\\
    end\\\
end\\\
\\\
function cfxPlayer.getAllExistingPlayerUnitsRaw()\\\
    local apu = {}\\\
    for i=1, #cfxPlayer.coalitionSides do \\\
        local theSide = cfxPlayer.coalitionSides[i] \\\
        -- get all players for this side\\\
        local thePlayers = coalition.getPlayers(theSide) \\\
        for p=1, #thePlayers do \\\
            local aUnit = thePlayers[p]\\\
            if aUnit and aUnit:isExist() then \\\
                table.insert(apu, aUnit)\\\
            end\\\
        end\\\
    end\\\
    return apu \\\
end\\\
\\\
-- evType that can actually happen are 'new', 'leave' for units,\\\
-- 'newGroup' and 'removeGroup' for groups     \\\
function cfxPlayer.defaultMonitor(evType, description, info, data)\\\
    if cfxPlayer.verbose then\\\
        trigger.action.outText(\\\"+++Plr - evt '\\\".. evType ..\\\"': <\\\" .. description .. \\\">\\\", 30)\\\
        if (info) then \\\
            trigger.action.outText(\\\"+++Plr: for unit named: \\\" .. info.name, 30) \\\
        else \\\
            --trigger.action.outText(\\\"+++Plr: no player data\\\", 30)\\\
        end\\\
        --trigger.action.outText(\\\"+++Plr: desc: '\\\".. evType ..\\\"'<\\\" .. description .. \\\">\\\", 30)\\\
        -- we ignore the data block\\\
    end\\\
end\\\
\\\
function cfxPlayer.start()\\\
    trigger.action.outText(\\\"cf/x player v\\\".. cfxPlayer.version .. \\\": started\\\", 10)\\\
    cfxPlayer.running = true\\\
    cfxPlayer.update()    \\\
end\\\
\\\
function cfxPlayer.stop()\\\
    if cfxPlayer.verbose then \\\
        trigger.action.outText(\\\"cf/x player v\\\".. cfxPlayer.version .. \\\": stopped\\\", 10)\\\
    end\\\
    timer.removeFunction(cfxPlayer.updateSchedule) -- will require another start() to resume\\\
    cfxPlayer.running = false\\\
end\\\
\\\
function cfxPlayer.init()\\\
    trigger.action.outText(\\\"cf/x player v\\\".. cfxPlayer.version .. \\\": loaded\\\", 10)\\\
    -- when verbose, we also add a monitor to display player event\\\
    if cfxPlayer.verbose then \\\
        cfxPlayer.addMonitor(cfxPlayer.defaultMonitor, {})\\\
        trigger.action.outText(\\\"cf/x player isd verbose\\\", 10)\\\
    end\\\
    \\\
    cfxPlayer.start()\\\
end\\\
\\\
-- get everything rolling, but will only start if autostart is true\\\
cfxPlayer.init()\\\
\\\
--TODO: player status: ground, air, dead, none \\\
-- TODO: event when status changes ground/air/...\");a_do_script(\"-- cfxCommander - issue dcs commands to groups etc\\\
--\\\
-- supports scheduling\\\
-- *** EXTENDS ZONES: 'pathing' attribute \\\
--\\\
cfxCommander = {}\\\
cfxCommander.version = \\\"1.1.2\\\"\\\
--[[-- VERSION HISTORY\\\
 - 1.0.5 - createWPListForGroupToPointViaRoads: detect no road found \\\
 - 1.0.6 - build in more group checks in assign wp list \\\
         - added sanity checks for doScheduledTask\\\
         - assignWPListToGroup now can schedule tasks \\\
         - makeGroupGoThere supports scheduling\\\
         - makeGroupGoTherePreferringRoads supports scheduling \\\
         - scheduleTaskForGroup supports immediate execution\\\
         - makeGroupHalt\\\
 - 1.0.7 - warning if road shorter than direct\\\
         - forceOffRoad option\\\
         - noRoadsAtAll option \\\
 - 1.1.0 - load libs \\\
         - pathing zones. Currently only supports \\\
         - offroad to override road-usage\\\
         - pathing zones are overridden by noRoadsAtAll\\\
         - CommanderConfig zones \\\
 - 1.1.1 - default pathing for pathing zone is normal, not offroad \\\
 - 1.1.2 - makeGroupTransmit \\\
         - makeGroupStopTransmitting\\\
         - verbose check before path warning\\\
         - added delay defaulting for most scheduling functions \\\
--]]--\\\
\\\
cfxCommander.requiredLibs = {\\\
    \\\"dcsCommon\\\", -- common is of course needed for everything\\\
    \\\"cfxZones\\\", -- zones management for pathing zones \\\
}\\\
\\\
cfxCommander.verbose = false \\\
cfxCommander.forceOffRoad = true -- if true, vehicles path follow roads, but may drive offroad (they follow vertex points from path but not the road as they are still commanded 'offroad')\\\
cfxCommander.noRoadsAtAll = true  -- if true, always go direct, overrides forceOffRoad when true. Always a two-point path. Here, there, bang! \\\
cfxCommander.pathZones = {} -- zones that can override road settings\\\
\\\
--\\\
-- path zone\\\
--\\\
function cfxCommander.processPathingZone(aZone) -- process attribute and add to zone\\\
    local pathing = cfxZones.getStringFromZoneProperty(aZone, \\\"pathing\\\", \\\"normal\\\") -- must be \\\"offroad\\\" to force offroad\\\
    pathing = pathing:lower()\\\
    -- currently no validation of attribute \\\
    aZone.pathing = pathing\\\
end \\\
\\\
function cfxCommander.addPathingZone(aZone)\\\
    table.insert(cfxCommander.pathZones, aZone)\\\
end \\\
\\\
function cfxCommander.hasPathZoneFor(here, there)\\\
    for idx, aZone in pairs(cfxCommander.pathZones) do \\\
        if cfxZones.pointInZone(here, aZone) then return aZone end \\\
        if cfxZones.pointInZone(there, aZone) then return aZone end\\\
    end\\\
    return nil\\\
end\\\
\\\
--\\\
-- Config Zone Reading if present \\\
--\\\
function cfxCommander.readConfigZone()\\\
    -- note: must match exactly!!!!\\\
    local theZone = cfxZones.getZoneByName(\\\"CommanderConfig\\\") \\\
    if not theZone then \\\
        trigger.action.outText(\\\"+++cmdr: no config zone!\\\", 30) \\\
        return \\\
    end \\\
    \\\
    trigger.action.outText(\\\"+++cmdr: found config zone!\\\", 30) \\\
    \\\
    cfxCommander.verbose = cfxZones.getBoolFromZoneProperty(theZone, \\\"verbose\\\", false)\\\
    cfxCommander.forceOffRoad = cfxZones.getBoolFromZoneProperty(theZone, \\\"forceOffRoad\\\", false) -- if true, vehicles path follow roads, but may drive offroad\\\
    cfxCommander.noRoadsAtAll = cfxZones.getBoolFromZoneProperty(theZone, \\\"noRoadsAtAll\\\", false)\\\
\\\
end\\\
\\\
--\\\
-- Options are key, value pairs. Scheduler when you are creating groups\\\
-- \\\
\\\
function cfxCommander.doOption(data) \\\
    if cfxCommander.verbose then \\\
        trigger.action.outText(\\\"Commander: setting option \\\" .. data.key .. \\\" --> \\\" .. data.value, 30)\\\
    end\\\
\\\
    local theController = data.group:getController()\\\
    theController:setOption(data.key, data.value)\\\
end\\\
\\\
function cfxCommander.scheduleOptionForGroup(group, key, value, delay) \\\
    local data = {}\\\
    if not delay then delay = 0.1 end \\\
    data.group = group\\\
    data.key = key\\\
    data.value = value \\\
    timer.scheduleFunction(cfxCommander.doOption, data, timer.getTime() + delay)\\\
end\\\
\\\
--\\\
-- performCommand is a special version of issuing a command\\\
-- that can be easily schduled by pushing the commandData on \\\
-- the stack with scheduling it \\\
-- group or name must be filled to get the group,\\\
-- and the command table is what is going to be passed to the setCommand\\\
-- commands are given in an array, so you can stack commands \\\
function cfxCommander.performCommands(commandData)\\\
    -- see if we have a group\\\
    if not commandData.group then \\\
        commandData.group = Group.getByName(commandData.name) -- better be inited!\\\
    end\\\
    -- get the AI\\\
    local theController = commandData.group:getController()\\\
    for i=1, #commandData.commands do\\\
        if cfxCommander.verbose then \\\
            trigger.action.outText(\\\"Commander: performing \\\" .. commandData.commands[i].id, 30)\\\
        end\\\
        theController:setCommand(commandData.commands[i])\\\
    end\\\
    \\\
    return nil -- a timer called us, so we return no desire to be rescheduled\\\
end\\\
\\\
function cfxCommander.scheduleCommands(data, delay)\\\
    if not delay then delay = 1 end \\\
    timer.scheduleFunction(cfxCommander.performCommands, data, timer.getTime() + delay)\\\
end\\\
\\\
function cfxCommander.scheduleSingleCommand(group, command, delay) \\\
    if not delay then delay = 1 end \\\
    local data = createCommandDataTableFor(group)\\\
    cfxCommander.addCommand(data, command)\\\
    cfxCommander.scheduleCommands(data, delay)\\\
end\\\
\\\
\\\
function cfxCommander.createCommandDataTableFor(group, name)\\\
    local cD = {}\\\
    if not group then \\\
        cD.name = name\\\
    else\\\
        cD.group = group\\\
    end\\\
    cD.commands={}\\\
    return cD\\\
end\\\
\\\
function cfxCommander.addCommand(theCD, theCommand)\\\
    if not theCD then return end \\\
    if not theCommand then return end \\\
    \\\
    table.insert(theCD.commands, theCommand)\\\
end\\\
\\\
function cfxCommander.createSetFrequencyCommand(freq, modulator)\\\
    local theCmd = {}\\\
    if not freq then freq = 100 end \\\
    if not modulator then modulator = 0 end -- AM = 0, default\\\
    theCmd.id = 'SetFrequency'\\\
    theCmd.params = {}\\\
    theCmd.params.frequency = freq * 10000 -- 88 --> 880000. 124 --> 1.24 MHz\\\
    theCmd.params.modulation = modulator\\\
    return theCmd\\\
end\\\
\\\
-- oneShot is optional. if present and anything but false, will cause message to \\\
-- me sent only once, no loops\\\
function cfxCommander.createTransmissionCommand(filename, oneShot)\\\
    local looping = true\\\
    if not filename then filename = \\\"dummy\\\" end \\\
    if oneShot then looping = false end\\\
    local theCmd = {}\\\
    theCmd.id = 'TransmitMessage'\\\
    theCmd.params = {}\\\
    theCmd.params.loop = looping\\\
    theCmd.params.file = \\\"l10n/DEFAULT/\\\" .. filename -- need to prepend the resource string\\\
    return theCmd\\\
end\\\
\\\
function cfxCommander.createStopTransmissionCommand()\\\
    local theCmd = {}\\\
    theCmd.id = 'stopTransmission'\\\
    theCmd.params = {}\\\
    return theCmd\\\
end\\\
\\\
--\\\
-- tasks\\\
-- \\\
\\\
function cfxCommander.doScheduledTask(data) \\\
    if cfxCommander.verbose then \\\
        trigger.action.outText(\\\"Commander: setting task \\\" .. data.task.id .. \\\" for group \\\" .. data.group:getName(), 30)\\\
    end\\\
    local theGroup = data.group \\\
    if not theGroup then return end \\\
    if not theGroup.isExist then return end\\\
    \\\
    local theController = theGroup:getController()\\\
    theController:pushTask(data.task)\\\
end\\\
\\\
function cfxCommander.scheduleTaskForGroup(group, task, delay)\\\
    if not delay then delay = 0 end \\\
    local data = {}\\\
    data.group = group\\\
    data.task = task\\\
    if delay < 0.001 then \\\
        cfxCommander.doScheduledTask(data) -- immediate execution\\\
        return \\\
    end\\\
    timer.scheduleFunction(cfxCommander.doScheduledTask, data, timer.getTime() + delay)\\\
end\\\
\\\
function cfxCommander.createAttackGroupCommand(theGroupToAttack)\\\
    local task = {}\\\
    task.id = 'AttackGroup'\\\
    task.params = {}\\\
    task.params.groupID = theGroupToAttack:getID()\\\
    return task\\\
end\\\
\\\
function cfxCommander.createEngageGroupCommand(theGroupToAttack)\\\
    local task = {}\\\
    task.id = 'EngageGroup'\\\
    task.params = {}\\\
    task.params.groupID = theGroupToAttack:getID()\\\
    return task\\\
end\\\
\\\
--\\\
-- waypoints, routes etc \\\
--\\\
\\\
-- basic waypoint is for ground units. point can be xyz or xy \\\
function cfxCommander.createBasicWaypoint(point, speed, formation)\\\
    local wp = {}\\\
    wp.x = point.x\\\
    -- support xyz and xy format\\\
    if point.z then \\\
        wp.y = point.z\\\
    else\\\
        wp.y = point.y\\\
    end\\\
    \\\
    if not speed then speed = 6 end -- 6 m/s = 20 kph\\\
    wp.speed = speed \\\
    \\\
    if cfxCommander.forceOffRoad then \\\
        formation = \\\"Off Road\\\"\\\
    end\\\
    \\\
    if not formation then formation = \\\"Off Road\\\" end\\\
    -- legal formations:\\\
    -- Off road\\\
    -- On Road -- second letter upper case?\\\
    -- Cone \\\
    -- Rank\\\
    -- Diamond\\\
    -- Vee\\\
    -- EchelonR\\\
    -- EchelonL\\\
    wp.action = formation -- silly name, but that's how ME does it\\\
    wp.type = 'Turning Point'\\\
    return wp\\\
\\\
end\\\
\\\
function cfxCommander.buildTaskFromWPList(wpList)\\\
    -- build the task that will make a group follow the WP list\\\
    -- we do this by creating a \\\"Mission\\\" task around the WP List\\\
    -- WP list is consumed by this action\\\
    local missionTask = {}\\\
    missionTask.id = \\\"Mission\\\"\\\
    missionTask.params = {}\\\
    missionTask.params.route = {}\\\
    missionTask.params.route.points=wpList\\\
    return missionTask\\\
end\\\
\\\
function cfxCommander.assignWPListToGroup(group, wpList, delay)\\\
    if not delay then delay = 0 end \\\
    if not group then return end \\\
    if type(group) == 'string' then -- group name, nice mist trick \\\
        group = Group.getByName(group)\\\
    end\\\
    if not group then return end \\\
    if not group:isExist() then return end \\\
    \\\
    local theTask = cfxCommander.buildTaskFromWPList(wpList)\\\
    local ctrl = group:getController()\\\
\\\
--[[--\\\
    if delay < 0.001 then -- immediate action\\\
        if ctrl then\\\
            ctrl:setTask(theTask)\\\
        end\\\
    else \\\
        -- delay execution of this command by the specified amount \\\
        -- of seconds \\\
        cfxCommander.scheduleTaskForGroup(group, theTask, delay)\\\
    end\\\
--]]--\\\
    cfxCommander.scheduleTaskForGroup(group, theTask, delay)\\\
end\\\
\\\
function cfxCommander.createWPListForGroupToPoint(group, point, speed, formation)\\\
    if type(group) == 'string' then -- group name\\\
        group = Group.getByName(group)\\\
    end\\\
\\\
    local wpList = {}\\\
    -- here we are, and we want to go there. In DCS, this means that\\\
    -- we need to create a wp list consisting of here and there\\\
    local here = dcsCommon.getGroupLocation(group)\\\
    local wpHere = cfxCommander.createBasicWaypoint(here, speed, formation)\\\
    local wpThere = cfxCommander.createBasicWaypoint(point, speed, formation)\\\
    wpList[1] = wpHere\\\
    wpList[2] = wpThere\\\
    return wpList\\\
end\\\
\\\
-- make a ground units group head to a waypoint by replacing the entire mission\\\
-- with a two-waypoint lsit from (here) to there at speed and formation. formation\\\
-- default is 'off road'\\\
function cfxCommander.makeGroupGoThere(group, there, speed, formation, delay)\\\
    if not delay then delay = 0 end \\\
    if type(group) == 'string' then -- group name\\\
        group = Group.getByName(group)\\\
    end\\\
    local wp = cfxCommander.createWPListForGroupToPoint(group, there, speed, formation)\\\
    \\\
    cfxCommander.assignWPListToGroup(group, wp, delay)\\\
end\\\
\\\
function cfxCommander.calculatePathLength(roadPoints)\\\
    local totalLen = 0\\\
    if #roadPoints < 2 then return 0 end\\\
    for i=1, #roadPoints-1 do\\\
        totalLen = totalLen + dcsCommon.dist(roadPoints[i], roadPoints[i+1])\\\
    end\\\
    return totalLen\\\
end\\\
\\\
-- make ground units go from here (group location) to there, using roads if possible\\\
function cfxCommander.createWPListForGroupToPointViaRoads(group, point, speed)\\\
    if type(group) == 'string' then -- group name\\\
        group = Group.getByName(group)\\\
    end\\\
\\\
    local wpList = {}\\\
    -- here we are, and we want to go there. In DCS, this means that\\\
    -- we need to create a wp list consisting of here and there\\\
    -- when going via roads, we add to more wayoints:\\\
    -- go on-roads and leaveRoads. \\\
    -- only if we can get these two additional points, we do that, else we \\\
    -- fall back to direct route \\\
    \\\
    local here = dcsCommon.getGroupLocation(group)\\\
\\\
    -- now generate a list of all points from here to there that uses roads\\\
    local rawRoadPoints = land.findPathOnRoads('roads', here.x, here.z, point.x, point.z)\\\
    -- this is the entire path. calculate the length and make \\\
    -- sure that path on-road isn't more than twice as long \\\
    -- that can happen if a bridge is out or we need to go around a hill\\\
    if not rawRoadPoints or #rawRoadPoints<3 then \\\
        trigger.action.outText(\\\"+++ no roads leading there. Taking direct approach\\\", 30)\\\
        return cfxCommander.createWPListForGroupToPoint(group, point, speed)\\\
    end\\\
    \\\
    local pathLength = cfxCommander.calculatePathLength(rawRoadPoints)\\\
    local direct = dcsCommon.dist(here, point)\\\
    if pathLength < direct and cfxCommander.verbose then \\\
        trigger.action.outText(\\\"+++dcsC: WARNING road path (\\\" .. pathLength .. \\\") shorter than direct route(\\\" .. direct .. \\\"), will not path correctly\\\", 30)\\\
    end\\\
    \\\
    if pathLength > (2 * direct) then \\\
        -- road takes too long, take direct approach\\\
        --trigger.action.outText(\\\"+++ road path (\\\" .. pathLength .. \\\") > twice direct route(\\\" .. direct .. \\\"), commencing direct off-road\\\", 30)\\\
        return cfxCommander.createWPListForGroupToPoint(group, point, speed)\\\
    end\\\
    \\\
    --trigger.action.outText(\\\"+++ \\\".. group:getName() .. \\\": choosing road path l=\\\" .. pathLength .. \\\" over direct route d=\\\" .. direct, 30)\\\
    \\\
    -- if we are here, the road trip is valid \\\
    for idx, wp in pairs(rawRoadPoints) do \\\
        -- createBasic... supports w.xy format\\\
        local theNewWP = cfxCommander.createBasicWaypoint(wp, speed, \\\"On Road\\\") -- force off road for better compatibility?\\\
        table.insert(wpList, theNewWP)\\\
    end\\\
    \\\
    \\\
    \\\
    -- now make first and last entry OFF Road\\\
    local wpc = wpList[1]\\\
    wpc.action = \\\"Off Road\\\"\\\
    wpc = wpList[#wpList]\\\
    wpc.action = \\\"Off Road\\\"\\\
\\\
    return wpList\\\
end\\\
\\\
function cfxCommander.makeGroupGoTherePreferringRoads(group, there, speed, delay)\\\
    if type(group) == 'string' then -- group name\\\
        group = Group.getByName(group)\\\
    end\\\
    if not delay then delay = 0 end \\\
\\\
\\\
    if cfxCommander.noRoadsAtAll then \\\
        -- we don't even follow roads, completely forced off\\\
        cfxCommander.makeGroupGoThere(group, there, speed, \\\"Off Road\\\", delay)\\\
        return \\\
    end\\\
\\\
    -- see if we have an override situation \\\
    -- for one of the two points where a pathing Zone \\\
    -- overrides the roads setting \\\
    if #cfxCommander.pathZones > 0 then  \\\
        local here = dcsCommon.getGroupLocation(group)\\\
        local oRide = cfxCommander.hasPathZoneFor(here, there)\\\
        if oRide and oRide.pathing == \\\"offroad\\\" then \\\
            -- yup, override road preference\\\
            cfxCommander.makeGroupGoThere(group, there, speed, \\\"Off Road\\\", delay)\\\
            --trigger.action.outText(\\\"pathing: override offroad\\\")\\\
            return \\\
        end\\\
    end\\\
\\\
    -- viaRoads will only use roads if the road trip isn't more than twice \\\
    -- as long as the direct route \\\
    local wp = cfxCommander.createWPListForGroupToPointViaRoads(group, there, speed)\\\
    cfxCommander.assignWPListToGroup(group, wp, delay)\\\
end\\\
\\\
\\\
function cfxCommander.makeGroupHalt(group, delay)\\\
    if not group then return end \\\
    if not group:isExist() then return end \\\
    if not delay then delay = 0 end \\\
    local theTask = {id = 'Hold', params = {}}\\\
    cfxCommander.scheduleTaskForGroup(group, theTask, delay)\\\
end\\\
\\\
function cfxCommander.makeGroupTransmit(group, tenKHz, filename, oneShot, delay)\\\
    if not group then return end \\\
    if not tenKHz then tenKHz = 20 end -- default to 200KHz\\\
    if not delay then delay = 1.0 end \\\
    if not filename then return end \\\
    if not oneShot then oneShot = false end \\\
    \\\
    -- now build the transmission command\\\
    local theCommands = cfxCommander.createCommandDataTableFor(group)\\\
    local cmd = cfxCommander.createSetFrequencyCommand(tenKHz) -- freq in 10000 Hz\\\
    cfxCommander.addCommand(theCommands, cmd)\\\
    cmd = cfxCommander.createTransmissionCommand(filename, oneShot)\\\
    cfxCommander.addCommand(theCommands, cmd)\\\
    cfxCommander.scheduleCommands(theCommands, delay)\\\
end \\\
\\\
function cfxCommander.makeGroupStopTransmitting(group, delay)\\\
    if not delay then delay = 1 end \\\
    if not group then return end \\\
    local theCommands = cfxCommander.createCommandDataTableFor(group)\\\
    local cmd = cfxCommander.createStopTransmissionCommand()\\\
    cfxCommander.addCommand(theCommands, cmd)\\\
    cfxCommander.scheduleCommands(theCommands, delay)\\\
end\\\
\\\
\\\
function cfxCommander.start()\\\
    -- make sure we have loaded all relevant libraries \\\
    if not dcsCommon.libCheck(\\\"cfx Commander\\\", cfxCommander.requiredLibs) then \\\
        trigger.action.outText(\\\"cf/x Commander aborted: missing libraries\\\", 30)\\\
        return false \\\
    end\\\
    \\\
    -- identify and process all 'pathing' zones\\\
    local pathZones = cfxZones.getZonesWithAttributeNamed(\\\"pathing\\\")\\\
    \\\
    -- now create a spawner for all, add them to the spawner updater, and spawn for all zones that are not\\\
    -- paused \\\
    for k, aZone in pairs(pathZones) do \\\
        cfxCommander.processPathingZone(aZone) -- process attribute and add to zone\\\
        cfxCommander.addPathingZone(aZone) -- remember it so we can smoke it\\\
    end\\\
    \\\
    -- read config overides \\\
    cfxCommander.readConfigZone()\\\
    \\\
    return true\\\
end\\\
\\\
if cfxCommander.start() then \\\
    trigger.action.outText(\\\"cfxCommander v\\\" .. cfxCommander.version .. \\\" loaded\\\", 30)\\\
else \\\
    trigger.action.outText(\\\"+++cfxCommander load FAILED\\\", 30)\\\
    cfxCommander = nil\\\
end\\\
\\\
--[[-- known issues\\\
\\\
- troops remain motionless until all are repaired or produced after cature\\\
- long roads / roads not taken in persia \\\
- all troops red and blue become motionless when one zone is occupied\\\
- after capture, the troop capturing remains, all others can go on. one will always remain there \\\
- rethink the factor to add to road, and simply add 100m \\\
\\\
 TODO: break long distances into smaller paths, and gravitate towards pathing zones if they have a 'gravitate' or similar attribute \\\
--]]--\\\
\");a_do_script(\"cfxGroundTroops = {}\\\
cfxGroundTroops.version = \\\"1.7.3\\\"\\\
cfxGroundTroops.ups = 1\\\
cfxGroundTroops.requiredLibs = {\\\
    \\\"dcsCommon\\\", -- common is of course needed for everything\\\
                 -- pretty stupid to check for this since we \\\
                 -- need common to invoke the check, but anyway\\\
    \\\"cfxCommander\\\", -- generic data module for weight \\\
    -- cfxOwnedZones is optional \\\
}\\\
-- ground troops: a module to manage ground toops. makes groups of ground troops\\\
-- patrol and engage enemies and signal idle\\\
-- understands cfxOwnedZones orders 'attackOwnedZone' and will re-direct\\\
-- troops when a zone was captured by interacting with cfxOwnedZones to \\\
-- find the nearest non-owned zone and direct the group there \\\
\\\
-- USAGE\\\
-- Allocate a group in game and issue them marching orders towars a goal \\\
-- then createGroundTroops to allocate a structure used by this \\\
-- module and addTroopsToPool to have them then managed by this \\\
-- module \\\
\\\
cfxGroundTroops.deployedTroops = {}\\\
\\\
-- version history\\\
--   1.3.0 - added \\\"wait-\\\" prefix to have toops do nothing \\\
--         - added lazing \\\
--   1.3.1 - sound for lazing msg is \\\"UI_SCI-FI_Tone_Bright_Dry_20_stereo.wav\\\"\\\
--         - lazing --> lasing in text \\\
--   1.3.2 - set ups to 2 \\\
--   1.4.0 - queued updates except for lazers \\\
--   1.4.1 - makeTroopsEngageZone now issues hold before moving on 5 seconds later\\\
--         - getTroopReport\\\
--           - include size of group \\\
--   1.4.2 - uses unitIsInfantry from dcsCommon \\\
--   1.5.0 - new scheduled updates per troop to reduce processor load \\\
--         - tiebreak code \\\
--   1.5.1 - small bugfix in scheduled code \\\
--   1.5.2 - checkSchedule \\\
--         - speed warning in scheduler\\\
--         - go off road when speed warning too much \\\
--   1.5.3 - monitor troops \\\
--         - managed queue for ground troops \\\
--         - on second switch to offroad now removed from MQ\\\
--   1.5.4 - removed debugging messages\\\
--   1.5.5 - removed bug in troop report reading nil destination \\\
--   1.6.0 - check modules \\\
--   1.6.1 - troopsCallback management so you can be informed if a \\\
--           troop you have added to the pool is dead or has achieved a goal.\\\
--           callback will list reasons \\\"dead\\\" and \\\"arrived\\\"\\\
--           updateAttackers\\\
--   1.6.2 - also accept 'lase' as 'laze', translate directly \\\
--   1.7.0 - now can use groundTroopsConfig zone\\\
--   1.7.1 - addTroopsDeadCallback() renamed to addTroopsCallback() \\\
--         - invokeCallbacksFor also accepts and passes on data block\\\
--         - troops is always passed in data block as .troops \\\
--   1.7.2 - callback when group is neutralized on guard orders\\\
--         - callback when group is being engaged under guard orders \\\
--   1.7.3 - callbacks for lase:tracking and lase:stop \\\
\\\
\\\
\\\
\\\
-- an entry into the deployed troop has the following attributes\\\
--  - group - the group \\\
--  - orders: \\\"guard\\\" - will guard the spot and look for enemies in range\\\
--            \\\"patrol\\\" - will walk between way points back and forth \\\
--            \\\"laze\\\" - will stay in place and try to laze visible vehicles in range\\\
--              \\\"attackOwnedZone\\\" - interface to cfxOwnedZones module, seeks out\\\
--              enemy zones to attack and capture them\\\
--            \\\"wait-<some other orders>\\\" do nothing. the \\\"wait\\\" prefix will be removed some time and <some other order> then revealed. Used at least by heloTroops\\\
--            \\\"train\\\" - target dummies. ROE=HOLD, no ground loop \\\
--            \\\"attack\\\" - transition to destination, once there, stop and \\\
--            switch to guard. requires destination zone be sez to a valid cfxZone\\\
--  - coalition - the coalition from the group\\\
--  - enemy - if set, the group this group it is engaging. this means the group is fighting and not idle\\\
--  - name - name of group, dan be freely changed\\\
--  - signature - \\\"cfx\\\" to tell apart from dcs groups \\\
--  - range = range to look for enemies. default is 300m. In \\\"laze\\\" orders, range to laze\\\
--  - lazeTarget - target currently lazing\\\
--  - lazeCode - laser code. default is 1688\\\
\\\
-- \\\
-- usage:\\\
-- take a dcs group of ground troops and create a cfx ground troop record with \\\
--   createGroundTroops()\\\
-- then add this to the manager with \\\
--   addGroundTroopsToPool()\\\
-- \\\
-- you can control what the group is to do by changing the cfx troop attribute orders \\\
-- you can install a callback that will notify you if a troop reached a goal or\\\
-- was killed with addTroopsCallback() which will also give a reason\\\
-- callback pattern is myCallback(reason, theGroup, orders, data) with troop being the \\\
-- group, and orders the original orders, and reason a string containing why the \\\
-- callback was invoked. Currently defined reasons are\\\
--   - \\\"dead\\\" - entire group was killed \\\
--   - \\\"arrived\\\" - at least a part of group arrived at destination (only with some orders)\\\
--\\\
\\\
--\\\
-- UPDATE MODELS\\\
-- standard is update all every time: fastest, but may cause \\\
-- performance issues\\\
-- queued will work one every pass (except for lazed), distributing the load much better \\\
-- schedueld installs a callback for each group separately and thus distributes the load over time much better \\\
\\\
cfxGroundTroops.queuedUpdates = false -- set to true to process one group per turn. To work this way, scheduledUpdates must be false \\\
cfxGroundTroops.scheduledUpdates = true -- set to false to allow queing of standard updates. overrides queuedUpdates \\\
cfxGroundTroops.monitorNumbers = false -- set to true to debug managed group size \\\
\\\
cfxGroundTroops.standardScheduleInterval = 30 -- 30 seconds between calls\\\
cfxGroundTroops.guardUpdateInterval = 30 -- every 30 seconds we check up on guards\\\
cfxGroundTroops.trackingUpdateInterval = 0.5 -- 0.5 seconds for lazer tracking etc \\\
\\\
cfxGroundTroops.maxManagedTroops = 67 -- -1 is infinite, any positive number turn on cap on managed troops and palces excess troops in queue \\\
cfxGroundTroops.troopQueue = {} -- FIFO stack \\\
-- return the best tracking interval for this type of orders \\\
\\\
--\\\
-- READ CONFIG ZONE TO OVERRIDE SETTING\\\
--\\\
function cfxGroundTroops.readConfigZone()\\\
    -- note: must match exactly!!!!\\\
    local theZone = cfxZones.getZoneByName(\\\"groundTroopsConfig\\\") \\\
    if not theZone then \\\
        trigger.action.outText(\\\"***gndT: NO config zone!\\\", 30) \\\
        return \\\
    end \\\
    \\\
    trigger.action.outText(\\\"+++gndT: found config zone!\\\", 30) \\\
    \\\
    -- ok, for each property, load it if it exists\\\
    if cfxZones.hasProperty(theZone, \\\"queuedUpdates\\\")  then \\\
        cfxGroundTroops.queuedUpdates = cfxZones.getBoolFromZoneProperty(theZone, \\\"queuedUpdates\\\", false)\\\
    end\\\
    \\\
    if cfxZones.hasProperty(theZone, \\\"scheduledUpdates\\\")  then \\\
        cfxGroundTroops.scheduledUpdates = cfxZones.getBoolFromZoneProperty(theZone, \\\"scheduledUpdates\\\", false)\\\
    end\\\
    \\\
    if cfxZones.hasProperty(theZone, \\\"maxManagedTroops\\\")  then \\\
        cfxGroundTroops.maxManagedTroops = cfxZones.getNumberFromZoneProperty(theZone, \\\"maxManagedTroops\\\", 65)\\\
    end\\\
    \\\
    if cfxZones.hasProperty(theZone, \\\"monitorNumbers\\\")  then \\\
        cfxGroundTroops.monitorNumbers = cfxZones.getBoolFromZoneProperty(theZone, \\\"monitorNumbers\\\", false)\\\
    end\\\
    \\\
    if cfxZones.hasProperty(theZone, \\\"standardScheduleInterval\\\")  then \\\
        cfxGroundTroops.standardScheduleInterval = cfxZones.getNumberFromZoneProperty(theZone, \\\"standardScheduleInterval\\\", 30)\\\
    end\\\
    \\\
    if cfxZones.hasProperty(theZone, \\\"guardUpdateInterval\\\")  then \\\
        cfxGroundTroops.guardUpdateInterval = cfxZones.getNumberFromZoneProperty(theZone, \\\"guardUpdateInterval\\\", 30)\\\
    end\\\
    \\\
    if cfxZones.hasProperty(theZone, \\\"trackingUpdateInterval\\\")  then \\\
        cfxGroundTroops.trackingUpdateInterval = cfxZones.getNumberFromZoneProperty(theZone, \\\"trackingUpdateInterval\\\", 0.5)\\\
    end\\\
    \\\
    \\\
end\\\
\\\
\\\
-- \\\
-- Callback handling\\\
--\\\
\\\
cfxGroundTroops.troopsCallback = {}\\\
\\\
function cfxGroundTroops.addTroopsCallback(theCallback)\\\
    table.insert(cfxGroundTroops.troopsCallback, theCallback)\\\
end\\\
\\\
function cfxGroundTroops.invokeCallbacksFor(reason, troops, data)\\\
    if not data then data = {} end\\\
    data.troops = troops \\\
    for idx, theCB in pairs (cfxGroundTroops.troopsCallback) do \\\
        theCB(reason, troops.group, troops.orders, data)\\\
    end\\\
end\\\
\\\
function cfxGroundTroops.getScheduleInterval(orders)\\\
    if orders == \\\"laze\\\" then \\\
        return cfxGroundTroops.trackingUpdateInterval\\\
    end\\\
    return cfxGroundTroops.standardScheduleInterval\\\
end\\\
\\\
-- create controller commands to attack a group \\\"enemies\\\"\\\
-- enemies are an attribute of the troop structure\\\
function cfxGroundTroops.makeTroopsEngageEnemies(troop)\\\
    local group = troop.group\\\
    local enemies = troop.enemy\\\
    local from = dcsCommon.getGroupLocation(group)\\\
    if not from then return end -- the commandos died\\\
    local there = dcsCommon.getGroupLocation(enemies)\\\
    if not there then return end\\\
    \\\
    -- we lerp to 2/3 of enemy location\\\
    there = dcsCommon.vLerp(from, there, 0.66) \\\
    \\\
    local speed = 10 -- m/s = 10 km/h\\\
    cfxCommander.makeGroupGoThere(group, there, speed)\\\
    local attask = cfxCommander.createAttackGroupCommand(enemies)\\\
    cfxCommander.scheduleTaskForGroup(group, attask, 0.5)\\\
end\\\
\\\
-- make the troops engage a cfxZone passed in the destination \\\
-- attribute \\\
function cfxGroundTroops.makeTroopsEngageZone(troop)\\\
    local group = troop.group\\\
    local enemyZone = troop.destination -- must be cfxZone \\\
    local from = dcsCommon.getGroupLocation(group)\\\
    if not from then return end -- the group died\\\
    local there = enemyZone.point -- access zone position\\\
    if not there then return end\\\
    \\\
    -- we lerp to 102% of enemy location to force overshoot and engagement\\\
    --there = dcsCommon.vLerp(from, there, 1.02) \\\
    \\\
    local speed = 14 -- m/s; 10 m/s = 36 km/h\\\
    -- we prefer going over roads since we don't know \\\
    -- what is there \\\
    \\\
    -- make troops stop in 1 second, then start in 5 seconds to give AI respite \\\
    cfxCommander.makeGroupHalt(group, 1) -- 1 second delay\\\
    cfxCommander.makeGroupGoTherePreferringRoads(group, there, speed, 5)\\\
    -- no attack command since we don't know what is there\\\
    -- but mayhaps we should issue weapons free?\\\
    -- we'll soon test that by sticking in a troop on the way \\\
    \\\
--    local attask = cfxCommander.createAttackGroupCommand(enemies)\\\
--    cfxCommander.scheduleTaskForGroup(group, attask, 0.5)\\\
end\\\
\\\
function cfxGroundTroops.switchToOffroad(troops)\\\
    -- we may need to test if we already did this, \\\
    -- but not for now \\\
    \\\
    -- this is called when troops are stuck \\\
    -- on their route for longer than allowed\\\
    -- we now force a direct approach \\\
    local group = troops.group\\\
    local enemies = troops.destination\\\
    local from = dcsCommon.getGroupLocation(group)\\\
    if not from then return end -- the commandos died\\\
    local there = enemies.point\\\
    if not there then return end\\\
        \\\
    local speed = 14 -- m/s; 10 m/s = 36 km/h\\\
    \\\
    cfxCommander.makeGroupHalt(group, 0) -- no delay, halt now\\\
    cfxCommander.makeGroupGoThere(group, there, speed, \\\"Off Road\\\", 5)\\\
    \\\
    troops.lastOrderDate = timer.getTime()\\\
    troops.speedWarning = 0\\\
end\\\
\\\
--\\\
-- update loop for troops that have 'attackOwnedZones' as \\\
-- their orders\\\
-- if they have no destination zone, or the zone they are \\\
-- are heading for is already owned by their side, then look for \\\
-- the closest enemy zone, and cut attack orders to move there \\\
function cfxGroundTroops.getClosestEnemyZone(troop)\\\
    local p = dcsCommon.getGroupLocation(troop.group)\\\
    local tempZone = cfxZones.createSimpleZone(\\\"tz\\\", p, 100)\\\
    tempZone.owner = troop.side\\\
    local newTarget = cfxOwnedZones.getNearestEnemyOwnedZone(tempZone, true) -- 'true' will also target neutral zones \\\
    return newTarget\\\
end\\\
\\\
function cfxGroundTroops.updateZoneAttackers(troop)\\\
    if not troop then return end \\\
    troop.insideDestination = false -- mark as not inside \\\
    \\\
    local newTargetZone = cfxGroundTroops.getClosestEnemyZone(troop)\\\
    if not newTargetZone then\\\
        -- all target zones are friendly, go to guard mode\\\
--        trigger.action.outTextForCoalition(troop.side, troop.name .. \\\" holding position\\\", 30)\\\
        troop.orders = \\\"guard\\\"\\\
        return \\\
    end\\\
    \\\
    if newTargetZone ~= troop.destination then \\\
--        trigger.action.outTextForCoalition(troop.side, troop.name .. \\\" enroute to \\\" .. newTargetZone.name, 30)\\\
        troop.destination = newTargetZone \\\
        cfxGroundTroops.makeTroopsEngageZone(troop)\\\
        troop.lastOrderDate = timer.getTime()\\\
        troop.speedWarning = 0\\\
        return\\\
    end\\\
    \\\
    -- if we get here, we are under way to troop.destination\\\
    -- check if we are inside the zone, and if so, set variable to true \\\
    local p = dcsCommon.getGroupLocation(troop.group)\\\
    troop.insideDestination = cfxZones.isPointInsideZone(p, troop.destination)\\\
    \\\
--    if we get here, we need no change \\\
\\\
    \\\
end\\\
\\\
-- attackers simply travel to their destination, and then switch to \\\
-- guard orders once they arrive \\\
function cfxGroundTroops.updateAttackers(troop) \\\
    if not troop then return end \\\
    if not troop.destination then return end \\\
    \\\
    if cfxZones.isGroupPartiallyInZone(troop.group, troop.destination) then\\\
        -- we have arrived\\\
        -- we could now also initiate a general callback with reason\\\
        cfxGroundTroops.invokeCallbacksFor(\\\"arrived\\\", troop)\\\
        troop.orders = \\\"guard\\\"\\\
        return \\\
    end\\\
    \\\
    \\\
--    if we get here, we need no change \\\
end\\\
\\\
-- update loop for a group that has \\\"guard\\\" orders.\\\
-- basically it stands around and looks for enemies \\\
-- until it finds a group, and then engages the enemy\\\
-- when engaged, it is not looking for other enemies\\\
-- 'engaged' means that the troop.enemy attribute is set\\\
 \\\
function cfxGroundTroops.updateGuards(troop)\\\
    local theEnemy = troop.enemy\\\
    if theEnemy then \\\
        -- see if enemy is dead \\\
        if not dcsCommon.isGroupAlive(theEnemy) then \\\
            troop.enemy = nil\\\
            -- yup, zed's dead. next time around, we won't be checking this again\\\
            trigger.action.outText(troop.name .. \\\" has neutralized enemy forces\\\", 30)\\\
            --DONE: invoke callback for defeating troops\\\
            local data = {}\\\
            data.enemy = theEnemy\\\
            cfxGroundTroops.invokeCallbacksFor(\\\"neutralized\\\", troop, data)\\\
            return\\\
        end\\\
        -- yes, we are still engaged\\\
        return \\\
    end\\\
    \\\
    -- we are currently unengaged. look for an enemy\\\
    if not troop.range then troop.range = 300 end\\\
    troop.coalition = troop.group:getCoalition()\\\
    local enemyCoal = dcsCommon.getEnemyCoalitionFor(troop.coalition)\\\
    local cat = Group.Category.GROUND\\\
    local p = dcsCommon.getGroupLocation(troop.group)\\\
    local enemies, enemyDist = dcsCommon.getClosestLivingGroupToPoint(p, enemyCoal, cat) \\\
    local maxRange = troop.range -- meters \\\
    -- if we have enemies then schedule a path to go there\\\
    if enemies and (enemyDist < maxRange) then \\\
        troop.enemy = enemies\\\
        --timer.scheduleFunction(cfxGroundTroops.makeGroupEngageEnemies, troop, timer.getTime() + 1.0)\\\
        cfxGroundTroops.makeTroopsEngageEnemies(troop)\\\
        trigger.action.outText(troop.name .. \\\" is engaging enemy forces at range \\\" .. math.floor(enemyDist) .. \\\"meters\\\", 30)\\\
        --DONE: invoke callback for engaging troops, pass data \\\
        local data = {}\\\
        data.enemy = enemies\\\
        cfxGroundTroops.invokeCallbacksFor(\\\"engaging\\\", troop, data)\\\
    elseif enemies then \\\
        --trigger.action.outText(troop.name .. \\\" enemiy out of range: \\\" .. math.floor(enemyDist) .. \\\"meters\\\", 30)\\\
    else \\\
        --trigger.action.outText(troop.name .. \\\" no enemies\\\", 30)\\\
    end\\\
end\\\
\\\
--\\\
-- update loop for units that laze targets.\\\
-- they can only laze if they are alive, but update \\\
-- will take care of that, so when we are here, there \\\
-- is at least one of them alive\\\
-- \\\
\\\
function cfxGroundTroops.findLazeTarget(troop)\\\
    local here = troop.group:getUnit(1):getPoint()\\\
    troop.coalition = troop.group:getCoalition()\\\
    local enemyCoal = dcsCommon.getEnemyCoalitionFor(troop.coalition)\\\
    --local enemySide = dcsCommon.getEnemyCoalitionFor(troop.side)\\\
    local cat = Group.Category.GROUND\\\
    local enemyGroups = dcsCommon.getLivingGroupsAndDistInRangeToPoint(here, troop.range, enemyCoal, cat) \\\
    -- we now have a list of possible targets in range\\\
    if #enemyGroups < 1 then     \\\
        -- no targets in range\\\
        return nil \\\
    end\\\
\\\
    here = {x = here.x, y = here.y + 2.0, z = here.z} -- raise by 2.0m\\\
    \\\
    -- iterate through the list until we find the first target \\\
    -- that fits the bill and return it\\\
--    trigger.action.outText(\\\"+++ looking at \\\" .. #enemyGroups .. \\\" laze groups\\\", 30)\\\
    for i=1, #enemyGroups do    \\\
        -- get all units for this group \\\
        local aGroup = enemyGroups[i].group -- remember, they are in a {dist, group} tuple\\\
        local theUnits = aGroup:getUnits()\\\
        -- iterate all units \\\
        for udx, aUnit in pairs(theUnits) do \\\
            if (aUnit:isExist() and aUnit:getLife() > 1) then \\\
                -- unit lives \\\
                -- now, we need to filter infantry. we do this by \\\
                -- pre-fetching the typeString\\\
                --troop.lazeTargetType = aUnit:getTypeName()\\\
                -- and checking if the name contains some infantry-\\\
                -- typical strings. Idea taken from JTAC script \\\
                local isInfantry =  dcsCommon.unitIsInfantry(theUnit)\\\
    \\\
                \\\
                if not isInfantry then \\\
                    -- this is a vehicle, is it in line of sight?\\\
                    -- raise the point 2m above ground for both points\\\
                    -- as done in jtac script\\\
                    local there = aUnit:getPoint()  \\\
                    there = {x = there.x, y = there.y + 2.0, z = there.z}\\\
                   \\\
                    if land.isVisible(here, there) then \\\
                        -- we found a visible vehicle in \\\
                        -- the nearest group to us in range \\\
                        -- that is visible!\\\
                        return aUnit\\\
                    else \\\
                        --trigger.action.outText(\\\"+++ \\\".. aUnit:getName() ..\\\"cant be seen\\\", 30)\\\
                    end -- if visible\\\
                else \\\
                    -- trigger.action.outText(\\\"+++ \\\".. aUnit:getName() ..\\\" (\\\".. troop.lazeTargetType .. \\\") is infantry\\\", 30)\\\
                end -- if not infantry \\\
            end -- if alive \\\
        end -- for all units\\\
    end -- for all enemy groups\\\
    --trigger.action.outText(\\\"+++ find nearest laze target did not find anything to laze\\\", 30)\\\
    return nil -- no unit found \\\
end\\\
\\\
function cfxGroundTroops.lazerOff(troop)\\\
    if troop.lazerPointer then \\\
        troop.lazerPointer:destroy()\\\
    end\\\
    troop.lazerPointer = nil \\\
    troop.lazingUnit = nil \\\
end\\\
\\\
function cfxGroundTroops.trackLazer(troop)\\\
    -- the only thing that must be set when entering here is\\\
    -- lazeTarget. We set up the rest\\\
    if not troop.lazingUnit then \\\
        troop.lazingUnit = troop.group:getUnit(1) -- get first unit\\\
        if troop.lazingUnit:getLife() < 1 then \\\
            trigger.action.outText(\\\"+++ LazingUnit is dead, getUnit works differently from what docs say, need to filter for lively units\\\", 30)\\\
        end\\\
    end\\\
    \\\
    if not troop.lazerPointer then\\\
        local there = troop.lazeTarget:getPoint()\\\
        troop.lazerPointer = Spot.createLaser(troop.lazingUnit,{x = 0, y = 2, z = 0}, there, 1688)\\\
        troop.lazeTargetType = troop.lazeTarget:getTypeName()\\\
        trigger.action.outTextForCoalition(troop.side, troop.name .. \\\" tally target - lasing \\\" .. troop.lazeTargetType .. \\\"!\\\", 30)\\\
         trigger.action.outSoundForCoalition(troop.side, \\\"UI_SCI-FI_Tone_Bright_Dry_20_stereo.wav\\\")\\\
        troop.lastLazerSpot = there -- remember last spot\\\
        local data = {}\\\
        data.enemy = troop.lazeTarget\\\
        data.tracker = troop.lazingUnit\\\
        cfxGroundTroops.invokeCallbacksFor(\\\"lase:tracking\\\", troop, data)\\\
        return\\\
    end\\\
    \\\
    -- if true then return end \\\
    \\\
    -- if we get here, we update the lazerPointer\\\
    local there = troop.lazeTarget:getPoint()\\\
    -- we may only want to update the laser spot when dist > trigger\\\
    troop.lazerPointer:setPoint(there)\\\
    -- we may want to report dist\\\
    troop.lastLazerSpot = there\\\
end\\\
\\\
function cfxGroundTroops.updateLaze(troop)\\\
    -- check if we have a laze target. \\\
    -- check if lazing unit was killed, and therefore lost target\\\
    if troop.lazingUnit then \\\
        -- check that unit still alive\\\
        if troop.lazingUnit:isExist() and \\\
        troop.lazingUnit:getLife() >= 1 then\\\
        else \\\
            cfxGroundTroops.lazerOff(troop)\\\
            troop.lazeTarget = nil\\\
            trigger.action.outTextForCoalition(troop.side, troop.name .. \\\" reports lasing \\\" .. troop.lazeTargetType .. \\\" interrupted. Re-acquiring.\\\", 30)\\\
            trigger.action.outSoundForCoalition(troop.side, \\\"UI_SCI-FI_Tone_Bright_Dry_20_stereo.wav\\\")\\\
            troop.lazingUnit = nil \\\
            cfxGroundTroops.invokeCallbacksFor(\\\"lase:stop\\\", troop)\\\
            return -- we'll re-acquire through a new unit next round\\\
        end\\\
    end\\\
    \\\
    -- if we get here, a lazing unit \\\
    --local here = troop.lazingUnit:getPoint()\\\
    \\\
    if troop.lazeTarget then \\\
        -- check if that target is alive and in range\\\
        if troop.lazeTarget:isExist() and troop.lazeTarget:getLife() >= 1 then\\\
            -- note: when we laze a target, we know that we have a lazing unit\\\
            local here = troop.lazingUnit:getPoint()\\\
            -- check if it has moved out of range \\\
            local there = troop.lazeTarget:getPoint()\\\
            if dcsCommon.dist(here, there) > troop.range then \\\
                -- troop out of range\\\
                trigger.action.outTextForCoalition(troop.side, troop.name .. \\\" lost sight of lazed target \\\" .. troop.lazeTargetType, 30)\\\
                trigger.action.outSoundForCoalition(troop.side, \\\"UI_SCI-FI_Tone_Bright_Dry_20_stereo.wav\\\")\\\
                troop.lazeTarget = nil\\\
                cfxGroundTroops.lazerOff(troop)\\\
                troop.lazingUnit = nil\\\
                cfxGroundTroops.invokeCallbacksFor(\\\"lase:stop\\\", troop)\\\
                return \\\
            end\\\
            \\\
            -- if we get here, we need to update the target point \\\
            cfxGroundTroops.trackLazer(troop)\\\
            return\\\
        else\\\
            -- target died\\\
            trigger.action.outTextForCoalition(troop.side, troop.name .. \\\" confirms kill for \\\" .. troop.lazeTargetType, 30)\\\
            trigger.action.outSoundForCoalition(troop.side, \\\"UI_SCI-FI_Tone_Bright_Dry_20_stereo.wav\\\")\\\
            troop.lazeTarget = nil\\\
            cfxGroundTroops.lazerOff(troop)\\\
            troop.lazingUnit = nil\\\
            cfxGroundTroops.invokeCallbacksFor(\\\"lase:stop\\\", troop)\\\
            return\\\
        end        \\\
    end\\\
    \\\
    -- if we get here, we must look for a laze target \\\
    troop.lazeTarget = cfxGroundTroops.findLazeTarget(troop)\\\
    if troop.lazeTarget then \\\
        cfxGroundTroops.trackLazer(troop) -- will also set up lazing unit \\\
    end\\\
end\\\
\\\
\\\
function cfxGroundTroops.updateWait(troop)\\\
    -- currently nothing to do\\\
    \\\
end\\\
\\\
function cfxGroundTroops.updateTroops(troop)\\\
    -- if orders start with \\\"wait-\\\" then the troops \\\
    -- simply do nothing\\\
    if dcsCommon.stringStartsWith(troop.orders, \\\"wait-\\\") then\\\
        -- the troops are waiting to be picked update\\\
        -- when they are dropped again, thre prefix to \\\
        -- their order is removed, and the 'real' orders \\\
        -- are revealed. For now, do nothing\\\
        cfxGroundTroops.updateWait(troop)\\\
    \\\
    elseif troop.orders == \\\"guard\\\" then \\\
        cfxGroundTroops.updateGuards(troop)\\\
    \\\
    elseif troop.orders == \\\"attackOwnedZone\\\" then \\\
        cfxGroundTroops.updateZoneAttackers(troop)\\\
\\\
    elseif troop.orders == \\\"laze\\\" then \\\
        cfxGroundTroops.updateLaze(troop)\\\
    \\\
    elseif troop.orders == \\\"attackZone\\\" then \\\
        cfxGroundTroops.updateAttackers(troop)\\\
        \\\
    else \\\
        trigger.action.outText(\\\"+++ updated troops \\\" .. troop.name .. \\\" have unknown orders \\\" .. troop.orders, 30)\\\
    end\\\
    \\\
end\\\
\\\
--\\\
-- we have to systems to process during update: \\\
-- once all, and one per turn, with the exception \\\
-- of lazers, who get updated every turn\\\
-- \\\
\\\
--\\\
-- all at once \\\
--\\\
function cfxGroundTroops.update()\\\
    cfxGroundTroops.updateSchedule = timer.scheduleFunction(cfxGroundTroops.update, {}, timer.getTime() + 1/cfxGroundTroops.ups)\\\
    -- iterate all my troops and build next \\\
    -- versions pool\\\
    local liveTroops = {}\\\
    for idx, troop in pairs(cfxGroundTroops.deployedTroops) do \\\
        local group = troop.group \\\
        if not dcsCommon.isGroupAlive(group) then \\\
            -- group dead. remove from pool\\\
            -- this happens by not copying it into the poos\\\
        --    trigger.action.outText(\\\"+++ removing ground troops \\\" .. troop.name, 30)\\\
            cfxGroundTroops.invokeCallbacksFor(\\\"dead\\\", troop) -- notify anyone who is interested that we are no longer proccing these \\\
        else \\\
            -- work with this groop according to its orders\\\
            cfxGroundTroops.updateTroops(troop)\\\
--            trigger.action.outText(\\\"+++ updated troops \\\" .. troop.name, 30)\\\
            -- since group is alive remember it for next loop\\\
            --table.insert(liveTroops, troop)\\\
            liveTroops[idx] = troop -- do NOT use insert as we have indexed table\\\
        end\\\
    end\\\
    -- liveTroops holds all troops that are still alive and will\\\
    -- be revisited next loop\\\
    cfxGroundTroops.deployedTroops = liveTroops\\\
end\\\
\\\
--\\\
-- UpdateQueued looks for the first unordered (.receivedOrders == false) group\\\
-- and processes them. if orders are 'laze', it will always be ordered \\\
--\\\
\\\
\\\
function cfxGroundTroops.updateQueued()\\\
    cfxGroundTroops.updateSchedule = timer.scheduleFunction(cfxGroundTroops.updateQueued, {}, timer.getTime() + 1/cfxGroundTroops.ups)\\\
    -- iterate all my troops and build next \\\
    -- versions pool\\\
    local liveTroops = {}\\\
    local hasOrdered = false -- so far, no orders have been given \\\
    for idx, troop in pairs(cfxGroundTroops.deployedTroops) do \\\
        local group = troop.group \\\
        if not dcsCommon.isGroupAlive(group) then \\\
            -- group dead. remove from pool\\\
            -- this happens by not copying it to liveTroops \\\
            -- trigger.action.outText(\\\"+++ removing ground troops \\\" .. troop.name, 30)\\\
            cfxGroundTroops.invokeCallbacksFor(\\\"dead\\\", troop) -- notify anyone who is interested that we are no longer proccing these \\\
        else \\\
            -- check if this is a lazer \\\
            if troop.orders == \\\"laze\\\" then \\\
                -- lazers are updated each turn \\\
                cfxGroundTroops.updateLaze(troop)\\\
            else \\\
                if not hasOrdered and not (troop.receivedOrders) then \\\
                -- work with this groop according to its orders\\\
                cfxGroundTroops.updateTroops(troop)\\\
                troop.receivedOrders = true -- this one has received orders \\\
                hasOrdered = true \\\
                end \\\
            end\\\
            liveTroops[idx] = troop -- do NOT use insert as we have indexed table\\\
        end\\\
    end\\\
    -- liveTroops holds all troops that are still alive and will\\\
    -- be revisited next loop\\\
    cfxGroundTroops.deployedTroops = liveTroops\\\
    \\\
    -- if no orders have been passed, clear all troop's .receivedOrders flag \\\
    -- and the loop starts anew next loop \\\
    if not hasOrdered then \\\
        for idx, troop in pairs(cfxGroundTroops.deployedTroops) do\\\
            troop.receivedOrders = nil  \\\
        end\\\
    end\\\
end\\\
\\\
--\\\
-- in updateCheckOnly we simply check the ground queue \\\
-- if there are troops added that need scheduling (i.e. have \\\
-- been passed in by addTroops and schedule them \\\
--\\\
function cfxGroundTroops.updateCheckOnly()\\\
    -- re-schedule myself in 1 second \\\
    timer.scheduleFunction(cfxGroundTroops.updateCheckOnly, {}, timer.getTime() + 1)\\\
    \\\
    -- iterate through all troops, and \\\
    -- see if there are any that have not been scheduled \\\
    -- to schedule them for updates in 1 second\\\
    -- that will be the first time that they are scheduled,\\\
    -- all others will be self-scheduled \\\
    for idx, troop in pairs(cfxGroundTroops.deployedTroops) do \\\
        if not troop.hasBeenScheduled then \\\
            local params = {troop}\\\
            troop.hasBeenScheduled = true \\\
            troop.updateID = timer.scheduleFunction(cfxGroundTroops.updateSingleScheduled, params, timer.getTime() + 1)\\\
            --trigger.action.outText(\\\"+++groundT: scheduling troops <\\\".. troop.group:getName() ..\\\"> with orders <\\\" .. troop.orders .. \\\">\\\", 30)\\\
        end\\\
    end\\\
    -- note that alive checks are now done during the scheduled\\\
    -- update, not every time for all\\\
\\\
end\\\
\\\
function cfxGroundTroops.updateSingleScheduled(params)\\\
    local troops = params[1]\\\
    troops.updateID = nil -- erase update id \\\
    if not troops then \\\
        trigger.action.outText(\\\"+++groundT WARNING: nil troop in updateSingle\\\", 30)\\\
        return -- no further action required, no longer updates\\\
    end\\\
    \\\
    local group = troops.group \\\
    -- see if we have been taken out of the pool or updated\\\
    -- if so, exit \\\
    \\\
    if not group:isExist() then \\\
        -- simply never again look at it. \\\
        return \\\
    end\\\
    \\\
    if cfxGroundTroops.deployedTroops[troops.group:getName()] ~= troops then \\\
        -- trigger.action.outText(\\\"+++groundT NOTE: troops <\\\".. troops.group:getName() ..\\\"> was removed from pool. Cancel Update\\\", 30)\\\
        return -- no further reschedule\\\
    end\\\
    \\\
    -- see if scheduling is turned off\\\
    if not troops.reschedule then \\\
        trigger.action.outText(\\\"+++groundT NOTE: no longer updating <\\\".. troops.group:getName() ..\\\"> per reschedule param\\\", 30)\\\
        return \\\
    end\\\
    \\\
    -- now, check if still alive \\\
    if not dcsCommon.isGroupAlive(group) then \\\
        -- group dead, no longer updates \\\
        --trigger.action.outText(\\\"+++groundT NOTE: <\\\".. troops.group:getName() ..\\\"> dead, removing\\\", 30)\\\
        cfxGroundTroops.invokeCallbacksFor(\\\"dead\\\", troops) -- notify anyone who is interested that we are no longer proccing these \\\
        cfxGroundTroops.removeTroopsFromPool(troops)\\\
        return -- nothing else to do\\\
    end\\\
    \\\
    -- now, execute the update itself, standard update \\\
    --trigger.action.outText(\\\"+++groundT: singleU troop <\\\".. troops.group:getName() ..\\\"> with orders <\\\" .. troops.orders .. \\\">\\\", 30)\\\
    cfxGroundTroops.updateTroops(troops)\\\
    \\\
    -- check max speed of group. if < 0.1 then note and increase \\\
    -- speedWarning. if not, reset speed warning \\\
    if troops.orders == \\\"attackOwnedZone\\\" and dcsCommon.getGroupMaxSpeed(troops.group) < 0.1 then \\\
        if not troops.speedWarning then troops.speedWarning = 0 end\\\
        troops.speedWarning = troops.speedWarning + 1\\\
    else\\\
        troops.speedWarning = 0 -- reset\\\
    end\\\
    \\\
    if troops.speedWarning > 5 then -- make me 5\\\
        lastOrder = timer.getTime() - troops.lastOrderDate \\\
        --trigger.action.outText(\\\"+++groundT WARNING: <\\\".. troops.group:getName() ..\\\"> (S:\\\".. troops.side .. \\\") to \\\" .. troops.destination.name .. \\\": stopped for \\\" .. troops.speedWarning .. \\\" iters, orderage=\\\" .. lastOrder, 30)\\\
        -- this may be a matter of too many waypoints. \\\
        -- maybe issue orders to go to their destination directly?\\\
        -- now force an order to go directly.\\\
        if troops.speedWarning > 5 then \\\
            if troops.isOffroad then \\\
                -- we already switched to off-road. take me \\\
                -- out of the managed queue, I'm not going \\\
                -- anywhere\\\
                -- trigger.action.outText(\\\"+++groundT <\\\".. troops.group:getName() ..\\\"> is going nowhere. Removed from managed troops\\\", 30)\\\
                cfxGroundTroops.removeTroopsFromPool(troops)\\\
            else \\\
                cfxGroundTroops.switchToOffroad(troops)\\\
                -- trigger.action.outText(\\\"+++groundT <\\\".. troops.group:getName() ..\\\"> SWITCHED TO OFFROAD\\\", 30)\\\
                troops.isOffroad = true -- so we know that we already did that\\\
            end\\\
        end \\\
    end\\\
    \\\
    -- now reschedule updte for my best time \\\
    local updateTime = cfxGroundTroops.getScheduleInterval(troops.orders)\\\
    troops.updateID = timer.scheduleFunction(cfxGroundTroops.updateSingleScheduled, params, timer.getTime() + updateTime)\\\
end\\\
\\\
\\\
--\\\
-- PILEUP and TIE BRAKERS\\\
--\\\
-- there may come a situation where troops gather in \\\
-- one zone because the zone isn't won - some other troops \\\
-- are there and noone moves. \\\
-- a tie-break is required\\\
--\\\
\\\
-- checkpile up: every so often, we test if we have run into a \\\
-- pileup-situation. this happens if there are more than n \\\
-- units with group-attacker order in the same zone, and that \\\
-- zone is their destination \\\
-- this can be easily detected by the insideDestination flag \\\
-- checkPileUp should be run every minute or so \\\
 \\\
function cfxGroundTroops.checkPileUp()\\\
    -- schedule my next call \\\
    --trigger.action.outText(\\\"+++groundT: pileup check\\\", 30)\\\
    timer.scheduleFunction(cfxGroundTroops.checkPileUp, {}, timer.getTime() + 60)\\\
    local thePiles = {}\\\
    if not cfxOwnedZones then \\\
        -- trigger.action.outText(\\\"+++groundT: pileUp - owned zones not yet ready\\\", 30)\\\
        return \\\
    end\\\
    \\\
    -- create a list of all piles \\\
    for idx, oz in pairs(cfxOwnedZones.zones) do \\\
        local newPile = {}\\\
        newPile[1] = 0 -- no red inZone here \\\
        newPile[2] = 0 -- no blue inZone here \\\
        newPile.zone = oz -- the zone we are looking at \\\
        thePiles[oz] = newPile \\\
    end\\\
    \\\
    -- now iterate through all currently alive groups and \\\
    -- attribute them to their piles \\\
    for idx, troop in pairs(cfxGroundTroops.deployedTroops) do \\\
        -- get each group and count them if they are inside\\\
        -- their destination \\\
        if troop.insideDestination then\\\
            local side = troop.group:getCoalition()\\\
            local thePile = thePiles[troop.destination]\\\
            local theSide = troop.group:getCoalition()\\\
            thePile[theSide] = thePile[theSide] + 1 -- we count groups, not units  \\\
        end\\\
    end\\\
    \\\
    -- a pileup happens, if there are more than 3 groups in destination zone\\\
    -- with NO other troops present (usually the case)\\\
    -- or when there are 5 groups more than the number for the other side \\\
    -- so now scan all piles\\\
    for idx, thePile in pairs(thePiles) do \\\
        -- check red pileup \\\
        if thePile[1] > 3 and thePile[2] == 0 then \\\
            -- simple pileup. 3 groups, no others except defenders and \\\
            -- perhaps transients \\\
            cfxGroundTroops.breakTie(thePile, 1)\\\
        elseif thePile[1] >= thePile[2] + 5 then \\\
            -- numerical pileup \\\
            cfxGroundTroops.breakTie(thePile, 1)\\\
        end\\\
        \\\
        -- check blue loside \\\
        if thePile[2] >= 3 and thePile[1] == 0 then \\\
            -- simple pileup. 3 groups, no others except defenders and \\\
            -- perhaps transients \\\
            cfxGroundTroops.breakTie(thePile, 2)\\\
        elseif thePile[2] >= thePile[1] + 5 then \\\
            -- numerical pileup \\\
            cfxGroundTroops.breakTie(thePile, 2)\\\
        end\\\
    end\\\
end\\\
\\\
function cfxGroundTroops.breakTie(thePile, winner)\\\
    trigger.action.outText(\\\"+++ groundT: TIEBREAK - winner is \\\" .. winner .. \\\" in zone \\\" .. thePile.zone.name .. \\\": \\\" .. thePile[1] .. \\\":\\\" .. thePile[2] , 30)\\\
    -- now add some code to do the actual tie breaking: remove all units that \\\
    -- are inside the zone and who belong to the other side \\\
    local loser = 1 -- red default \\\
    local theZone = thePile.zone \\\
    if winner == 1 then loser = 2 end \\\
    -- now get all ground groups for the losing side\\\
    local losingGround = coalition.getGroups(loser, Group.Category.GROUND)\\\
    for idx, theGroup in pairs(losingGround) do \\\
        -- if alive, check if inside the zone \\\
        if theGroup:isExist() and dcsCommon.isGroupAlive(theGroup) then \\\
            -- make sure it's not a transient\\\
            if not isDeployedGroundTroop(theGroup) then \\\
                local p = dcsCommon.getGroupLocation(theGroup) \\\
                if cfxZones.isPointInsideZone(p, theZone) then \\\
                    trigger.action.outText(\\\"+++ groundT: TIEBREAK - destroying group \\\" .. theGroup:getName() , 30)\\\
                    -- we delete this group now\\\
                    theGroup:destroy()\\\
                end\\\
            end\\\
        end\\\
    end\\\
end\\\
\\\
--\\\
-- sanity checks for rescheduling\\\
--\\\
function cfxGroundTroops.checkSchedules()\\\
    timer.scheduleFunction(cfxGroundTroops.checkSchedules, {}, timer.getTime() + 10)\\\
    for idx, troop in pairs(cfxGroundTroops.deployedTroops) do\\\
        -- check if troop is not scheduled \\\
        -- if this happens to a group more than a certain times,\\\
        -- it has somehow dropped out of the reschedule \\\
        -- plan and needs to be scheduled \\\
        if troop.updateID == nil then \\\
            troop.unscheduleCount = troop.unscheduleCount + 1\\\
            if (troop.unscheduleCount > 1) then \\\
                trigger.action.outText(\\\"+++ groundT: unscheduled group  \\\" .. troop.group:getName() .. \\\" cnt=\\\" .. troop.unscheduleCount , 30)\\\
            end \\\
        end\\\
    end\\\
end\\\
\\\
--\\\
-- REPORTING \\\
--\\\
-- \\\
-- get a report of troops as string \\\
-- \\\
function cfxGroundTroops.getTroopReport(theSide, ignoreInfantry)\\\
    if not ignoreInfantry then ignoreInfantry = false end \\\
    local report = \\\"GROUND FORCES REPORT\\\"\\\
    for idx, troop in pairs(cfxGroundTroops.deployedTroops) do \\\
        if troop.side == theSide then \\\
            local unitNum = troop.group:getSize()\\\
            report = report .. \\\"\\\\n\\\" .. troop.name .. \\\" (\\\".. unitNum ..\\\"): <\\\" .. troop.orders .. \\\">\\\" \\\
            if troop.orders == \\\"attackOwnedZone\\\" then \\\
                if troop.destination then     \\\
                    report = report .. \\\" move towards \\\" .. troop.destination.name \\\
                else \\\
                    report = report .. \\\" (selecting destination)\\\"\\\
                end\\\
            end\\\
        end\\\
    end\\\
    report = report .. \\\"\\\\n---END REPORT\\\\n\\\"\\\
    return report \\\
end\\\
\\\
\\\
--\\\
-- CREATE / ADD / REMOVE \\\
--\\\
\\\
--\\\
-- createGroundTroop\\\
-- use this to create a cfxGroundTroops from a dcs group\\\
--\\\
function cfxGroundTroops.createGroundTroops(inGroup, range, orders) \\\
    local newTroops = {}\\\
    if not orders then \\\
        orders = \\\"guard\\\" \\\
        --trigger.action.outText(\\\"+++ adding ground troops <\\\".. inGroup:getName() ..\\\">with default orders\\\", 30)\\\
    else \\\
        --trigger.action.outText(\\\"+++ adding ground troops <\\\".. inGroup:getName() ..\\\">with orders \\\" .. orders, 30)\\\
    end\\\
    if orders:lower() == \\\"lase\\\" then \\\
        orders = \\\"laze\\\" -- we use WRONG spelling here, cause we're cool\\\
    end\\\
    newTroops.insideDestination = false\\\
    newTroops.unscheduleCount = 0 -- will count up as we aren't scheduled\\\
    newTroops.speedWarning = 0\\\
    newTroops.isOffroad = false -- if true, we switched to direct orders, not roads, after standstill\\\
    newTroops.group = inGroup\\\
    newTroops.orders = orders\\\
    newTroops.coalition = inGroup:getCoalition()\\\
    newTroops.side = newTroops.coalition -- because we'e been using both.\\\
    newTroops.name = inGroup:getName()\\\
    newTroops.signature = \\\"cfx\\\" -- to verify this is groundTroop group, not dcs groups\\\
    if not range then range = 300 end\\\
    newTroops.range = range\\\
    return newTroops\\\
end\\\
\\\
function cfxGroundTroops.addGroundTroopsToPool(troops) -- troops MUST be a table that I understand, with \\\
    if not troops then return end\\\
    if troops.signature ~= \\\"cfx\\\" then \\\
        trigger.action.outText(\\\"+++ adding ground troops with unsupported troop signature\\\", 30)\\\
        return \\\
    end\\\
    \\\
    troops.reschedule = true -- in case we use scheduled update \\\
    -- we now add to internal array. this is worked on by all \\\
    -- update meths, on scheduled upadtes, it is only used to \\\
    -- pick up, and do the initial schedule, after that they \\\
    -- all re-schedule themselves \\\
    troops.hasBeenScheduled = false -- so far, no updates \\\
    -- hasBeenScheduled is used by updateCheckOnly when scheduled \\\
    -- updates are used. \\\
    \\\
    -- now add to actively managed table or queue it if enabled\\\
    if cfxGroundTroops.maxManagedTroops > 0 and dcsCommon.getSizeOfTable(cfxGroundTroops.deployedTroops) >= cfxGroundTroops.maxManagedTroops then \\\
        -- we need to queue \\\
        table.insert(cfxGroundTroops.troopQueue, troops)\\\
        -- trigger.action.outText(\\\"enqued \\\" .. troops.group:getName() .. \\\" at pos \\\".. #cfxGroundTroops.troopQueue ..\\\", manage cap surpassed.\\\", 30)\\\
    else\\\
        -- add to deployed set\\\
        cfxGroundTroops.deployedTroops[troops.group:getName()] = troops\\\
    end\\\
end\\\
\\\
function cfxGroundTroops.removeTroopsFromPool(troops)\\\
    if not troops then return end \\\
    if troops.signature ~= \\\"cfx\\\" then return end\\\
    \\\
    if cfxGroundTroops.deployedTroops[troops.group:getName()] then \\\
        local troop = cfxGroundTroops.deployedTroops[troops.group:getName()]\\\
        troops.reschedule = false -- so a reschedule wont update any more\\\
        cfxGroundTroops.deployedTroops[troops.group:getName()] = nil\\\
        return \\\
    end\\\
    \\\
    -- if we get here, we need to check if perhaps the troops \\\
    -- are in the queue\\\
    for i=1, #cfxGroundTroops.troopQueue do \\\
        if cfxGroundTroops.troopQueue[i] == troops then \\\
            table.remove(cfxGroundTroops.troopQueue, i)\\\
            return\\\
        end\\\
    end\\\
end\\\
\\\
function isDeployedGroundTroop(aGroup) \\\
    if not aGroup then return false end \\\
    -- see if its already managed\\\
    if cfxGroundTroops.deployedTroops[aGroup:getName()] ~= nil then \\\
        return true \\\
    end \\\
    \\\
    -- see if it's in the queue \\\
    for i=1, #cfxGroundTroops.troopQueue do \\\
        if cfxGroundTroops.troopQueue[i] == troops then \\\
            return true\\\
        end\\\
    end\\\
    -- if we get here, it's neither managed nor queued\\\
    return false \\\
--    return cfxGroundTroops.deployedTroops[aGroup:getName()] ~= nil \\\
end\\\
\\\
function cfxGroundTroops.getGroundTroopsForGroup(aGroup) \\\
    if not (cfxGroundTroops.deployedTroops[aGroup:getName()]) then\\\
        -- see if it's queued \\\
        for i=1, #cfxGroundTroops.troopQueue do \\\
            local troops = cfxGroundTroops.troopQueue[i]\\\
            if troops.group == aGroup then \\\
                return troops\\\
            end\\\
        end\\\
        \\\
        trigger.action.outText(\\\"+++ WARNING: cannot find group \\\" .. aGroup:getName() .. \\\" for troop retrieval. Known troops are:\\\", 30)\\\
        for k,v in pairs(cfxGroundTroops.deployedTroops) do \\\
            trigger.action.outText(\\\"+++ \\\".. k .. \\\": has v: \\\" .. v.name, 30)\\\
        end\\\
        return nil\\\
    end\\\
    \\\
    return cfxGroundTroops.deployedTroops[aGroup:getName()]\\\
end\\\
\\\
function cfxGroundTroops.monitorQueues()\\\
    timer.scheduleFunction(cfxGroundTroops.monitorQueues, {}, timer.getTime() + 5)\\\
    \\\
    -- calculate the numbers \\\
    local num = dcsCommon.getSizeOfTable(cfxGroundTroops.deployedTroops)\\\
    \\\
    local msg = \\\"+++ gT - Groups Managed: <\\\" .. num .. \\\">\\\"\\\
    -- display the numbers\\\
    if cfxGroundTroops.maxManagedTroops > 0 then \\\
        msg = msg .. \\\" capped at \\\" .. cfxGroundTroops.maxManagedTroops .. \\\", q size is <\\\" .. #cfxGroundTroops.troopQueue .. \\\">\\\"\\\
    end\\\
    trigger.action.outText(msg, 30)\\\
end\\\
\\\
\\\
-- manageQueue: if depth of deployedTroops is below max and we have \\\
-- items in queue, pop off first one and put in managed table \\\
-- checked once every 2 seconds \\\
function cfxGroundTroops.manageQueues() \\\
    timer.scheduleFunction(cfxGroundTroops.manageQueues, {}, timer.getTime() + 2)\\\
    if cfxGroundTroops.maxManagedTroops < 1 then return end\\\
    \\\
    -- if we get here, we have a limit on managed \\\
    -- items \\\
    if #cfxGroundTroops.troopQueue < 1 then return end \\\
    \\\
    -- if we here, there are items waiting in the queue\\\
    while dcsCommon.getSizeOfTable(cfxGroundTroops.deployedTroops) < cfxGroundTroops.maxManagedTroops and #cfxGroundTroops.troopQueue > 0 do \\\
        -- trnasfer items from the front to the managed queue \\\
        local theTroops = cfxGroundTroops.troopQueue[1]\\\
        table.remove(cfxGroundTroops.troopQueue, 1)\\\
        cfxGroundTroops.deployedTroops[theTroops.group:getName()] = theTroops\\\
        -- trigger.action.outText(\\\"+++gT: dequed and activaed \\\" .. theTroops.group:getName(), 30)\\\
    end\\\
end\\\
\\\
\\\
function cfxGroundTroops.start()\\\
    if not dcsCommon.libCheck(\\\"cfx Ground Troops\\\",\\\
                              cfxGroundTroops.requiredLibs)\\\
    then \\\
        trigger.action.outText(\\\"cf/x Ground Troops aborted: missing libraries\\\", 30)\\\
        return false \\\
    end\\\
    \\\
    -- read optional config zone \\\
    cfxGroundTroops.readConfigZone()\\\
    \\\
    if cfxGroundTroops.scheduledUpdates then \\\
        cfxGroundTroops.queuedUpdates = false \\\
        cfxGroundTroops.updateCheckOnly()\\\
        cfxGroundTroops.checkSchedules() -- check regularly if all troops have been updated by checking their ID\\\
    elseif cfxGroundTroops.queuedUpdates then \\\
        cfxGroundTroops.updateQueued()\\\
    else     \\\
        cfxGroundTroops.update()\\\
    end \\\
    -- now install a regular pileup check \\\
    timer.scheduleFunction(cfxGroundTroops.checkPileUp, {}, timer.getTime() + 60) \\\
    \\\
    if cfxGroundTroops.monitorNumbers then \\\
        timer.scheduleFunction(cfxGroundTroops.monitorQueues, {}, timer.getTime() + 5) \\\
    end\\\
    \\\
    if cfxGroundTroops.maxManagedTroops > 0 then\\\
        timer.scheduleFunction(cfxGroundTroops.manageQueues, {}, timer.getTime() + 1) \\\
    end \\\
    \\\
    trigger.action.outText(\\\"cf/x Ground Troops v\\\" .. cfxGroundTroops.version .. \\\" started\\\", 30)\\\
    \\\
    if not cfxOwnedZones then \\\
        --trigger.action.outText(\\\"+++groundT: pileUp - owned zones not yet ready\\\", 30)\\\
    end\\\
    return true \\\
end\\\
\\\
if not cfxGroundTroops.start() then \\\
    cfxGroundTroops = nil \\\
    trigger.action.outText(\\\"cfxGroundTroops aborted load\\\", 30)\\\
end\\\
\\\
--[[--\\\
 TO DO \\\
 \\\
 - implement 'patrol' orders!!! \\\
   \\\
   when ordering a new route, issue a command to stop in 1 second\\\
 and another with new marching orders in 5 seconds \\\
 look at setTask() and resetTask() for controller\\\
 - change group logic to set itself up to 'requestOrders' with group as parameter, so they can decide themselves how quickly they want to be re-tasked\\\
 \\\
 - DONE enqueue and dequeue methods with capped ground troops size \\\
 - named locs have strategic values attached (default = 1), and distance is divided by strat value to get at priority when rerouting \\\
 \\\
 - difficulty increase: make enemy troops better by raining their spawned level \\\
 \\\
 - check out simple slot block SSB (pre-moose) to see if we can implement slot blocking for downed pilots \\\
 \\\
 - new 'wanda' (wander) module to make airports more lively: zone, have individuals/single vehicle wander around. two waypoints (start and stop), that are zones, and whenever they reach one or are at speed 0, they get a new one. may have pause before they go to next. \\\
 variant on above: selection of zones that are somehow connected, and destinations are made between these for patrolling zone. can force order, loop, and ping-pong. \\\
--]]--\");a_do_script(\"cfxSpawnZones = {}\\\
cfxSpawnZones.version = \\\"1.4.6\\\"\\\
cfxSpawnZones.requiredLibs = {\\\
    \\\"dcsCommon\\\", -- common is of course needed for everything\\\
                 -- pretty stupid to check for this since we \\\
                 -- need common to invoke the check, but anyway\\\
    \\\"cfxZones\\\", -- Zones, of course \\\
    \\\"cfxCommander\\\", -- to make troops do stuff\\\
    \\\"cfxGroundTroops\\\", -- generic data module for weight \\\
}\\\
cfxSpawnZones.ups = 1\\\
\\\
--\\\
-- Zones that conform with this requirements spawn toops automatically\\\
--   *** DOES NOT EXTEND ZONES *** LINKED OWNER via masterOwner ***\\\
-- \\\
\\\
-- version history\\\
--   1.3.0 \\\
--         - maxSpawn\\\
--         - orders\\\
--         - range\\\
--   1.3.1 - spawnWithSpawner correct translation of country to coalition \\\
--         - createSpawner - corrected reading from properties\\\
--   1.3.2 - createSpawner - correct reading 'owner' from properties, now \\\
--           directly reads coalition\\\
--   1.4.0 - checks modules \\\
--         - orders 'train' or 'training' - will make the \\\
--           ground troops be issued HOLD WEAPS and \\\
--           not added to any queue. 'Training' troops \\\
--           are target dummies.\\\
--         - optional heading attribute \\\
--         - typeMult: repeate type this many time (can produce army in one call)\\\
--   1.4.1 - 'requestable' attribute. will automatically set zone to \\\
--         - paused, so troops can be produced on call\\\
--         - getRequestableSpawnersInRange \\\
--   1.4.2 - target attribute. used for\\\
--         - orders: attackZone \\\
--         - spawner internally copies name from cfxZone used for spawning (convenience only)\\\
--   1.4.3 - can subscribe to callbacks. currently called when spawnForSpawner is invoked, reason is \\\"spawned\\\"\\\
--         - masterOwner to link ownership to other zone \\\
--   1.4.4 - autoRemove flag to instantly start CD and respawn \\\
--   1.4.5 - verify that maxSpawns ~= 0 on initial spawn on start-up \\\
--   1.4.6 - getSpawnerForZoneNamed(aName)\\\
--         - nil-trapping orders before testing for 'training'\\\
--   1.4.7 - defaulting orders to 'guard'\\\
--         - also accept 'dummy' and 'dummies' as substitute for training \\\
--\\\
-- new version requires cfxGroundTroops, where they are \\\
--\\\
-- How do we recognize a spawn zone?\\\
-- contains a \\\"spawner\\\" attribute\\\
-- a spawner must also have the following attributes\\\
--  - spawner - anything, must be present to signal. put in 'ground' to be able to expand to other types  \\\
--  - types    - type strings, comma separated \\\
-- see here: https://github.com/mrSkortch/DCS-miscScripts/tree/master/ObjectDB\\\
--  - typeMult - repeat types n times to create really LOT of troops. optional, defaults to 1\\\
--  - country  - defaults to 2 (usa) -- see here https://wiki.hoggitworld.com/view/DCS_enum_country\\\
--    some important: 0 = Russia, 2 = US, 82 = UN neutral\\\
--    country is converted to coalition and then assigned to\\\
--    Joint Task Force <side> upon spawn\\\
--  - masterOwner - optional name of master cfxZone used to determine whom the surrounding \\\
--    territory belongs to. Spwaner will only spawn if the owner coalition is the \\\
--    the same as the coalition my own county belongs to.\\\
--    if not given, spawner spawns even if inside a zone owned by opposing force \\\
--  - baseName - for naming spawned groups - MUST BE UNIQUE!!!!\\\
--  \\\
-- the following attributes are optional \\\
--  - cooldown, defaults to 60 (seconds) after troops are removed from zone,\\\
--    then the next group spawns. This means troops will only spawn after \\\
--    troops are removed and cooldown timed out \\\
--  - autoRemove - instantly removes spwaned troops, will spawn again \\\
--    again after colldown \\\
--  - formation - default is  circle_out; other formations are \\\
--        - line - left lo right (west-east) facing north\\\
--      - line_V - vertical line, facing north\\\
--      - chevron - west-east, point growing to north \\\
--      - scattered, random\\\
--      - circle, circle_forward (all fact north)\\\
--        - circle-in (all face in)\\\
--      - circle-out (all face out)\\\
--      - grid, square, rect arrayed in optimal grid\\\
--      - 2deep, 2cols two columns, deep \\\
--      - 2wide 2 columns wide (2 deep) \\\
--  - heading in DEGREES (deafult 0 = north ) direction entire group is facing \\\
--  - destination - zone name to go to, no destination = stay where you are \\\
--  - paused - defaults to false. If present true, spawning will not happen\\\
--    you can then manually invoke cfxSpawnZones.spawnWithSpawner(spawner) to \\\
--    spawn the troops as they are described in the spawner \\\
--  - orders - tell them what to do. \\\"train\\\" makes them dummies, \\\"guard\\\" \\\
--    \\\"laze\\\", \\\"wait-laze\\\" etc \\\
--    other orders are as defined by cfxGroundTroops, at least \\\
--      guard - hold and defend (default)\\\
--      laze - laze targets \\\
--      wait-xxx for helo troops, stand by until dropped from helo \\\
--      attackOwnedZone - seek nearest owned zone and attack\\\
--      attackZone - move towards the named cfxZone. will generate error if zone not found \\\
--      name of zone to attack is in 'target' attribute\\\
--  - target - names a target cfxZone, used for orders. Troops will immediately\\\
--    start moving towards that zone if defined and such a zone exists\\\
--  - maxSpawns - limit number of spawn cycles. omit or -1 is unlimited\\\
--  - requestable - used with heloTroops to determine if spawning can be ordered by \\\
--    comms when in range\\\
-- respawn currently happens after theSpawn is deleted and cooldown seconds have passed \\\
cfxSpawnZones.allSpawners = {}\\\
cfxSpawnZones.callbacks = {} -- signature: cb(reason, group, spawner)\\\
 \\\
\\\
--\\\
-- C A L L B A C K S \\\
-- \\\
function cfxSpawnZones.addCallback(theCallback)\\\
    table.insert(cfxSpawnZones.callbacks, theCallback)\\\
end\\\
\\\
function cfxSpawnZones.invokeCallbacksFor(reason, theGroup, theSpawner)\\\
    for idx, theCB in pairs (cfxSpawnZones.callbacks) do \\\
        theCB(reason, theGroup, theSpawner)\\\
    end\\\
end\\\
\\\
\\\
--\\\
-- creating a spawner\\\
--\\\
function cfxSpawnZones.createSpawner(inZone)\\\
    local theSpawner = {}\\\
    theSpawner.zone = inZone\\\
    theSpawner.name = inZone.name \\\
    theSpawner.types = cfxZones.getZoneProperty(inZone, \\\"types\\\")\\\
    --theSpawner.owner = cfxZones.getCoalitionFromZoneProperty(inZone, \\\"owner\\\", 0)\\\
    -- synthesize types * typeMult\\\
    local n = cfxZones.getNumberFromZoneProperty(inZone, \\\"typeMult\\\", 1)\\\
    local repeater = \\\"\\\"\\\
    if n < 1 then n = 1 end \\\
    while n > 1 do \\\
        repeater = repeater .. \\\",\\\" .. theSpawner.types\\\
        n = n - 1\\\
    end\\\
    theSpawner.types = theSpawner.types .. repeater \\\
    \\\
    theSpawner.country = cfxZones.getNumberFromZoneProperty(inZone, \\\"country\\\", 0) -- coalition2county(theSpawner.owner)\\\
    theSpawner.masterZoneName = cfxZones.getStringFromZoneProperty(inZone, \\\"masterOwner\\\", \\\"\\\")\\\
    if theSpawner.masterZoneName == \\\"\\\" then theSpawner.masterZoneName = nil end \\\
    \\\
    theSpawner.rawOwner = coalition.getCountryCoalition(theSpawner.country)\\\
    theSpawner.baseName = cfxZones.getZoneProperty(inZone, \\\"baseName\\\")\\\
    theSpawner.cooldown = cfxZones.getNumberFromZoneProperty(inZone, \\\"cooldown\\\", 60)\\\
    theSpawner.autoRemove = cfxZones.getBoolFromZoneProperty(inZone, \\\"autoRemove\\\", false)\\\
    theSpawner.lastSpawnTimeStamp = -10000 -- just init so it will always work\\\
    theSpawner.heading = cfxZones.getNumberFromZoneProperty(inZone, \\\"heading\\\", 0)\\\
    --trigger.action.outText(\\\"+++spwn: zone \\\" .. inZone.name .. \\\" owner \\\" .. theSpawner.owner \\\" --> ctry \\\" .. theSpawner.country, 30)\\\
    \\\
    theSpawner.cdTimer = 0 -- used for cooldown. if timer.getTime < this value, don't spawn\\\
    theSpawner.cdStarted = false -- used to initiate cooldown when theSpawn disappears\\\
    theSpawner.count = 1 -- used to create names, and count how many groups created\\\
    theSpawner.theSpawn = nil -- link to last spawned group\\\
    theSpawner.formation = \\\"circle_out\\\"\\\
    theSpawner.formation = cfxZones.getStringFromZoneProperty(inZone, \\\"formation\\\", \\\"circle_out\\\")\\\
    theSpawner.paused = cfxZones.getBoolFromZoneProperty(inZone, \\\"paused\\\", false)\\\
    theSpawner.orders = cfxZones.getStringFromZoneProperty(inZone, \\\"orders\\\", \\\"guard\\\")\\\
    --theSpawner.orders = cfxZones.getZoneProperty(inZone, \\\"orders\\\")\\\
    -- used to assign special orders, default is 'guard', use \\\"laze\\\" to make them laze targets. can be 'wait-' which may auto-convert to 'guard' after pick-up by helo, to be handled outside.\\\
    -- use \\\"train\\\" to tell them to HOLD WEAPONS, don't move and don't participate in loop, so we have in effect target dummies\\\
    -- can also use order 'dummy' or 'dummies' to switch to train\\\
    if theSpawner.orders:lower() == \\\"dummy\\\" or theSpawner.orders:lower() == \\\"dummies\\\" then theSpawner.orders = \\\"train\\\" end \\\
    \\\
    theSpawner.range = cfxZones.getNumberFromZoneProperty(inZone, \\\"range\\\", 300) -- if we have a range, for example enemy detection for Lasing or engage range\\\
    theSpawner.maxSpawns = cfxZones.getNumberFromZoneProperty(inZone, \\\"maxSpawns\\\", -1) -- if there is a limit on how many troops can spawn. -1 = endless spawns\\\
    theSpawner.requestable = cfxZones.getBoolFromZoneProperty(inZone, \\\"requestable\\\", false)\\\
    if theSpawner.requestable then \\\
        theSpawner.paused = true \\\
    end\\\
    theSpawner.target = cfxZones.getStringFromZoneProperty(inZone, \\\"target\\\", \\\"\\\")\\\
    if theSpawner.target == \\\"\\\" then -- this is the defaut case \\\
        theSpawner.target = nil \\\
    end\\\
    \\\
    return theSpawner\\\
end\\\
\\\
function cfxSpawnZones.addSpawner(aSpawner)\\\
    cfxSpawnZones.allSpawners[aSpawner.zone] = aSpawner\\\
end\\\
\\\
function cfxSpawnZones.removeSpawner(aSpawner)\\\
    cfxSpawnZones.allSpawners[aSpawner.zone] = nil\\\
end\\\
\\\
function cfxSpawnZones.getSpawnerForZone(aZone)\\\
    return cfxSpawnZones.allSpawners[aZone]\\\
end\\\
\\\
function cfxSpawnZones.getSpawnerForZoneNamed(aName)\\\
    local aZone = cfxZones.getZoneByName(aName) \\\
    return cfxSpawnZones.getSpawnerForZone(aZone)\\\
end\\\
\\\
\\\
function cfxSpawnZones.getRequestableSpawnersInRange(aPoint, aRange, aSide)\\\
    -- trigger.action.outText(\\\"enter requestable spawners for side \\\" .. aSide , 30)\\\
    if not aSide then aSide = 0 end  \\\
    if not aRange then aRange = 200 end \\\
    if not aPoint then return {} end \\\
\\\
    local theSpawners = {}\\\
    for aZone, aSpawner in pairs(cfxSpawnZones.allSpawners) do \\\
        -- iterate all zones and collect those that match \\\
        local hasMatch = true \\\
        local delta = dcsCommon.dist(aPoint, aZone.point)\\\
        if delta>aRange then hasMatch = false end \\\
        if aSide ~= 0 then \\\
            -- check if side is correct for owned zone \\\
            if not cfxSpawnZones.verifySpawnOwnership(aSpawner) then \\\
                -- failed ownership test. owner of master \\\
                -- is not my own zone \\\
                hasMatch = false \\\
            end\\\
        end\\\
        \\\
        if aSide ~= aSpawner.rawOwner then \\\
            -- only return spawners with this side\\\
            -- note: this will NOT work with neutral players \\\
            hasMatch = false \\\
        end\\\
        \\\
        if not aSpawner.requestable then \\\
            hasMatch = false \\\
        end\\\
        \\\
        if hasMatch then \\\
            table.insert(theSpawners, aSpawner)\\\
        end\\\
    end\\\
    \\\
    return theSpawners\\\
end\\\
--\\\
-- spawn troops \\\
-- \\\
function cfxSpawnZones.verifySpawnOwnership(spawner)\\\
    -- returns false ONLY if masterSpawn disagrees\\\
    if not spawner.masterZoneName then \\\
        --trigger.action.outText(\\\"spawner \\\" .. spawner.name .. \\\" no master, go!\\\", 30)\\\
        return true \\\
    end -- no master owner, all ok\\\
    local myCoalition = spawner.rawOwner\\\
    local masterZone = cfxZones.getZoneByName(spawner.masterZoneName)\\\
    if not masterZone then \\\
        trigger.action.outText(\\\"spawner \\\" .. spawner.name .. \\\" DID NOT FIND MASTER ZONE <\\\" .. spawner.masterZoneName .. \\\">\\\", 30)\\\
    end\\\
    \\\
    if not masterZone.owner then \\\
        --trigger.action.outText(\\\"spawner \\\" .. spawner.name .. \\\" - masterZone \\\" .. masterZone.name .. \\\" HAS NO OWNER????\\\", 30)\\\
        return true \\\
    end\\\
    \\\
    if (myCoalition ~= masterZone.owner) then \\\
        -- can't spawn, surrounding area owned by enemy\\\
        --trigger.action.outText(\\\"spawner \\\" .. spawner.name .. \\\" - spawn suppressed: area not owned: \\\" .. \\\" master owner is \\\" .. masterZone.owner .. \\\", we are \\\" .. myCoalition, 30)\\\
        return false \\\
    end\\\
    --trigger.action.outText(\\\"spawner \\\" .. spawner.name .. \\\" good to go: \\\", 30)\\\
    return true\\\
end\\\
\\\
function cfxSpawnZones.spawnWithSpawner(aSpawner)\\\
    -- will NOT check if conditions are met. This forces a spawn\\\
    local unitTypes = {} -- build type names\\\
    local p = aSpawner.zone.point  \\\
        \\\
    -- split the conf.troopsOnBoardTypes into an array of types\\\
    unitTypes = dcsCommon.splitString(aSpawner.types, \\\",\\\")\\\
    if #unitTypes < 1 then \\\
        table.insert(unitTypes, \\\"Soldier M4\\\") -- make it one m4 trooper as fallback\\\
    end\\\
    \\\
    local theCountry = aSpawner.country  \\\
    local theCoalition = coalition.getCountryCoalition(theCountry)\\\
--    trigger.action.outText(\\\"+++ spawn: coal <\\\" .. theCoalition .. \\\"> from country <\\\" .. theCountry .. \\\">\\\", 30)\\\
    \\\
    local theGroup = cfxZones.createGroundUnitsInZoneForCoalition (\\\
                theCoalition, \\\
                aSpawner.baseName .. \\\"-\\\" .. aSpawner.count, -- must be unique \\\
                aSpawner.zone,                                             \\\
                unitTypes,                                                     \\\
                aSpawner.formation,\\\
                aSpawner.heading)\\\
    aSpawner.theSpawn = theGroup\\\
    aSpawner.count = aSpawner.count + 1 \\\
    -- we may also want to add this to auto ground troops pool \\\
    -- we not only want to, we absolutely need to in order \\\
    -- to make this work. \\\
    \\\
    if aSpawner.orders and (\\\
       aSpawner.orders:lower() == \\\"training\\\" or \\\
       aSpawner.orders:lower() == \\\"train\\\" )\\\
    then \\\
        -- make them ROE \\\"HOLD\\\"\\\
        cfxCommander.scheduleOptionForGroup(\\\
            theGroup, \\\
            AI.Option.Ground.id.ROE, \\\
            AI.Option.Ground.val.ROE.WEAPON_HOLD, \\\
            1.0)\\\
    else \\\
        local newTroops = cfxGroundTroops.createGroundTroops(theGroup, aSpawner.range, aSpawner.orders) \\\
        cfxGroundTroops.addGroundTroopsToPool(newTroops)\\\
        \\\
        -- see if we have defined a target zone as destination\\\
        if aSpawner.target then \\\
            local destZone = cfxZones.getZoneByName(aSpawner.target)\\\
            if destZone then\\\
                newTroops.destination = destZone\\\
                cfxGroundTroops.makeTroopsEngageZone(newTroops)\\\
            else \\\
                trigger.action.outText(\\\"+++ spawner \\\" .. aSpawner.name .. \\\" has illegal target \\\" .. aSpawner.target .. \\\". Pausing.\\\", 30)\\\
                aSpawner.paused = true \\\
            end\\\
        elseif aSpawner.orders == \\\"attackZone\\\" then \\\
            trigger.action.outText(\\\"+++ spawner \\\" .. aSpawner.name .. \\\" has no target but attackZone command. Pausing.\\\", 30)\\\
                aSpawner.paused = true         \\\
        end \\\
        \\\
    end\\\
    \\\
    -- callback to all who want to know \\\
    cfxSpawnZones.invokeCallbacksFor(\\\"spawned\\\", theGroup, aSpawner)\\\
    \\\
    -- timestamp so we can check against cooldown on manual spawn\\\
    aSpawner.lastSpawnTimeStamp = timer.getTime()\\\
    -- make sure a requestable spawner is always paused \\\
    if aSpawner.requestable then \\\
        aSpawner.paused = true \\\
    end\\\
    \\\
    if aSpawner.autoRemove then \\\
        -- simply remove the group \\\
        aSpawner.theSpawn = nil\\\
    end\\\
end\\\
\\\
\\\
--\\\
-- U P D A T E \\\
--\\\
\\\
function cfxSpawnZones.update()\\\
    cfxSpawnZones.updateSchedule = timer.scheduleFunction(cfxSpawnZones.update, {}, timer.getTime() + 1/cfxSpawnZones.ups)\\\
    \\\
    for key, spawner in pairs (cfxSpawnZones.allSpawners) do \\\
        -- see if the spawn is dead or was removed\\\
        local needsSpawn = true \\\
        if spawner.theSpawn then \\\
            local group = spawner.theSpawn\\\
            if group:isExist() then \\\
                -- see how many members of this group are still alive\\\
                local liveUnits = dcsCommon.getLiveGroupUnits(group)\\\
                -- spawn is still alive, will not spawn\\\
                if #liveUnits > 1 then \\\
                    -- we may want to check if this member is still inside\\\
                    -- of spawn location. currently we don't do that\\\
                    needsSpawn = false \\\
                end\\\
            end\\\
        end\\\
    \\\
        if spawner.paused then needsSpawn = false end \\\
        \\\
        -- see if we spawned maximum number of times already\\\
        -- or have -1 as maxspawn, indicating endless\\\
        if needsSpawn and spawner.maxSpawns > -1 then \\\
            needsSpawn = spawner.maxSpawns > 0\\\
        end\\\
        \\\
        if needsSpawn then \\\
            -- is this the first time? \\\
            if not spawner.cdStarted then \\\
                -- no, start cooldown\\\
                spawner.cdStarted = true \\\
                spawner.cdTimer = timer.getTime() + spawner.cooldown\\\
            end\\\
        end\\\
\\\
        -- still on cooldown?\\\
        if timer.getTime() < spawner.cdTimer then needsSpawn = false end \\\
        \\\
        -- is master zone still alinged with me?\\\
        needsSpawn = needsSpawn and cfxSpawnZones.verifySpawnOwnership(spawner)\\\
                \\\
        -- if we get here, and needsSpawn is still set, we go ahead and spawn\\\
        if needsSpawn then \\\
---            trigger.action.outText(\\\"+++ spawning for zone \\\" .. spawner.zone.name, 30)\\\
            cfxSpawnZones.spawnWithSpawner(spawner)\\\
            spawner.cdStarted = false -- reset spawner cd signal \\\
            if spawner.maxSpawns > 0 then \\\
                spawner.maxSpawns = spawner.maxSpawns - 1\\\
            end\\\
            if spawner.maxSpawns == 0 then \\\
                spawner.paused = true \\\
                trigger.action.outText(\\\"+++ maxspawn -- turning off  zone \\\" .. spawner.zone.name, 30)\\\
            end\\\
        else \\\
            -- trigger.action.outText(\\\"+++ NOSPAWN for zone \\\" .. spawner.zone.name, 30)\\\
        end\\\
    end\\\
end\\\
\\\
function cfxSpawnZones.start()\\\
    if not dcsCommon.libCheck(\\\"cfx Spawn Zones\\\", \\\
        cfxSpawnZones.requiredLibs) then\\\
        return false \\\
    end\\\
    \\\
    -- collect all spawn zones \\\
    local attrZones = cfxZones.getZonesWithAttributeNamed(\\\"spawner\\\")\\\
    \\\
    -- now create a spawner for all, add them to the spawner updater, and spawn for all zones that are not\\\
    -- paused \\\
    for k, aZone in pairs(attrZones) do \\\
        local aSpawner = cfxSpawnZones.createSpawner(aZone)\\\
        cfxSpawnZones.addSpawner(aSpawner)\\\
        if not aSpawner.paused and cfxSpawnZones.verifySpawnOwnership(aSpawner) and aSpawner.maxSpawns ~= 0 then \\\
            cfxSpawnZones.spawnWithSpawner(aSpawner)\\\
        end\\\
    end\\\
    \\\
    -- and start the regular update calls\\\
    cfxSpawnZones.update()\\\
    \\\
    trigger.action.outText(\\\"cfx Spawn Zones v\\\" .. cfxSpawnZones.version .. \\\" started.\\\", 30)\\\
    return true\\\
end\\\
\\\
if not cfxSpawnZones.start() then \\\
    trigger.action.outText(\\\"cf/x Spawn Zones aborted: missing libraries\\\", 30)\\\
    cfxSpawnZones = nil \\\
end\\\
\\\
--[[--\\\
IMPROVEMENTS\\\
 'notMasterOwner' a flag to invert ownership, so we can spawn blue if masterOwner is red\\\
  \\\
  take apart owned zone and spawner, so we have a more canonical behaviour\\\
  \\\
  'repair' flag - have repair logic for units that are spawned just like now the owned zones do\\\
--]]--\");a_do_script(\"jtacGrpUI = {}\\\
jtacGrpUI.version = \\\"1.0.2\\\"\\\
--[[-- VERSION HISTORY\\\
 - 1.0.2 - also include idling JTACS\\\
         - add positional info when using owned zones \\\
         \\\
--]]--\\\
-- find & command cfxGroundTroops-based jtacs\\\
-- UI installed via OTHER for all groups with players\\\
-- module based on xxxGrpUI\\\
 \\\
jtacGrpUI.groupConfig = {} -- all inited group private config data \\\
jtacGrpUI.simpleCommands = true -- if true, f10 other invokes directly\\\
\\\
--\\\
-- C O N F I G   H A N D L I N G \\\
-- =============================\\\
--\\\
-- Each group has their own config block that can be used to \\\
-- store group-private data and configuration items.\\\
--\\\
\\\
function jtacGrpUI.resetConfig(conf)\\\
end\\\
\\\
function jtacGrpUI.createDefaultConfig(theGroup)\\\
    local conf = {}\\\
    conf.theGroup = theGroup\\\
    conf.name = theGroup:getName()\\\
    conf.id = theGroup:getID()\\\
    conf.coalition = theGroup:getCoalition() \\\
    \\\
    jtacGrpUI.resetConfig(conf)\\\
\\\
    conf.mainMenu = nil; -- this is where we store the main menu if we branch\\\
    conf.myCommands = nil; -- this is where we store the commands if we branch \\\
    \\\
    return conf\\\
end\\\
\\\
-- getConfigFor group will allocate if doesn't exist in DB\\\
-- and add to it\\\
function jtacGrpUI.getConfigForGroup(theGroup)\\\
    if not theGroup then \\\
        trigger.action.outText(\\\"+++WARNING: jtacGrpUI nil group in getConfigForGroup!\\\", 30)\\\
        return nil \\\
    end\\\
    local theName = theGroup:getName()\\\
    local c = jtacGrpUI.getConfigByGroupName(theName) -- we use central accessor\\\
    if not c then \\\
        c = jtacGrpUI.createDefaultConfig(theGroup)\\\
        jtacGrpUI.groupConfig[theName] = c -- should use central accessor...\\\
    end\\\
    return c \\\
end\\\
\\\
function jtacGrpUI.getConfigByGroupName(theName) -- DOES NOT allocate when not exist\\\
    if not theName then return nil end \\\
    return jtacGrpUI.groupConfig[theName]\\\
end\\\
\\\
\\\
function jtacGrpUI.getConfigForUnit(theUnit)\\\
    -- simple one-off step by accessing the group \\\
    if not theUnit then \\\
        trigger.action.outText(\\\"+++WARNING: jtacGrpUI nil unit in getConfigForUnit!\\\", 30)\\\
        return nil \\\
    end\\\
    \\\
    local theGroup = theUnit:getGroup()\\\
    return getConfigForGroup(theGroup)\\\
end\\\
\\\
--\\\
--\\\
-- M E N U   H A N D L I N G \\\
-- =========================\\\
--\\\
--\\\
 function jtacGrpUI.clearCommsSubmenus(conf)\\\
    if conf.myCommands then \\\
        for i=1, #conf.myCommands do\\\
            missionCommands.removeItemForGroup(conf.id, conf.myCommands[i])\\\
        end\\\
    end\\\
    conf.myCommands = {}\\\
end\\\
\\\
function jtacGrpUI.removeCommsFromConfig(conf)\\\
    jtacGrpUI.clearCommsSubmenus(conf)\\\
    \\\
    if conf.myMainMenu then \\\
        missionCommands.removeItemForGroup(conf.id, conf.myMainMenu) \\\
        conf.myMainMenu = nil\\\
    end\\\
end\\\
\\\
-- this only works in single-unit groups. may want to check if group \\\
-- has disappeared\\\
function jtacGrpUI.removeCommsForUnit(theUnit)\\\
    if not theUnit then return end\\\
    if not theUnit:isExist() then return end     \\\
    -- perhaps add code: check if group is empty\\\
    local conf = jtacGrpUI.getConfigForUnit(theUnit)\\\
    jtacGrpUI.removeCommsFromConfig(conf)\\\
end\\\
\\\
function jtacGrpUI.removeCommsForGroup(theGroup)\\\
    if not theGroup then return end\\\
    if not theGroup:isExist() then return end     \\\
    local conf = jtacGrpUI.getConfigForGroup(theGroup)\\\
    jtacGrpUI.removeCommsFromConfig(conf)\\\
end\\\
\\\
--\\\
-- set main root in F10 Other. All sub menus click into this \\\
--\\\
function jtacGrpUI.isEligibleForMenu(theGroup)\\\
    return true\\\
end\\\
\\\
function jtacGrpUI.setCommsMenuForUnit(theUnit)\\\
    if not theUnit then \\\
        trigger.action.outText(\\\"+++WARNING: jtacGrpUI nil UNIT in setCommsMenuForUnit!\\\", 30)\\\
        return\\\
    end\\\
    if not theUnit:isExist() then return end \\\
    \\\
    local theGroup = theUnit:getGroup()\\\
    jtacGrpUI.setCommsMenu(theGroup)\\\
end\\\
\\\
function jtacGrpUI.setCommsMenu(theGroup)\\\
    -- depending on own load state, we set the command structure\\\
    -- it begins at 10-other, and has 'jtac' as main menu with submenus\\\
    -- as required \\\
    if not theGroup then return end\\\
    if not theGroup:isExist() then return end \\\
    \\\
    -- we test here if this group qualifies for \\\
    -- the menu. if not, exit \\\
    if not jtacGrpUI.isEligibleForMenu(theGroup) then return end\\\
    \\\
    local conf = jtacGrpUI.getConfigForGroup(theGroup) \\\
    conf.id = theGroup:getID(); -- we do this ALWAYS so it is current even after a crash \\\
--    trigger.action.outText(\\\"+++ setting group <\\\".. conf.theGroup:getName() .. \\\"> jtac command\\\", 30)\\\
    \\\
    if jtacGrpUI.simpleCommands then \\\
        -- we install directly in F-10 other \\\
        if not conf.myMainMenu then \\\
            local commandTxt = \\\"jtac Lasing Report\\\"\\\
            local theCommand =  missionCommands.addCommandForGroup(\\\
                conf.id, \\\
                commandTxt,\\\
                nil,\\\
                jtacGrpUI.redirectCommandX, \\\
                {conf, \\\"lasing report\\\"}\\\
                )\\\
            conf.myMainMenu = theCommand\\\
        end\\\
        \\\
        return \\\
    end\\\
    \\\
    \\\
    -- ok, first, if we don't have an F-10 menu, create one \\\
    if not (conf.myMainMenu) then \\\
        conf.myMainMenu = missionCommands.addSubMenuForGroup(conf.id, 'jtac') \\\
    end\\\
    \\\
    -- clear out existing commands\\\
    jtacGrpUI.clearCommsSubmenus(conf)\\\
    \\\
    -- now we have a menu without submenus. \\\
    -- add our own submenus\\\
    jtacGrpUI.addSubMenus(conf)\\\
    \\\
end\\\
\\\
function jtacGrpUI.addSubMenus(conf)\\\
    -- add menu items to choose from after \\\
    -- user clickedf on MAIN MENU. In this implementation\\\
    -- they all result invoked methods\\\
    \\\
    \\\
    \\\
    local commandTxt = \\\"jtac Lasing Report\\\"\\\
    local theCommand =  missionCommands.addCommandForGroup(\\\
                conf.id, \\\
                commandTxt,\\\
                conf.myMainMenu,\\\
                jtacGrpUI.redirectCommandX, \\\
                {conf, \\\"lasing report\\\"}\\\
                )\\\
    table.insert(conf.myCommands, theCommand)\\\
--[[--\\\
    commandTxt = \\\"This is another important command\\\"\\\
    theCommand =  missionCommands.addCommandForGroup(\\\
                conf.id, \\\
                commandTxt,\\\
                conf.myMainMenu,\\\
                jtacGrpUI.redirectCommandX, \\\
                {conf, \\\"Sub2\\\"}\\\
                )\\\
    table.insert(conf.myCommands, theCommand)\\\
--]]--\\\
end\\\
\\\
--\\\
-- each menu item has a redirect and timed invoke to divorce from the\\\
-- no-debug zone in the menu invocation. Delay is .1 seconds\\\
--\\\
\\\
function jtacGrpUI.redirectCommandX(args)\\\
    timer.scheduleFunction(jtacGrpUI.doCommandX, args, timer.getTime() + 0.1)\\\
end\\\
\\\
function jtacGrpUI.doCommandX(args)\\\
    local conf = args[1] -- < conf in here\\\
    local what = args[2] -- < second argument in here\\\
    local theGroup = conf.theGroup\\\
--    trigger.action.outTextForGroup(conf.id, \\\"+++ groupUI: processing comms menu for <\\\" .. what .. \\\">\\\", 30)\\\
    local targetList = jtacGrpUI.collectJTACtargets(conf, true)\\\
    -- iterate the list\\\
    if #targetList < 1 then \\\
        trigger.action.outTextForGroup(conf.id, \\\"No targets are currently being lased\\\", 30)\\\
        return \\\
    end\\\
    \\\
    local desc = \\\"JTAC Target Report:\\\\n\\\"\\\
--    trigger.action.outTextForGroup(conf.id, \\\"Target Report:\\\", 30)\\\
    for i=1, #targetList do \\\
        local aTarget = targetList[i]\\\
        if aTarget.idle then \\\
            desc = desc .. \\\"\\\\n\\\" .. aTarget.jtacName .. aTarget.posInfo ..\\\": no target\\\"\\\
        else \\\
            desc = desc .. \\\"\\\\n\\\" .. aTarget.jtacName .. aTarget.posInfo ..\\\" lasing \\\" .. aTarget.lazeTargetType .. \\\" [\\\" .. aTarget.range .. \\\"nm at \\\" .. aTarget.bearing .. \\\"°]\\\"\\\
        end \\\
    end\\\
    trigger.action.outTextForGroup(conf.id, desc .. \\\"\\\\n\\\", 30)\\\
end\\\
\\\
function jtacGrpUI.collectJTACtargets(conf, includeIdle)\\\
    -- iterate cfxGroundTroops.deployedTroops to retrieve all \\\
    -- troops that are lazing. 'Lazing' are all groups that \\\
    -- have an active (non-nil) lazeTarget and 'laze' orders\\\
    if not includeIdle then includeIdle = false end \\\
    \\\
    local theJTACS = {}\\\
    for idx, troop in pairs(cfxGroundTroops.deployedTroops) do \\\
        if troop.coalition == conf.coalition\\\
         and troop.orders == \\\"laze\\\" \\\
         and troop.lazeTarget \\\
         and troop.lazeTarget:isExist() \\\
        then \\\
            table.insert(theJTACS, troop)\\\
        elseif troop.coalition == conf.coalition \\\
         and troop.orders == \\\"laze\\\"\\\
         and includeIdle\\\
        then \\\
            -- we also include idlers\\\
            table.insert(theJTACS, troop)\\\
        end\\\
    end\\\
    \\\
    -- we now have a list of all ground troops that are lazing.\\\
    -- get bearing and range to targets, and sort them accordingly\\\
    local targetList = {}\\\
    local here = dcsCommon.getGroupLocation(conf.theGroup) -- this is me\\\
    \\\
    for idx, troop in pairs (theJTACS) do\\\
        local aTarget = {}\\\
        -- establish our location \\\
        aTarget.jtacName = troop.name \\\
        aTarget.posInfo = \\\"\\\"\\\
        if cfxOwnedZones and cfxOwnedZones.hasOwnedZones() then \\\
            local jtacLoc = dcsCommon.getGroupLocation(troop.group)\\\
            local nearestZone = cfxOwnedZones.getNearestOwnedZoneToPoint(jtacLoc)\\\
            if nearestZone then \\\
                local ozRange = dcsCommon.dist(jtacLoc, nearestZone.point) * 0.000621371\\\
                ozRange = math.floor(ozRange * 10) / 10\\\
                local relPos = dcsCommon.compassPositionOfARelativeToB(jtacLoc, nearestZone.point)\\\
                aTarget.posInfo = \\\" (\\\" .. ozRange .. \\\"nm \\\" .. relPos .. \\\" of \\\" .. nearestZone.name .. \\\")\\\"\\\
            end\\\
        end\\\
        -- we may get idlers, catch them now \\\
        if not troop.lazeTarget then \\\
            aTarget.idle = true\\\
            aTarget.range = math.huge\\\
        else \\\
            -- get the target we are lazing \\\
            local there = troop.lazeTarget:getPoint()\\\
            aTarget.idle = false\\\
            aTarget.range = dcsCommon.dist(here, there)\\\
            aTarget.range = aTarget.range * 0.000621371 -- meter to miles \\\
            aTarget.range = math.floor(aTarget.range * 10) / 10\\\
            aTarget.bearing = dcsCommon.bearingInDegreesFromAtoB(here, there)\\\
            --aTarget.jtacName = troop.name \\\
            aTarget.lazeTargetType = troop.lazeTargetType\\\
        end\\\
        table.insert(targetList, aTarget)\\\
    end\\\
    \\\
    -- now sort by range \\\
    table.sort(targetList, function (left, right) return left.range < right.range end )\\\
    \\\
    -- return list sorted by distance\\\
    return targetList\\\
end\\\
\\\
--\\\
-- G R O U P   M A N A G E M E N T \\\
--\\\
-- Group Management is required to make sure all groups\\\
-- receive a comms menu and that they receive a clean-up \\\
-- when required \\\
--\\\
-- Callbacks are provided by cfxPlayer module to which we\\\
-- subscribe during init \\\
--\\\
function jtacGrpUI.playerChangeEvent(evType, description, player, data)\\\
    --trigger.action.outText(\\\"+++ groupUI: received <\\\".. evType .. \\\"> Event\\\", 30)\\\
    if evType == \\\"newGroup\\\" then \\\
        -- initialized attributes are in data as follows\\\
        --   .group - new group \\\
        --   .name - new group's name \\\
        --   .primeUnit - the unit that trigggered new group appearing \\\
        --   .primeUnitName - name of prime unit \\\
        --   .id group ID \\\
        --theUnit = data.primeUnit\\\
        jtacGrpUI.setCommsMenu(data.group)\\\
--        trigger.action.outText(\\\"+++ groupUI: added \\\" .. theUnit:getName() .. \\\" to comms menu\\\", 30)\\\
        return \\\
    end\\\
    \\\
    if evType == \\\"removeGroup\\\" then \\\
        -- data is the player record that no longer exists. it consists of\\\
        --  .name \\\
        -- we must remove the comms menu for this group else we try to add another one to this group later\\\
        local conf = jtacGrpUI.getConfigByGroupName(data.name)\\\
        \\\
        if conf then \\\
            jtacGrpUI.removeCommsFromConfig(conf) -- remove menus \\\
            jtacGrpUI.resetConfig(conf) -- re-init this group for when it re-appears\\\
        else \\\
            trigger.action.outText(\\\"+++ jtacUI: can't retrieve group <\\\" .. data.name .. \\\"> config: not found!\\\", 30)\\\
        end\\\
        \\\
        return\\\
    end\\\
    \\\
    if evType == \\\"leave\\\" then\\\
        -- player unit left. we don't care since we only work on group level\\\
        -- if they were the only, this is followed up by group disappeared \\\
        \\\
    end\\\
    \\\
    if evType == \\\"unit\\\" then \\\
        -- player changed units. almost never in MP, but possible in solo\\\
        -- because of 1 seconds timing loop \\\
        -- will result in a new group appearing and a group disappearing, so we are good\\\
        -- may need some logic to clean up old configs and/or menu items \\\
\\\
    end\\\
    \\\
end\\\
\\\
--\\\
-- Start \\\
--\\\
function jtacGrpUI.start()\\\
\\\
    -- iterate existing groups so we have a start situation\\\
    -- now iterate through all player groups and install the Assault Troop Menu\\\
    allPlayerGroups = cfxPlayerGroups -- cfxPlayerGroups is a global, don't fuck with it! \\\
    -- contains per group player record. Does not resolve on unit level!\\\
    for gname, pgroup in pairs(allPlayerGroups) do \\\
        local theUnit = pgroup.primeUnit -- get any unit of that group\\\
        jtacGrpUI.setCommsMenuForUnit(theUnit) -- set up\\\
    end\\\
    -- now install the new group notifier to install Assault Troops menu\\\
    \\\
    cfxPlayer.addMonitor(jtacGrpUI.playerChangeEvent)\\\
    trigger.action.outText(\\\"cf/x jtacGrpUI v\\\" .. jtacGrpUI.version .. \\\" started\\\", 30)\\\
    \\\
end\\\
\\\
--\\\
-- GO GO GO \\\
--\\\
if not cfxGroundTroops then \\\
    trigger.action.outText(\\\"cf/x jtacGrpUI REQUIRES cfxGroundTroops to work.\\\", 30)\\\
else \\\
    jtacGrpUI.start()\\\
end\");",
        }, -- end of ["actions"]
        ["events"] = 
        {
        }, -- end of ["events"]
        ["custom"] = 
        {
        }, -- end of ["custom"]
        ["func"] = 
        {
        }, -- end of ["func"]
        ["flag"] = 
        {
            [1] = true,
        }, -- end of ["flag"]
        ["conditions"] = 
        {
            [1] = "return(true)",
        }, -- end of ["conditions"]
        ["customStartup"] = 
        {
        }, -- end of ["customStartup"]
        ["funcStartup"] = 
        {
            [1] = "if mission.trig.conditions[1]() then mission.trig.actions[1]() end",
        }, -- end of ["funcStartup"]
    }, -- end of ["trig"]
    ["requiredModules"] = 
    {
    }, -- end of ["requiredModules"]
    ["date"] = 
    {
        ["Year"] = 2016,
        ["Day"] = 21,
        ["Month"] = 6,
    }, -- end of ["date"]
    ["result"] = 
    {
        ["offline"] = 
        {
            ["conditions"] = 
            {
            }, -- end of ["conditions"]
            ["actions"] = 
            {
            }, -- end of ["actions"]
            ["func"] = 
            {
            }, -- end of ["func"]
        }, -- end of ["offline"]
        ["total"] = 0,
        ["blue"] = 
        {
            ["conditions"] = 
            {
            }, -- end of ["conditions"]
            ["actions"] = 
            {
            }, -- end of ["actions"]
            ["func"] = 
            {
            }, -- end of ["func"]
        }, -- end of ["blue"]
        ["red"] = 
        {
            ["conditions"] = 
            {
            }, -- end of ["conditions"]
            ["actions"] = 
            {
            }, -- end of ["actions"]
            ["func"] = 
            {
            }, -- end of ["func"]
        }, -- end of ["red"]
    }, -- end of ["result"]
    ["groundControl"] = 
    {
        ["isPilotControlVehicles"] = false,
        ["roles"] = 
        {
            ["artillery_commander"] = 
            {
                ["neutrals"] = 0,
                ["blue"] = 0,
                ["red"] = 0,
            }, -- end of ["artillery_commander"]
            ["instructor"] = 
            {
                ["neutrals"] = 0,
                ["blue"] = 0,
                ["red"] = 0,
            }, -- end of ["instructor"]
            ["observer"] = 
            {
                ["neutrals"] = 0,
                ["blue"] = 0,
                ["red"] = 0,
            }, -- end of ["observer"]
            ["forward_observer"] = 
            {
                ["neutrals"] = 0,
                ["blue"] = 0,
                ["red"] = 0,
            }, -- end of ["forward_observer"]
        }, -- end of ["roles"]
    }, -- end of ["groundControl"]
    ["maxDictId"] = 5,
    ["pictureFileNameN"] = 
    {
    }, -- end of ["pictureFileNameN"]
    ["goals"] = 
    {
    }, -- end of ["goals"]
    ["descriptionNeutralsTask"] = "DictKey_descriptionNeutralsTask_4",
    ["weather"] = 
    {
        ["atmosphere_type"] = 0,
        ["groundTurbulence"] = 0,
        ["enable_fog"] = false,
        ["wind"] = 
        {
            ["at8000"] = 
            {
                ["speed"] = 0,
                ["dir"] = 0,
            }, -- end of ["at8000"]
            ["at2000"] = 
            {
                ["speed"] = 0,
                ["dir"] = 0,
            }, -- end of ["at2000"]
            ["atGround"] = 
            {
                ["speed"] = 0,
                ["dir"] = 0,
            }, -- end of ["atGround"]
        }, -- end of ["wind"]
        ["enable_dust"] = false,
        ["season"] = 
        {
            ["temperature"] = 20,
        }, -- end of ["season"]
        ["type_weather"] = 0,
        ["qnh"] = 760,
        ["cyclones"] = 
        {
        }, -- end of ["cyclones"]
        ["name"] = "Winter, clean sky",
        ["dust_density"] = 0,
        ["modifiedTime"] = false,
        ["fog"] = 
        {
            ["thickness"] = 0,
            ["visibility"] = 0,
        }, -- end of ["fog"]
        ["visibility"] = 
        {
            ["distance"] = 80000,
        }, -- end of ["visibility"]
        ["clouds"] = 
        {
            ["thickness"] = 200,
            ["density"] = 0,
            ["preset"] = "Preset2",
            ["base"] = 2500,
            ["iprecptns"] = 0,
        }, -- end of ["clouds"]
    }, -- end of ["weather"]
    ["theatre"] = "Caucasus",
    ["triggers"] = 
    {
        ["zones"] = 
        {
            [1] = 
            {
                ["radius"] = 25,
                ["zoneId"] = 165,
                ["color"] = 
                {
                    [1] = 1,
                    [2] = 1,
                    [3] = 1,
                    [4] = 0.15,
                }, -- end of ["color"]
                ["properties"] = 
                {
                    [1] = 
                    {
                        ["key"] = "spawner",
                        ["value"] = "training BTR",
                    }, -- end of [1]
                    [2] = 
                    {
                        ["key"] = "types",
                        ["value"] = "BTR-80",
                    }, -- end of [2]
                    [3] = 
                    {
                        ["key"] = "typeMult",
                        ["value"] = "6",
                    }, -- end of [3]
                    [4] = 
                    {
                        ["key"] = "country",
                        ["value"] = "0",
                    }, -- end of [4]
                    [5] = 
                    {
                        ["key"] = "baseName",
                        ["value"] = "BTRs",
                    }, -- end of [5]
                    [6] = 
                    {
                        ["key"] = "orders",
                        ["value"] = "training",
                    }, -- end of [6]
                    [7] = 
                    {
                        ["key"] = "cooldown",
                        ["value"] = "60",
                    }, -- end of [7]
                    [8] = 
                    {
                        ["key"] = "formation",
                        ["value"] = "2cols",
                    }, -- end of [8]
                    [9] = 
                    {
                        ["key"] = "heading",
                        ["value"] = "88",
                    }, -- end of [9]
                }, -- end of ["properties"]
                ["hidden"] = false,
                ["y"] = 694278.47377826,
                ["x"] = -275570.29579698,
                ["name"] = "Spawn BTR",
                ["type"] = 0,
            }, -- end of [1]
            [2] = 
            {
                ["radius"] = 30,
                ["zoneId"] = 166,
                ["color"] = 
                {
                    [1] = 1,
                    [2] = 1,
                    [3] = 1,
                    [4] = 0.15,
                }, -- end of ["color"]
                ["properties"] = 
                {
                    [1] = 
                    {
                        ["key"] = "spawner",
                        ["value"] = "training Leo",
                    }, -- end of [1]
                    [2] = 
                    {
                        ["key"] = "types",
                        ["value"] = "Leopard-2",
                    }, -- end of [2]
                    [3] = 
                    {
                        ["key"] = "typeMult",
                        ["value"] = "9",
                    }, -- end of [3]
                    [4] = 
                    {
                        ["key"] = "country",
                        ["value"] = "0",
                    }, -- end of [4]
                    [5] = 
                    {
                        ["key"] = "baseName",
                        ["value"] = "Leos",
                    }, -- end of [5]
                    [6] = 
                    {
                        ["key"] = "orders",
                        ["value"] = "training",
                    }, -- end of [6]
                    [7] = 
                    {
                        ["key"] = "cooldown",
                        ["value"] = "60",
                    }, -- end of [7]
                    [8] = 
                    {
                        ["key"] = "formation",
                        ["value"] = "rect",
                    }, -- end of [8]
                    [9] = 
                    {
                        ["key"] = "heading",
                        ["value"] = "270",
                    }, -- end of [9]
                }, -- end of ["properties"]
                ["hidden"] = false,
                ["y"] = 695182.00362737,
                ["x"] = -275537.48082424,
                ["name"] = "Spawn Leos",
                ["type"] = 0,
            }, -- end of [2]
            [3] = 
            {
                ["radius"] = 30,
                ["zoneId"] = 331,
                ["color"] = 
                {
                    [1] = 1,
                    [2] = 1,
                    [3] = 1,
                    [4] = 0.15,
                }, -- end of ["color"]
                ["properties"] = 
                {
                    [1] = 
                    {
                        ["key"] = "spawner",
                        ["value"] = "JTAC",
                    }, -- end of [1]
                    [2] = 
                    {
                        ["key"] = "types",
                        ["value"] = "Soldier M4",
                    }, -- end of [2]
                    [3] = 
                    {
                        ["key"] = "typeMult",
                        ["value"] = "4",
                    }, -- end of [3]
                    [4] = 
                    {
                        ["key"] = "country",
                        ["value"] = "2",
                    }, -- end of [4]
                    [5] = 
                    {
                        ["key"] = "baseName",
                        ["value"] = "JTAC",
                    }, -- end of [5]
                    [6] = 
                    {
                        ["key"] = "orders",
                        ["value"] = "laze",
                    }, -- end of [6]
                    [7] = 
                    {
                        ["key"] = "cooldown",
                        ["value"] = "60",
                    }, -- end of [7]
                    [8] = 
                    {
                        ["key"] = "heading",
                        ["value"] = "30",
                    }, -- end of [8]
                    [9] = 
                    {
                        ["key"] = "range",
                        ["value"] = "3000",
                    }, -- end of [9]
                    [10] = 
                    {
                        ["key"] = "maxSpawns",
                        ["value"] = "1",
                    }, -- end of [10]
                }, -- end of ["properties"]
                ["hidden"] = false,
                ["y"] = 694686.02521787,
                ["x"] = -275204.36180804,
                ["name"] = "JTAC Spawn",
                ["type"] = 0,
            }, -- end of [3]
            [4] = 
            {
                ["radius"] = 5,
                ["zoneId"] = 497,
                ["color"] = 
                {
                    [1] = 1,
                    [2] = 1,
                    [3] = 1,
                    [4] = 0.15,
                }, -- end of ["color"]
                ["properties"] = 
                {
                    [1] = 
                    {
                        ["key"] = "spawner",
                        ["value"] = "gas platform",
                    }, -- end of [1]
                    [2] = 
                    {
                        ["key"] = "types",
                        ["value"] = "Soldier M4",
                    }, -- end of [2]
                    [3] = 
                    {
                        ["key"] = "typeMult",
                        ["value"] = "6",
                    }, -- end of [3]
                    [4] = 
                    {
                        ["key"] = "country",
                        ["value"] = "2",
                    }, -- end of [4]
                    [5] = 
                    {
                        ["key"] = "baseName",
                        ["value"] = "gassers",
                    }, -- end of [5]
                }, -- end of ["properties"]
                ["hidden"] = false,
                ["y"] = 439298.81850578,
                ["x"] = -153547.18402581,
                ["name"] = "Gas Platform Spawn",
                ["type"] = 0,
            }, -- end of [4]
        }, -- end of ["zones"]
    }, -- end of ["triggers"]
    ["map"] = 
    {
        ["centerY"] = 693585.87576384,
        ["zoom"] = 12891.931337386,
        ["centerX"] = -275868.30564374,
    }, -- end of ["map"]
    ["coalitions"] = 
    {
        ["blue"] = 
        {
            [1] = 21,
            [2] = 11,
            [3] = 8,
            [4] = 80,
            [5] = 28,
            [6] = 26,
            [7] = 13,
            [8] = 5,
            [9] = 16,
            [10] = 6,
            [11] = 15,
            [12] = 20,
            [13] = 12,
            [14] = 40,
            [15] = 45,
            [16] = 9,
            [17] = 46,
            [18] = 10,
            [19] = 3,
            [20] = 4,
            [21] = 1,
            [22] = 2,
        }, -- end of ["blue"]
        ["neutrals"] = 
        {
            [1] = 70,
            [2] = 83,
            [3] = 23,
            [4] = 65,
            [5] = 86,
            [6] = 64,
            [7] = 25,
            [8] = 63,
            [9] = 76,
            [10] = 84,
            [11] = 29,
            [12] = 62,
            [13] = 30,
            [14] = 78,
            [15] = 87,
            [16] = 31,
            [17] = 61,
            [18] = 32,
            [19] = 33,
            [20] = 60,
            [21] = 17,
            [22] = 35,
            [23] = 69,
            [24] = 36,
            [25] = 59,
            [26] = 71,
            [27] = 79,
            [28] = 58,
            [29] = 57,
            [30] = 56,
            [31] = 55,
            [32] = 88,
            [33] = 73,
            [34] = 39,
            [35] = 89,
            [36] = 54,
            [37] = 77,
            [38] = 72,
            [39] = 41,
            [40] = 42,
            [41] = 44,
            [42] = 85,
            [43] = 75,
            [44] = 53,
            [45] = 22,
            [46] = 52,
            [47] = 66,
            [48] = 51,
            [49] = 74,
            [50] = 82,
            [51] = 7,
            [52] = 68,
            [53] = 50,
            [54] = 49,
            [55] = 48,
            [56] = 67,
        }, -- end of ["neutrals"]
        ["red"] = 
        {
            [1] = 18,
            [2] = 24,
            [3] = 27,
            [4] = 81,
            [5] = 34,
            [6] = 37,
            [7] = 38,
            [8] = 0,
            [9] = 43,
            [10] = 19,
            [11] = 47,
        }, -- end of ["red"]
    }, -- end of ["coalitions"]
    ["descriptionText"] = "DictKey_descriptionText_1",
    ["pictureFileNameR"] = 
    {
    }, -- end of ["pictureFileNameR"]
    ["descriptionBlueTask"] = "DictKey_descriptionBlueTask_3",
    ["descriptionRedTask"] = "DictKey_descriptionRedTask_2",
    ["pictureFileNameB"] = 
    {
    }, -- end of ["pictureFileNameB"]
    ["coalition"] = 
    {
        ["blue"] = 
        {
            ["bullseye"] = 
            {
                ["y"] = 617414,
                ["x"] = -291014,
            }, -- end of ["bullseye"]
            ["nav_points"] = 
            {
            }, -- end of ["nav_points"]
            ["name"] = "blue",
            ["country"] = 
            {
                [1] = 
                {
                    ["id"] = 80,
                    ["name"] = "CJTF Blue",
                    ["plane"] = 
                    {
                        ["group"] = 
                        {
                            [1] = 
                            {
                                ["modulation"] = 0,
                                ["tasks"] = 
                                {
                                }, -- end of ["tasks"]
                                ["radioSet"] = false,
                                ["task"] = "Nothing",
                                ["uncontrolled"] = false,
                                ["taskSelected"] = true,
                                ["route"] = 
                                {
                                    ["points"] = 
                                    {
                                        [1] = 
                                        {
                                            ["alt"] = 500,
                                            ["action"] = "Turning Point",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["vnav"] = 1,
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                                ["scale"] = 0,
                                                ["angle"] = 0,
                                                ["vangle"] = 0,
                                                ["steer"] = 2,
                                            }, -- end of ["properties"]
                                            ["speed"] = 125,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                        [1] = 
                                                        {
                                                            ["number"] = 1,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["enabled"] = true,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "EPLRS",
                                                                    ["params"] = 
                                                                    {
                                                                        ["value"] = true,
                                                                        ["groupId"] = 1,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [1]
                                                    }, -- end of ["tasks"]
                                                }, -- end of ["params"]
                                            }, -- end of ["task"]
                                            ["type"] = "Turning Point",
                                            ["ETA"] = 0,
                                            ["ETA_locked"] = true,
                                            ["y"] = 691460.96534144,
                                            ["x"] = -275399.93914757,
                                            ["formation_template"] = "",
                                            ["speed_locked"] = true,
                                        }, -- end of [1]
                                        [2] = 
                                        {
                                            ["alt"] = 200,
                                            ["action"] = "Turning Point",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["vnav"] = 1,
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                                ["scale"] = 0,
                                                ["angle"] = 0,
                                                ["vangle"] = 0,
                                                ["steer"] = 2,
                                            }, -- end of ["properties"]
                                            ["speed"] = 125,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                    }, -- end of ["tasks"]
                                                }, -- end of ["params"]
                                            }, -- end of ["task"]
                                            ["type"] = "Turning Point",
                                            ["ETA"] = 44.722467935624,
                                            ["ETA_locked"] = false,
                                            ["y"] = 695141.19758554,
                                            ["x"] = -275631.50432248,
                                            ["formation_template"] = "",
                                            ["speed_locked"] = true,
                                        }, -- end of [2]
                                    }, -- end of ["points"]
                                }, -- end of ["route"]
                                ["groupId"] = 1,
                                ["hidden"] = false,
                                ["units"] = 
                                {
                                    [1] = 
                                    {
                                        ["alt"] = 500,
                                        ["hardpoint_racks"] = true,
                                        ["alt_type"] = "BARO",
                                        ["livery_id"] = "25th FS Osan AB, Korea (OS)",
                                        ["skill"] = "Client",
                                        ["speed"] = 125,
                                        ["AddPropAircraft"] = 
                                        {
                                        }, -- end of ["AddPropAircraft"]
                                        ["type"] = "A-10C_2",
                                        ["unitId"] = 1,
                                        ["psi"] = -1.6336348345839,
                                        ["y"] = 691460.96534144,
                                        ["x"] = -275399.93914757,
                                        ["name"] = "Hawg One",
                                        ["payload"] = 
                                        {
                                            ["pylons"] = 
                                            {
                                                [1] = 
                                                {
                                                    ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}",
                                                }, -- end of [1]
                                                [2] = 
                                                {
                                                    ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}",
                                                }, -- end of [2]
                                                [3] = 
                                                {
                                                    ["CLSID"] = "{LAU-131x3 - 7 AGR-20A}",
                                                }, -- end of [3]
                                                [4] = 
                                                {
                                                    ["CLSID"] = "{CBU-87}",
                                                }, -- end of [4]
                                                [5] = 
                                                {
                                                    ["CLSID"] = "{5335D97A-35A5-4643-9D9B-026C75961E52}",
                                                }, -- end of [5]
                                                [7] = 
                                                {
                                                    ["CLSID"] = "{5335D97A-35A5-4643-9D9B-026C75961E52}",
                                                }, -- end of [7]
                                                [8] = 
                                                {
                                                    ["CLSID"] = "{CBU-87}",
                                                }, -- end of [8]
                                                [9] = 
                                                {
                                                    ["CLSID"] = "{LAU-131x3 - 7 AGR-20 M282}",
                                                }, -- end of [9]
                                                [10] = 
                                                {
                                                    ["CLSID"] = "{LAU-131 - 7 AGR-20 M282}",
                                                }, -- end of [10]
                                                [11] = 
                                                {
                                                    ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}",
                                                }, -- end of [11]
                                            }, -- end of ["pylons"]
                                            ["fuel"] = 2515,
                                            ["flare"] = 240,
                                            ["ammo_type"] = 1,
                                            ["chaff"] = 240,
                                            ["gun"] = 100,
                                        }, -- end of ["payload"]
                                        ["heading"] = 1.6336348345839,
                                        ["callsign"] = 
                                        {
                                            [1] = 9,
                                            [2] = 1,
                                            [3] = 1,
                                            ["name"] = "Hawg11",
                                        }, -- end of ["callsign"]
                                        ["onboard_num"] = "010",
                                    }, -- end of [1]
                                }, -- end of ["units"]
                                ["y"] = 691460.96534144,
                                ["x"] = -275399.93914757,
                                ["name"] = "Hawg One",
                                ["communication"] = true,
                                ["start_time"] = 0,
                                ["uncontrollable"] = false,
                                ["frequency"] = 251,
                            }, -- end of [1]
                            [2] = 
                            {
                                ["modulation"] = 0,
                                ["tasks"] = 
                                {
                                }, -- end of ["tasks"]
                                ["radioSet"] = false,
                                ["task"] = "CAS",
                                ["uncontrolled"] = false,
                                ["route"] = 
                                {
                                    ["points"] = 
                                    {
                                        [1] = 
                                        {
                                            ["alt"] = 500,
                                            ["action"] = "Turning Point",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 83.333333333333,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                        [1] = 
                                                        {
                                                            ["number"] = 1,
                                                            ["key"] = "CAS",
                                                            ["id"] = "EngageTargets",
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["params"] = 
                                                            {
                                                                ["targetTypes"] = 
                                                                {
                                                                    [1] = "Helicopters",
                                                                    [2] = "Ground Units",
                                                                    [3] = "Light armed ships",
                                                                }, -- end of ["targetTypes"]
                                                                ["priority"] = 0,
                                                            }, -- end of ["params"]
                                                        }, -- end of [1]
                                                        [2] = 
                                                        {
                                                            ["number"] = 2,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["enabled"] = true,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["value"] = 2,
                                                                        ["name"] = 1,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [2]
                                                        [3] = 
                                                        {
                                                            ["number"] = 3,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["enabled"] = true,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["value"] = 1,
                                                                        ["name"] = 3,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [3]
                                                        [4] = 
                                                        {
                                                            ["number"] = 4,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["enabled"] = true,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["variantIndex"] = 2,
                                                                        ["name"] = 5,
                                                                        ["formationIndex"] = 2,
                                                                        ["value"] = 131074,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [4]
                                                        [5] = 
                                                        {
                                                            ["number"] = 5,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["enabled"] = true,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["value"] = true,
                                                                        ["name"] = 15,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [5]
                                                        [6] = 
                                                        {
                                                            ["number"] = 6,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["enabled"] = true,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["targetTypes"] = 
                                                                        {
                                                                        }, -- end of ["targetTypes"]
                                                                        ["name"] = 21,
                                                                        ["value"] = "none;",
                                                                        ["noTargetTypes"] = 
                                                                        {
                                                                            [1] = "Fighters",
                                                                            [2] = "Multirole fighters",
                                                                            [3] = "Bombers",
                                                                            [4] = "Helicopters",
                                                                            [5] = "Infantry",
                                                                            [6] = "Fortifications",
                                                                            [7] = "Tanks",
                                                                            [8] = "IFV",
                                                                            [9] = "APC",
                                                                            [10] = "Artillery",
                                                                            [11] = "Unarmed vehicles",
                                                                            [12] = "AAA",
                                                                            [13] = "SR SAM",
                                                                            [14] = "MR SAM",
                                                                            [15] = "LR SAM",
                                                                            [16] = "Aircraft Carriers",
                                                                            [17] = "Cruisers",
                                                                            [18] = "Destroyers",
                                                                            [19] = "Frigates",
                                                                            [20] = "Corvettes",
                                                                            [21] = "Light armed ships",
                                                                            [22] = "Unarmed ships",
                                                                            [23] = "Submarines",
                                                                            [24] = "Cruise missiles",
                                                                            [25] = "Antiship Missiles",
                                                                            [26] = "AA Missiles",
                                                                            [27] = "AG Missiles",
                                                                            [28] = "SA Missiles",
                                                                        }, -- end of ["noTargetTypes"]
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [6]
                                                        [7] = 
                                                        {
                                                            ["number"] = 7,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["enabled"] = true,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["value"] = true,
                                                                        ["name"] = 19,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [7]
                                                    }, -- end of ["tasks"]
                                                }, -- end of ["params"]
                                            }, -- end of ["task"]
                                            ["type"] = "Turning Point",
                                            ["ETA"] = 0,
                                            ["ETA_locked"] = true,
                                            ["y"] = 691419.61441735,
                                            ["x"] = -275887.88005184,
                                            ["formation_template"] = "",
                                            ["speed_locked"] = true,
                                        }, -- end of [1]
                                        [2] = 
                                        {
                                            ["alt"] = 200,
                                            ["action"] = "Turning Point",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 83.333333333333,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                    }, -- end of ["tasks"]
                                                }, -- end of ["params"]
                                            }, -- end of ["task"]
                                            ["type"] = "Turning Point",
                                            ["ETA"] = 44.722467935624,
                                            ["ETA_locked"] = false,
                                            ["y"] = 695141.19758554,
                                            ["x"] = -275689.39561621,
                                            ["formation_template"] = "",
                                            ["speed_locked"] = true,
                                        }, -- end of [2]
                                    }, -- end of ["points"]
                                }, -- end of ["route"]
                                ["groupId"] = 3,
                                ["hidden"] = false,
                                ["units"] = 
                                {
                                    [1] = 
                                    {
                                        ["alt"] = 500,
                                        ["hardpoint_racks"] = true,
                                        ["alt_type"] = "BARO",
                                        ["livery_id"] = "Algerian AF Desert KU-03",
                                        ["skill"] = "Client",
                                        ["speed"] = 83.333333333333,
                                        ["type"] = "Su-25T",
                                        ["unitId"] = 3,
                                        ["psi"] = -1.517513475237,
                                        ["y"] = 691419.61441735,
                                        ["x"] = -275887.88005184,
                                        ["name"] = "Frogger One",
                                        ["payload"] = 
                                        {
                                            ["pylons"] = 
                                            {
                                                [1] = 
                                                {
                                                    ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82D}",
                                                }, -- end of [1]
                                                [2] = 
                                                {
                                                    ["CLSID"] = "{CBC29BFE-3D24-4C64-B81D-941239D12249}",
                                                }, -- end of [2]
                                                [3] = 
                                                {
                                                    ["CLSID"] = "{79D73885-0801-45a9-917F-C90FE1CE3DFC}",
                                                }, -- end of [3]
                                                [4] = 
                                                {
                                                    ["CLSID"] = "{F789E86A-EE2E-4E6B-B81E-D5E5F903B6ED}",
                                                }, -- end of [4]
                                                [5] = 
                                                {
                                                    ["CLSID"] = "{E92CBFE5-C153-11d8-9897-000476191836}",
                                                }, -- end of [5]
                                                [6] = 
                                                {
                                                    ["CLSID"] = "{B1EF6B0E-3D91-4047-A7A5-A99E7D8B4A8B}",
                                                }, -- end of [6]
                                                [7] = 
                                                {
                                                    ["CLSID"] = "{E92CBFE5-C153-11d8-9897-000476191836}",
                                                }, -- end of [7]
                                                [8] = 
                                                {
                                                    ["CLSID"] = "{F789E86A-EE2E-4E6B-B81E-D5E5F903B6ED}",
                                                }, -- end of [8]
                                                [9] = 
                                                {
                                                    ["CLSID"] = "{79D73885-0801-45a9-917F-C90FE1CE3DFC}",
                                                }, -- end of [9]
                                                [10] = 
                                                {
                                                    ["CLSID"] = "{CBC29BFE-3D24-4C64-B81D-941239D12249}",
                                                }, -- end of [10]
                                                [11] = 
                                                {
                                                    ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82C}",
                                                }, -- end of [11]
                                            }, -- end of ["pylons"]
                                            ["fuel"] = "3790",
                                            ["flare"] = 128,
                                            ["chaff"] = 128,
                                            ["gun"] = 100,
                                        }, -- end of ["payload"]
                                        ["heading"] = 1.517513475237,
                                        ["callsign"] = 
                                        {
                                            [1] = 2,
                                            [2] = 1,
                                            [3] = 1,
                                            ["name"] = "Springfield11",
                                        }, -- end of ["callsign"]
                                        ["onboard_num"] = "011",
                                    }, -- end of [1]
                                }, -- end of ["units"]
                                ["y"] = 691419.61441735,
                                ["x"] = -275887.88005184,
                                ["name"] = "Frogger One",
                                ["communication"] = true,
                                ["start_time"] = 0,
                                ["uncontrollable"] = false,
                                ["frequency"] = 124,
                            }, -- end of [2]
                            [3] = 
                            {
                                ["modulation"] = 0,
                                ["tasks"] = 
                                {
                                }, -- end of ["tasks"]
                                ["radioSet"] = false,
                                ["task"] = "Nothing",
                                ["uncontrolled"] = false,
                                ["taskSelected"] = true,
                                ["route"] = 
                                {
                                    ["points"] = 
                                    {
                                        [1] = 
                                        {
                                            ["alt"] = 500,
                                            ["action"] = "Turning Point",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 125,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                    }, -- end of ["tasks"]
                                                }, -- end of ["params"]
                                            }, -- end of ["task"]
                                            ["type"] = "Turning Point",
                                            ["ETA"] = 0,
                                            ["ETA_locked"] = true,
                                            ["y"] = 691432.83054085,
                                            ["x"] = -276382.02998962,
                                            ["formation_template"] = "",
                                            ["speed_locked"] = true,
                                        }, -- end of [1]
                                        [2] = 
                                        {
                                            ["alt"] = 200,
                                            ["action"] = "Turning Point",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 125,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                    }, -- end of ["tasks"]
                                                }, -- end of ["params"]
                                            }, -- end of ["task"]
                                            ["type"] = "Turning Point",
                                            ["ETA"] = 30.102159103321,
                                            ["ETA_locked"] = false,
                                            ["y"] = 695131.62558105,
                                            ["x"] = -275691.12299155,
                                            ["formation_template"] = "",
                                            ["speed_locked"] = true,
                                        }, -- end of [2]
                                    }, -- end of ["points"]
                                }, -- end of ["route"]
                                ["groupId"] = 4,
                                ["hidden"] = false,
                                ["units"] = 
                                {
                                    [1] = 
                                    {
                                        ["alt"] = 500,
                                        ["hardpoint_racks"] = true,
                                        ["alt_type"] = "BARO",
                                        ["livery_id"] = "104th FS Maryland ANG, Baltimore (MD)",
                                        ["skill"] = "Client",
                                        ["speed"] = 125,
                                        ["AddPropAircraft"] = 
                                        {
                                        }, -- end of ["AddPropAircraft"]
                                        ["type"] = "A-10A",
                                        ["unitId"] = 4,
                                        ["psi"] = -1.3861319815704,
                                        ["y"] = 691432.83054085,
                                        ["x"] = -276382.02998962,
                                        ["name"] = "Hogger One",
                                        ["payload"] = 
                                        {
                                            ["pylons"] = 
                                            {
                                                [1] = 
                                                {
                                                    ["CLSID"] = "ALQ_184",
                                                }, -- end of [1]
                                                [2] = 
                                                {
                                                    ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
                                                }, -- end of [2]
                                                [3] = 
                                                {
                                                    ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}",
                                                }, -- end of [3]
                                                [4] = 
                                                {
                                                    ["CLSID"] = "{5335D97A-35A5-4643-9D9B-026C75961E52}",
                                                }, -- end of [4]
                                                [5] = 
                                                {
                                                    ["CLSID"] = "{5335D97A-35A5-4643-9D9B-026C75961E52}",
                                                }, -- end of [5]
                                                [7] = 
                                                {
                                                    ["CLSID"] = "{5335D97A-35A5-4643-9D9B-026C75961E52}",
                                                }, -- end of [7]
                                                [8] = 
                                                {
                                                    ["CLSID"] = "{5335D97A-35A5-4643-9D9B-026C75961E52}",
                                                }, -- end of [8]
                                                [9] = 
                                                {
                                                    ["CLSID"] = "LAU_88_AGM_65H_3",
                                                }, -- end of [9]
                                                [10] = 
                                                {
                                                    ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
                                                }, -- end of [10]
                                                [11] = 
                                                {
                                                    ["CLSID"] = "LAU-105_2*AIM-9P5",
                                                }, -- end of [11]
                                            }, -- end of ["pylons"]
                                            ["fuel"] = 5029,
                                            ["flare"] = 120,
                                            ["ammo_type"] = 1,
                                            ["chaff"] = 240,
                                            ["gun"] = 100,
                                        }, -- end of ["payload"]
                                        ["heading"] = 1.3861319815704,
                                        ["callsign"] = 
                                        {
                                            [1] = 1,
                                            [2] = 1,
                                            [3] = 1,
                                            ["name"] = "Enfield11",
                                        }, -- end of ["callsign"]
                                        ["onboard_num"] = "012",
                                    }, -- end of [1]
                                }, -- end of ["units"]
                                ["y"] = 691432.83054085,
                                ["x"] = -276382.02998962,
                                ["name"] = "Hogger One",
                                ["communication"] = true,
                                ["start_time"] = 0,
                                ["uncontrollable"] = false,
                                ["frequency"] = 124,
                            }, -- end of [3]
                        }, -- end of ["group"]
                    }, -- end of ["plane"]
                }, -- end of [1]
            }, -- end of ["country"]
        }, -- end of ["blue"]
        ["neutrals"] = 
        {
            ["bullseye"] = 
            {
                ["y"] = 0,
                ["x"] = 0,
            }, -- end of ["bullseye"]
            ["nav_points"] = 
            {
            }, -- end of ["nav_points"]
            ["name"] = "neutrals",
            ["country"] = 
            {
            }, -- end of ["country"]
        }, -- end of ["neutrals"]
        ["red"] = 
        {
            ["bullseye"] = 
            {
                ["y"] = 371700,
                ["x"] = 11557,
            }, -- end of ["bullseye"]
            ["nav_points"] = 
            {
            }, -- end of ["nav_points"]
            ["name"] = "red",
            ["country"] = 
            {
            }, -- end of ["country"]
        }, -- end of ["red"]
    }, -- end of ["coalition"]
    ["sortie"] = "DictKey_sortie_5",
    ["version"] = 20,
    ["trigrules"] = 
    {
        [1] = 
        {
            ["rules"] = 
            {
            }, -- end of ["rules"]
            ["eventlist"] = "",
            ["actions"] = 
            {
                [1] = 
                {
                    ["text"] = "dcsCommon = {}\
dcsCommon.version = \"2.4.9\"\
--[[-- VERSION HISTORY\
 2.2.6 - compassPositionOfARelativeToB\
       - clockPositionOfARelativeToB\
 2.2.7 - isTroopCarrier \
       - distFlat\
 2.2.8 - fixed event2text \
 2.2.9 - getUnitAGL\
       - getUnitAlt\
       - getUnitSpeed \
       - getUnitHeading\
       - getUnitHeadingDegrees\
       - mag\
       - clockPositionOfARelativeToB with own heading \
 2.3.0 - unitIsInfantry\
 2.3.1 - bool2YesNo\
       - bool2Text\
 2.3.2 - getGroupAvgSpeed\
       - getGroupMaxSpeed\
 2.3.3 - getSizeOfTable\
 2.3.4 - isSceneryObject\
         coalition2county\
 2.3.5 - smallRandom\
         pickRandom uses smallRandom\
         airfield handling, parking \
         flight waypoint handling\
         landing waypoint creation\
         take-off waypoint creation\
 2.3.6 - createOverheadAirdromeRoutPintData(aerodrome)\
 2.3.7 - coalition2county - warning when creating UN \
 2.3.8 - improved headingOfBInDegrees, new getClockDirection\
 2.3.9 - getClosingVelocity\
       - dot product \
       - magSquare\
       - vMag\
 2.4.0 - libCheck\
 2.4.1 - grid/square/rect formation \
       - arrangeGroupInNColumns formation \
       - 2Columns formation deep and wide formation\
 2.4.2 - getAirbasesInRangeOfPoint\
 2.4.3 - lerp \
 2.4.4 - getClosestAirbaseTo\
       - fixed bug in containsString when strings equal\
 2.4.5 - added cargo and mass options to createStaticObjectData\
 2.4.6 - fixed randompercent \
 2.4.7 - smokeColor2Num(smokeColor)\
 2.4.8 - linkStaticDataToUnit()\
 2.4.9 - trim functions \
       - createGroundUnitData uses trim function to remove leading/trailing blanks\
         so now we can use blanks after comma to separate types \
       - dcsCommon.trimArray(\
       - createStaticObjectData uses trim for type \
       - getEnemyCoalitionFor understands strings, still returns number\
       - coalition2county also undertsands 'red' and 'blue'       \
--]]--\
\
    -- dcsCommon is a library of common lua functions \
    -- for easy access and simple mission programming\
    -- (c) 2021 by Chritian Franz and cf/x AG\
\
    dcsCommon.verbose = false -- set to true to see debug messages. Lots of them\
    dcsCommon.uuidStr = \"uuid-\"\
\
    -- globals\
    dcsCommon.cbID = 0 -- callback id for simple callback scheduling\
    dcsCommon.troopCarriers = {\"Mi-8MT\", \"UH-1H\", \"Mi-24P\"} -- Ka-50 and Gazelle can't carry troops\
\
    -- verify that a module is loaded. obviously not required\
    -- for dcsCommon, but all higher-order modules\
    function dcsCommon.libCheck(testingFor, requiredLibs)\
        local canRun = true \
        for idx, libName in pairs(requiredLibs) do \
            if not _G[libName] then \
                trigger.action.outText(\"*** \" .. testingFor .. \" requires \" .. libName, 30)\
                canRun = false \
            end\
        end\
        return canRun\
    end\
\
    -- taken inspiration from mist, as dcs lua has issues with\
    -- random numbers smaller than 50. Given a range of x numbers 1..x, it is \
    -- repeated a number of times until it fills an array of at least \
    -- 50 items (usually some more), and only then one itemis picked from \
    -- that array with a random number that is from a greater range (0..50+)\
    function dcsCommon.smallRandom(theNum) -- adapted from mist, only support ints\
        if theNum >= 50 then return math.random(theNum) end\
        \
        -- for small randoms (<50) \
        local lowNum, highNum\
        highNum = theNum\
        lowNum = 1\
        local total = 1\
        if math.abs(highNum - lowNum + 1) < 50 then -- if total values is less than 50\
            total = math.modf(50/math.abs(highNum - lowNum + 1)) -- number of times to repeat whole range to get above 50. e.g. 11 would be 5 times 1 .. 11, giving us 55 items total \
        end\
        local choices = {}\
        for i = 1, total do -- iterate required number of times\
            for x = lowNum, highNum do -- iterate between the range\
                choices[#choices +1] = x -- add each entry to a table\
            end\
        end\
        local rtnVal; -- = math.random(#choices) -- will now do a math.random of at least 50 choices\
        for i = 1, 15 do\
            rtnVal = math.random(#choices) -- iterate 15 times for randomization\
        end\
        return choices[rtnVal] -- return indexed\
    end\
    \
\
    function dcsCommon.getSizeOfTable(theTable)\
        local count = 0\
        for _ in pairs(theTable) do count = count + 1 end\
        return count\
    end\
\
    function dcsCommon.findAndRemoveFromTable(theTable, theElement) -- assumes array \
        if not theElement then return false end \
        if not theTable then return false end \
        for i=1, #theTable do \
            if theTable[i] == theElement then \
                -- this element found. remove from table \
                table.remove(theTable, i)\
                return true \
            end\
        end\
    end\
\
    function dcsCommon.pickRandom(theTable)\
        if not theTable then \
            trigger.action.outText(\"*** warning: nil table in pick random\", 30)\
        end\
        \
        if #theTable < 1 then \
            trigger.action.outText(\"*** warning: zero choice in pick random\", 30)\
            local k = i.ll \
            return nil\
        end\
        if #theTable == 1 then return theTable[1] end\
        r = dcsCommon.smallRandom(#theTable) --r = math.random(#theTable)\
        return theTable[r]\
    end\
\
    -- enumerateTable - make an array out of a table for indexed access\
    function dcsCommon.enumerateTable(theTable)\
        if not theTable then theTable = {} end\
        local array = {}\
        for key, value in pairs(theTable) do \
            table.insert(array, value)\
        end\
        return array\
    end\
\
-- \
-- A I R F I E L D S  A N D  F A R P S  \
--\
\
    -- airfield management \
    function dcsCommon.getAirbaseCat(aBase)\
        if not aBase then return nil end \
        \
        local airDesc = aBase:getDesc()\
        if not airDesc then return nil end \
        \
        local airCat = airDesc.category\
        return airCat \
    end\
\
    -- get free parking slot. optional parkingType can be used to \
    -- filter for a scpecific type, e.g. 104 = open field\
    function dcsCommon.getFirstFreeParkingSlot(aerodrome, parkingType) \
        if not aerodrome then return nil end \
        local freeSlots = aerodrome:getParking(true)\
        \
        for idx, theSlot in pairs(freeSlots) do \
            if not parkingType then \
                -- simply return the first we come across\
                return theSlot\
            end        \
            \
            if theSlot.Term_Type == parkingType then \
                return theSlot \
            end\
        end\
        \
        return nil \
    end\
\
    -- getAirbasesInRangeOfPoint: get airbases that are in range of point \
    function dcsCommon.getAirbasesInRangeOfPoint(center, range, filterCat, filterCoalition)\
        if not center then return {} end \
        if not range then range = 500 end -- 500m default \
        local basesInRange = {}\
        \
        local allAB = dcsCommon.getAirbasesWhoseNameContains(\"*\", filterCat, filterCoalition)\
        for idx, aBase in pairs(allAB) do             \
            local delta = dcsCommon.dist(center, aBase:getPoint())\
            if delta <= range then \
                table.insert(basesInRange, aBase)\
            end\
        end\
        return basesInRange\
    end\
\
    -- getAirbasesInRangeOfAirbase returns all airbases that \
    -- are in range of the given airbase \
    function dcsCommon.getAirbasesInRangeOfAirbase(airbase, includeCenter, range, filterCat, filterCoalition)\
        if not airbase then return {} end\
        if not range then range = 150000 end \
        local center = airbase:getPoint() \
        local centerName = airbase:getName() \
        \
        local ABinRange = {}\
        local allAB = dcsCommon.getAirbasesWhoseNameContains(\"*\", filterCat, filterCoalition)\
        \
        for idx, aBase in pairs(allAB) do \
            if aBase:getName() ~= centerName then \
                local delta = dcsCommon.dist(center, aBase:getPoint())\
                if delta <= range then \
                    table.insert(ABinRange, aBase)\
                end\
            end        \
        end\
        \
        if includeCenter then \
            table.insert(ABinRange, airbase)\
        end\
        \
        return ABinRange\
    end\
\
    function dcsCommon.getAirbasesInRangeOfAirbaseList(theCenterList, includeList, range, filterCat, filterCoalition)\
        local collectorDict = {}\
        for idx, aCenter in pairs(theCenterList) do \
            -- get all surrounding airbases. returns list of airfields \
            local surroundingAB = dcsCommon.getAirbasesInRangeOfAirbase(airbase, includeList, range, filterCat, filterCoalition)\
            \
            for idx2, theAirField in pairs (surroundingAB) do \
                collectorDict[airField] = theAirField \
            end\
        end\
        \
        -- make result an array\
        local theABList = dcsCommon.enumerateTable(collectorDict)\
        return theABList\
    end\
\
    -- getAirbasesWhoseNameContains - get all airbases containing \
    -- a name. filterCat is optional and can be aerodrome (0), farp (1), ship (2)\
    -- filterCoalition is optional and can be 0 (neutral), 1 (red), 2 (blue) \
    -- if no name given or aName = \"*\", then all bases are returned prior to filtering \
    function dcsCommon.getAirbasesWhoseNameContains(aName, filterCat, filterCoalition)\
        --trigger.action.outText(\"getAB(name): enter with \" .. aName, 30)\
        if not aName then aName = \"*\" end \
        local allYourBase = world.getAirbases() -- get em all \
        local areBelongToUs = {}\
        -- now iterate all bases\
        for idx, aBase in pairs(allYourBase) do\
            local airBaseName = aBase:getName() -- get display name\
            if aName == \"*\" or dcsCommon.containsString(airBaseName, aName) then \
                -- containsString is case insesitive unless told otherwise\
                --if aName ~= \"*\" then \
                --    trigger.action.outText(\"getAB(name): matched \" .. airBaseName, 30)\
                --end \
                local doAdd = true \
                if filterCat then \
                    -- make sure the airbase is of that category \
                    local airCat = dcsCommon.getAirbaseCat(aBase)\
                    doAdd = doAdd and airCat == filterCat \
                end\
                \
                if filterCoalition then \
                    doAdd = doAdd and filterCoalition == aBase:getCoalition()\
                end\
                \
                if doAdd then \
                    -- all good, add to table\
                    table.insert(areBelongToUs, aBase)\
                end            \
            end\
        end\
        return areBelongToUs\
    end\
\
    function dcsCommon.getFirstAirbaseWhoseNameContains(aName, filterCat, filterCoalition)\
        local allBases = dcsCommon.getAirbasesWhoseNameContains(aName, filterCat, filterCoalition)\
        for idx, aBase in pairs (allBases) do \
            -- simply return first \
            return aBase\
        end\
        return nil \
    end    \
\
    function dcsCommon.getClosestAirbaseTo(thePoint, filterCat, filterCoalition)\
        local delta = math.huge\
        local allYourBase = dcsCommon.getAirbasesWhoseNameContains(\"*\", filterCat, filterCoalition) -- get em all and filter\
        local closestBase = nil \
        for idx, aBase in pairs(allYourBase) do\
            -- iterate them all \
            local abPoint = aBase:getPoint()\
            newDelta = dcsCommon.dist(thePoint, {x=abPoint.x, y = 0, z=abPoint.z})\
            if newDelta < delta then \
                delta = newDelta\
                closestBase = aBase\
            end\
        end\
        return closestBase, delta \
    end\
\
-- \
-- U N I T S   M A N A G E M E N T \
--\
\
    -- number of living units in group\
    function dcsCommon.livingUnitsInGroup(group)\
        local living = 0\
        local allUnits = group:getUnits()\
        for key, aUnit in pairs(allUnits) do \
            if aUnit:isExist() and aUnit:getLife() >= 1 then \
                living = living + 1\
            end\
        end\
        return living\
    end\
\
    -- closest living unit in group to a point\
    function dcsCommon.getClosestLivingUnitToPoint(group, p)\
        if not p then return nil end\
        if not group then return nil end\
        local closestUnit = nil\
        local closestDist = math.huge\
        local allUnits = group:getUnits()\
        for key, aUnit in pairs(allUnits) do \
            if aUnit:isExist() and aUnit:getLife() >= 1 then \
                local thisDist = dcsCommon.dist(p, aUnit:getPoint())\
                if thisDist < closestDist then \
                    closestDist = thisDist\
                    closestUnit = aUnit \
                end\
            end\
        end\
        return closestUnit, closestDist\
    end\
    \
    -- closest living group to a point - cat can be nil or one of Group.Category = { AIRPLANE = 0, HELICOPTER = 1, GROUND = 2, SHIP = 3, TRAIN = 4}\
    function dcsCommon.getClosestLivingGroupToPoint(p, coal, cat) \
        if not cat then cat = 2 end -- ground is default \
        local closestGroup = nil;\
        local closestGroupDist = math.huge\
        local allGroups =  coalition.getGroups(coal, cat) -- get all groups from this coalition, perhaps filtered by cat \
        for key, grp in pairs(allGroups) do\
            local closestUnit, dist = dcsCommon.getClosestLivingUnitToPoint(grp, p)\
            if closestUnit then \
                if dist < closestGroupDist then \
                    closestGroup = grp\
                    closestGroupDist = dist\
                end\
            end            \
        end\
        return closestGroup, closestGroupDist\
    end\
\
    function dcsCommon.getLivingGroupsAndDistInRangeToPoint(p, range, coal, cat) \
        if not cat then cat = 2 end -- ground is default \
        local groupsInRange = {};\
        local allGroups = coalition.getGroups(coal, cat) -- get all groups from this coalition, perhaps filtered by cat \
        for key, grp in pairs(allGroups) do\
            local closestUnit, dist = dcsCommon.getClosestLivingUnitToPoint(grp, p)\
            if closestUnit then \
                if dist < range then \
                    table.insert(groupsInRange, {group = grp, dist = dist}) -- array\
                end\
            end            \
        end\
        -- sort the groups by distance\
        table.sort(groupsInRange, function (left, right) return left.dist < right.dist end )\
        return groupsInRange\
    end\
\
    -- distFlat ignores y, input must be xyz points, NOT xy points  \
    function dcsCommon.distFlat(p1, p2) \
        local point1 = {x = p1.x, y = 0, z=p1.z}\
        local point2 = {x = p2.x, y = 0, z=p2.z}\
        return dcsCommon.dist(point1, point2)\
    end\
    \
    -- distance between points\
    function dcsCommon.dist(point1, point2)     -- returns distance between two points\
      -- supports xyz and xy notations\
      if not point1 then \
        trigger.action.outText(\"+++ warning: nil point1 in common:dist\", 30)\
        point1 = {x=0, y=0, z=0}\
      end\
\
      if not point2 then \
        trigger.action.outText(\"+++ warning: nil point2 in common:dist\", 30)\
        point2 = {x=0, y=0, z=0}\
        stop.here.now = 1\
      end\
      \
      local p1 = {x = point1.x, y = point1.y}\
      if not point1.z then \
        p1.z = p1.y\
        p1.y = 0\
      else \
        p1.z = point1.z\
      end\
      \
      local p2 = {x = point2.x, y = point2.y}\
      if not point2.z then \
        p2.z = p2.y\
        p2.y = 0\
      else \
        p2.z = point2.z\
      end\
      \
      local x = p1.x - p2.x\
      local y = p1.y - p2.y \
      local z = p1.z - p2.z\
      \
      return (x*x + y*y + z*z)^0.5\
    end\
\
    function dcsCommon.delta(name1, name2) -- returns distance (in meters) of two named objects\
      local n1Pos = Unit.getByName(name1):getPosition().p\
      local n2Pos = Unit.getByName(name2):getPosition().p\
      return dcsCommon.dist(n1Pos, n2Pos)\
    end\
\
    -- lerp between a and b, x being 0..1 (percentage), clipped to [0..1]\
    function dcsCommon.lerp(a, b, x) \
        if not a then return 0 end\
        if not b then return 0 end\
        if not x then return a end\
        if x < 0 then x = 0 end \
        if x > 1 then x = 1 end \
        return a + (b - a ) * x\
    end\
\
    function dcsCommon.bearingFromAtoB(A, B) -- coords in x, z \
        dx = B.x - A.x\
        dz = B.z - A.z\
        bearing = math.atan2(dz, dx) -- in radiants\
        return bearing\
    end\
\
    function dcsCommon.bearingInDegreesFromAtoB(A, B)\
        local bearing = dcsCommon.bearingFromAtoB(A, B) -- in rads \
        bearing = math.floor(bearing / math.pi * 180)\
        if bearing < 0 then bearing = bearing + 360 end\
        if bearing > 360 then bearing = bearing - 360 end\
        return bearing\
    end\
    \
    function dcsCommon.compassPositionOfARelativeToB(A, B)\
        -- warning: is REVERSE in order for bearing, returns a string like 'Sorth', 'Southwest'\
        if not A then return \"***error:A***\" end\
        if not B then return \"***error:B***\" end\
        local bearing = dcsCommon.bearingInDegreesFromAtoB(B, A) -- returns 0..360\
        if bearing < 23 then return \"North\" end \
        if bearing < 68 then return \"NE\" end\
        if bearing < 112 then return \"East\" end \
        if bearing < 158 then return \"SE\" end \
        if bearing < 202 then return \"South\" end \
        if bearing < 248 then return \"SW\" end \
        if bearing < 292 then return \"West\" end\
        if bearing < 338 then return \"NW\" end \
        return \"North\"\
    end\
    \
    function dcsCommon.clockPositionOfARelativeToB(A, B, headingOfBInDegrees)\
        -- o'clock notation \
        if not A then return \"***error:A***\" end\
        if not B then return \"***error:B***\" end\
        if not headingOfBInDegrees then headingOfBInDegrees = 0 end \
        \
        local bearing = dcsCommon.bearingInDegreesFromAtoB(B, A) -- returns 0..360\
--        trigger.action.outText(\"+++comm: oclock - bearing = \" .. bearing .. \" and inHeading = \" .. headingOfBInDegrees, 30) \
        bearing = bearing - headingOfBInDegrees\
        return dcsCommon.getClockDirection(bearing)\
        \
    end \
    \
    -- given a heading, return clock with 0 being 12, 180 being 6 etc.\
    function dcsCommon.getClockDirection(direction) -- inspired by cws, improvements my own\
        if not direction then return 0 end\
        direction = math.fmod (direction, 360)\
        while direction < 0 do \
            direction = direction + 360\
        end\
        \
        if direction < 15 then -- special case 12 o'clock past 12 o'clock\
            return 12\
        end\
    \
        direction = direction + 15 -- add offset so we get all other times correct\
        return math.floor(direction/30)\
    \
    end\
\
    \
    function dcsCommon.randomDegrees()\
        local degrees = math.random(360) * 3.14152 / 180\
        return degrees\
    end\
\
    function dcsCommon.randomPercent()\
        local percent = math.random(100)/100\
        return percent\
    end\
\
    function dcsCommon.randomPointOnPerimeter(sourceRadius, x, z) \
        return dcsCommon.randomPointInCircle(sourceRadius, sourceRadius-1, x, z)\
    end\
\
    function dcsCommon.randomPointInCircle(sourceRadius, innerRadius, x, z)\
        if not x then x = 0 end\
        --local y = 0\
        if not innerRadius then innerRadius = 0 end        \
        if innerRadius < 0 then innerRadius = 0 end\
        \
        local percent = dcsCommon.randomPercent() -- 1 / math.random(100)\
        -- now lets get a random degree\
        local degrees = dcsCommon.randomDegrees() -- math.random(360) * 3.14152 / 180 -- ok, it's actually radiants. \
        local r = (sourceRadius-innerRadius) * percent \
        local x = x + (innerRadius + r) * math.cos(degrees)\
        local z = z + (innerRadius + r) * math.sin(degrees)\
    \
        local thePoint = {}\
        thePoint.x = x\
        thePoint.y = 0\
        thePoint.z = z \
        \
        return thePoint, degrees\
    end\
\
    -- get group location: get the group's location by \
    -- accessing the fist existing, alive member of the group that it finds\
    function dcsCommon.getGroupLocation(group)\
        -- nifty trick from mist: make this work with group and group name\
        if type(group) == 'string' then -- group name\
            group = Group.getByName(group)\
        end\
        \
        -- get all units\
        local allUnits = group:getUnits()\
\
        -- iterate through all members of group until one is alive and exists\
        for index, theUnit in pairs(allUnits) do \
            if (theUnit:isExist() and theUnit:getLife() > 0) then \
                return theUnit:getPosition().p \
            end;\
        end\
\
        -- if we get here, there was no live unit \
        --trigger.action.outText(\"+++cmn: A group has no live units. returning nil\", 10)\
        return nil \
        \
    end\
\
    -- get the group's first Unit that exists and is \
    -- alive \
    function dcsCommon.getGroupUnit(group)\
        if not group then return nil  end\
        \
        -- nifty trick from mist: make this work with group and group name\
        if type(group) == 'string' then -- group name\
            group = Group.getByName(group)\
        end\
        \
        if not group:isExist() then return nil end \
        \
        -- get all units\
        local allUnits = group:getUnits()\
\
        -- iterate through all members of group until one is alive and exists\
        for index, theUnit in pairs(allUnits) do \
            if (theUnit:isExist() and theUnit:getLife() > 0) then \
                return theUnit\
            end;\
        end\
\
        -- if we get here, there was no live unit \
        --trigger.action.outText(\"+++cmn A group has no live units. returning nil\", 10)\
        return nil \
        \
    end\
\
    -- and here the alias\
    function dcsCommon.getFirstLivingUnit(group)\
        return dcsCommon.getGroupUnit(group)\
    end\
    \
    -- isGroupAlive returns true if there is at least one unit in the group that isn't dead\
    function dcsCommon.isGroupAlive(group)\
        return (dcsCommon.getGroupUnit(group) ~= nil) \
    end\
\
    function dcsCommon.getLiveGroupUnits(group)\
        -- nifty trick from mist: make this work with group and group name\
        if type(group) == 'string' then -- group name\
            group = Group.getByName(group)\
        end\
        \
        local liveUnits = {}\
        -- get all units\
        local allUnits = group:getUnits()\
\
        -- iterate through all members of group until one is alive and exists\
        for index, theUnit in pairs(allUnits) do \
            if (theUnit:isExist() and theUnit:getLife() > 0) then \
                table.insert(liveUnits, theUnit) \
            end;\
        end\
\
        -- if we get here, there was no live unit \
        return liveUnits\
    end\
\
    function dcsCommon.getGroupTypeString(group) -- convert into comma separated types \
        if not group then \
            trigger.action.outText(\"+++cmn getGroupTypeString: nil group\", 30)\
            return \"\" \
        end\
        if not dcsCommon.isGroupAlive(group) then \
            trigger.action.outText(\"+++cmn getGroupTypeString: dead group\", 30)\
            return \"\" \
        end \
        local theTypes = \"\"\
        local liveUnits = dcsCommon.getLiveGroupUnits(group)\
        for i=1, #liveUnits do \
            if i > 1 then theTypes = theTypes .. \",\" end\
            theTypes = theTypes .. liveUnits[i]:getTypeName()\
        end\
        return theTypes\
    end\
\
    function dcsCommon.getGroupTypes(group) \
        if not group then \
            trigger.action.outText(\"+++cmn getGroupTypes: nil group\", 30)\
            return {}\
        end\
        if not dcsCommon.isGroupAlive(group) then \
            trigger.action.outText(\"+++cmn getGroupTypes: dead group\", 30)\
            return {}\
        end \
        local liveUnits = dcsCommon.getLiveGroupUnits(group)\
        local unitTypes = {}\
        for i=1, #liveUnits do \
            table.insert(unitTypes, liveUnits[i]:getTypeName())\
        end\
        return unitTypes\
    end\
\
    function dcsCommon.getEnemyCoalitionFor(aCoalition)\
        if aCoalition == 1 then return 2 end\
        if aCoalition == 2 then return 1 end\
        if type(aCoalition) == \"string\" then \
            aCoalition = aCoalition:lower()\
            if aCoalition == \"red\" then return 2 end\
            if aCoalition == \"blue\" then return 1 end\
        end\
        return nil\
    end\
\
    function dcsCommon.getACountryForCoalition(aCoalition)\
        -- scan the table of countries and get the first country that is part of aCoalition\
        -- this is useful if you want to create troops for a coalition but don't know the\
        -- coalition's countries \
        -- we start with id=0 (Russia), go to id=85 (Slovenia), but skip id = 14\
        local i = 0\
        while i < 86 do \
            if i ~= 14 then \
                if (coalition.getCountryCoalition(i) == aCoalition) then return i end\
            end\
            i = i + 1\
        end\
        \
        return nil\
    end\
--\
--\
-- C A L L B A C K   H A N D L E R \
--\
--\
\
    -- installing callbacks\
    -- based on mist, with optional additional hooks for pre- and post-\
    -- processing of the event\
    -- when filtering occurs in pre, an alternative 'rejected' handler can be called \
    function dcsCommon.addEventHandler(f, pre, post, rejected) -- returns ID \
        local handler = {} -- build a wrapper and connect the onEvent\
        --dcsCommon.cbID = dcsCommon.cbID + 1 -- increment unique count\
        handler.id = dcsCommon.uuid(\"eventHandler\")\
        handler.f = f -- the callback itself\
        if (rejected) then handler.rejected = rejected end\
        -- now set up pre- and post-processors. defaults are set in place\
        -- so pre and post are optional. If pre returns false, the callback will\
        -- not be invoked\
        if (pre) then handler.pre = pre else handler.pre = dcsCommon.preCall end\
        if (post) then handler.post = post else handler.post = dcsCommon.postCall end\
        function handler:onEvent(event)\
            if not self.pre(event) then \
                if dcsCommon.verbose then\
--                    trigger.action.outText(\"event \" .. event.id .. \" discarded by pre-processor\", 10)\
                end\
                if (self.rejected) then self.rejected(event) end \
                return\
            end\
            self.f(event) -- call the handler\
            self.post(event) -- do post-processing\
        end\
        world.addEventHandler(handler)\
        return handler.id\
    end\
\
    function dcsCommon.preCall(e)\
        -- we can filter here\
        -- if we return false, the call is abortet\
        if dcsCommon.verbose then\
            trigger.action.outText(\"event \" .. e.id .. \" received: PRE-PROCESSING\", 10)\
        end\
        return true;\
    end;\
\
    function dcsCommon.postCall(e)\
        -- we do pos proccing here \
        if dcsCommon.verbose then\
            trigger.action.outText(\"event \" .. e.id .. \" received: post proc\", 10)\
        end\
    end\
    \
    -- highly specific eventhandler for one event only\
    -- based on above, with direct filtering built in; skips pre\
    -- but does post\
    function dcsCommon.addEventHandlerForEventTypes(f, evTypes, post, rejected) -- returns ID \
        local handler = {} -- build a wrapper and connect the onEvent\
        dcsCommon.cbID = dcsCommon.cbID + 1 -- increment unique count\
        handler.id = dcsCommon.cbID\
        handler.what = evTypes\
        if (rejected) then handler.rejected = rejected end \
        \
        handler.f = f -- set the callback itself\
        -- now set up post-processor. pre is hard-coded to match evType\
        -- post is optional. If event.id is not in evTypes, the callback will\
        -- not be invoked\
        if (post) then handler.post = post else handler.post = dcsCommon.postCall end\
        function handler:onEvent(event)\
            hasMatch = false;\
            for key, evType in pairs(self.what) do\
                if evType == event.id then\
                    hasMatch = true;\
                    break;\
                end;\
            end;\
            if not hasMatch then \
                if dcsCommon.verbose then\
                    trigger.action.outText(\"event \" .. e.id .. \" discarded - not in whitelist evTypes\", 10)\
                end\
                if (self.rejected) then self.rejected(event) end \
                return;\
            end;\
            \
            self.f(event) -- call the actual handler as passed to us\
            self.post(event) -- do post-processing \
        end\
        world.addEventHandler(handler) -- add to event handlers\
        return handler.id\
    end\
    \
    \
    \
    -- remove event handler / callback, identical to Mist \
    -- note we don't call world.removeEventHandler, but rather directly \
    -- access world.eventHandlers directly and remove kvp directly.\
    function dcsCommon.removeEventHandler(id)\
        for key, handler in pairs(world.eventHandlers) do\
            if handler.id and handler.id == id then\
                world.eventHandlers[key] = nil\
                return true\
            end\
        end\
        return false\
    end\
\
--\
--\
-- C L O N I N G \
--\
--\
    -- topClone is a shallow clone of orig, only top level is iterated,\
    -- all values are ref-copied\
    function dcsCommon.topClone(orig)\
        local orig_type = type(orig)\
        local copy\
        if orig_type == 'table' then\
            copy = {}\
            for orig_key, orig_value in pairs(orig) do\
                copy[orig_key] = orig_value\
            end\
        else -- number, string, boolean, etc\
            copy = orig\
        end\
        return copy\
    end\
\
    -- clone is a recursive clone which will also clone\
    -- deeper levels, as used in units \
    function dcsCommon.clone(orig)\
        local orig_type = type(orig)\
        local copy\
        if orig_type == 'table' then\
            copy = {}\
            for orig_key, orig_value in next, orig, nil do\
                copy[dcsCommon.clone(orig_key)] = dcsCommon.clone(orig_value)\
            end\
            setmetatable(copy, dcsCommon.clone(getmetatable(orig)))\
        else -- number, string, boolean, etc\
            copy = orig\
        end\
        return copy\
    end\
\
\
--\
-- \
-- S P A W N I N G \
-- \
-- \
\
    function dcsCommon.createEmptyGroundGroupData (name)\
        local theGroup = {} -- empty group\
        theGroup.visible = false\
        theGroup.taskSelected = true\
        -- theGroup.route = {}\
        -- theGroup.groupId = id\
        theGroup.tasks = {}\
        -- theGroup.hidden = false -- hidden on f10?\
\
        theGroup.units = { } -- insert units here! -- use addUnitToGroupData\
\
        theGroup.x = 0\
        theGroup.y = 0\
        theGroup.name = name\
        -- theGroup.start_time = 0\
        theGroup.task = \"Ground Nothing\"\
        \
        return theGroup\
    end;\
\
    function dcsCommon.createEmptyAircraftGroupData (name)\
        local theGroup = dcsCommon.createEmptyGroundGroupData(name)--{} -- empty group\
\
        theGroup.task = \"Nothing\" -- can be others, like Transport, CAS, etc\
        -- returns with empty route\
        theGroup.route = dcsCommon.createEmptyAircraftRouteData() -- we can add points here \
        return theGroup\
    end;\
\
    function dcsCommon.createAircraftRoutePointData(x, z, altitudeInFeet, knots, altType, action)\
        local rp = {}\
        rp.x = x\
        rp.y = z\
        rp.action = \"Turning Point\"\
        rp.type = \"Turning Point\"\
        if action then rp.action = action; rp.type = action end -- warning: may not be correct, need to verify later\
        rp.alt = altitudeInFeet * 0.3048\
        rp.speed = knots * 0.514444 -- we use \
        rp.alt_type = \"BARO\"\
        if (altType) then rp.alt_type = altType end \
        return rp\
    end\
\
    function dcsCommon.addRoutePointDataToRouteData(inRoute, x, z, altitudeInFeet, knots, altType, action)\
        local p = dcsCommon.createAircraftRoutePointData(x, z, altitudeInFeet, knots, altType, action)\
        local thePoints = inRoute.points \
        table.insert(thePoints, p)\
    end\
    \
    function dcsCommon.addRoutePointDataToGroupData(group, x, z, altitudeInFeet, knots, altType, action)\
        if not group.route then group.route = dcsCommon.createEmptyAircraftRouteData() end\
        local theRoute = group.route \
        dcsCommon.addRoutePointDataToRouteData(theRoute, x, z, altitudeInFeet, knots, altType, action)\
    end\
\
    function dcsCommon.addRoutePointForGroupData(theGroup, theRP)\
        if not theGroup then return end \
        if not theGroup.route then theGroup.route = dcsCommon.createEmptyAircraftRouteData() end\
        \
        local theRoute = theGroup.route \
        local thePoints = theRoute.points \
        table.insert(thePoints, theRP)\
    end\
    \
    function dcsCommon.createEmptyAircraftRouteData()\
        local route = {}\
        route.points = {}\
        return route\
    end\
\
    function dcsCommon.createTakeOffFromParkingRoutePointData(aerodrome)\
        if not aerodrome then return nil end \
            \
        local rp = {}    \
        local freeParkingSlot = dcsCommon.getFirstFreeParkingSlot(aerodrome, 104) -- get big slot first \
        if not freeParkingSlot then \
            freeParkingSlot = dcsCommon.getFirstFreeParkingSlot(aerodrome) -- try any size\
        end\
            \
        if not freeParkingSlot then \
            trigger.action.outText(\"civA: no free parking at \" .. aerodrome:getName(), 30)\
            return nil \
        end\
            \
        local p = freeParkingSlot.vTerminalPos\
            \
        rp.airdromeId = aerodrome:getID() \
        rp.x = p.x\
        rp.y = p.z\
        rp.alt = p.y \
        rp.action = \"From Parking Area\"\
        rp.type = \"TakeOffParking\"\
            \
        rp.speed = 100; -- in m/s? If so, that's 360 km/h \
        rp.alt_type = \"BARO\"\
        return rp\
    end\
\
    function dcsCommon.createOverheadAirdromeRoutPintData(aerodrome)\
        if not aerodrome then return nil end \
        local rp = {}            \
        local p = aerodrome:getPoint()\
        rp.x = p.x\
        rp.y = p.z\
        rp.alt = p.y + 2000 -- 6000 ft overhead\
        rp.action = \"Turning Point\"\
        rp.type = \"Turning Point\"\
            \
        rp.speed = 133; -- in m/s? If so, that's 360 km/h \
        rp.alt_type = \"BARO\"\
        return rp\
    end\
    \
\
    function dcsCommon.createLandAtAerodromeRoutePointData(aerodrome)\
        if not aerodrome then return nil end \
            \
        local rp = {}            \
        local p = aerodrome:getPoint()\
        rp.airdromeId = aerodrome:getID() \
        rp.x = p.x\
        rp.y = p.z\
        rp.alt = p.y \
        rp.action = \"Landing\"\
        rp.type = \"Land\"\
            \
        rp.speed = 100; -- in m/s? If so, that's 360 km/h \
        rp.alt_type = \"BARO\"\
        return rp\
    end\
\
    \
    function dcsCommon.createRPFormationData(findex) -- must be added as \"task\" to an RP. use 4 for Echelon right\
        local task = {}\
        task.id = \"ComboTask\"\
        local params = {}\
        task.params = params\
        local tasks = {}\
        params.tasks = tasks\
        local t1 = {}\
        tasks[1] = t1\
        t1.number = 1\
        t1.auto = false \
        t1.id = \"WrappedAction\"\
        t1.enabled = true\
        local t1p = {}\
        t1.params = t1p\
        local action = {}\
        t1p.action = action \
        action.id = \"Option\"\
        local ap = {}\
        action.params = ap\
        ap.variantIndex = 3\
        ap.name = 5 -- AI.Option.Air.ID 5 = Formation \
        ap.formationIndex = findex -- 4 is echelon_right\
        ap.value = 262147\
        \
        return task \
    end\
\
    function dcsCommon.addTaskDataToRP(theTask, theGroup, rpIndex)\
        local theRoute = theGroup.route\
        local thePoints = theRoute.points\
        local rp = thePoints[rpIndex]\
        rp.task = theTask\
    end\
    \
    -- create a minimal payload table that is compatible with creating \
    -- a unit. you may need to alter this before adding the unit to\
    -- the mission. all params optional \
    function dcsCommon.createPayload(fuel, flare, chaff, gun) \
        local payload = {}\
        payload.pylons = {}\
        if not fuel then fuel = 1000 end -- in kg. check against fuelMassMax in type desc\
        if not flare then flare = 0 end\
        if not chaff then chaff = 0 end\
        if not gun then gun = 0 end\
        return payload \
        \
    end\
\
    function dcsCommon.createCallsign(cs) \
        local callsign = {}\
        callsign[1] = 1\
        callsign[2] = 1\
        callsign[3] = 1\
        if not cs then cs = \"Enfield11\" end\
        callsign.name = cs\
        return callsign\
    end\
    \
\
    -- create the data table required to spawn a unit.\
    -- unit types are defined in https://github.com/mrSkortch/DCS-miscScripts/tree/master/ObjectDB\
    function dcsCommon.createGroundUnitData(name, unitType, transportable)\
        local theUnit = {}\
        unitType = dcsCommon.trim(unitType)\
        theUnit.type = unitType -- e.g. \"LAV-25\",\
        if not transportable then transportable = false end -- elaborate, not requried code\
        theUnit.transportable = {[\"randomTransportable\"] = transportable} \
        -- theUnit.unitId = id \
        theUnit.skill = \"Average\" -- always average \
        theUnit.x = 0 -- make it zero, zero!\
        theUnit.y = 0\
        theUnit.name = name\
        theUnit.playerCanDrive = false\
        theUnit.heading = 0\
        return theUnit\
    end \
\
    function dcsCommon.createAircraftUnitData(name, unitType, transportable, altitude, speed, heading)\
        local theAirUnit = dcsCommon.createGroundUnitData(name, unitType, transportable)\
        theAirUnit.alt = 100 -- make it 100m\
        if altitude then theAirUnit.alt = altitude end \
        theAirUnit.alt_type = \"RADIO\" -- AGL\
        theAirUnit.speed = 77 -- m/s --> 150 knots\
        if speed then theAirUnit.speed = speed end \
        if heading then theAirUnit.heading = heading end \
        theAirUnit.payload = dcsCommon.createPayload()\
        theAirUnit.callsign = dcsCommon.createCallsign()\
        return theAirUnit\
    end\
    \
\
    function dcsCommon.addUnitToGroupData(theUnit, theGroup, dx, dy, heading)\
        -- add a unit to a group, and place it at dx, dy of group's position,\
        -- taking into account unit's own current location\
        if not dx then dx = 0 end\
        if not dy then dy = 0 end\
        if not heading then heading = 0 end\
        theUnit.x = theUnit.x + dx + theGroup.x\
        theUnit.y = theUnit.y + dy + theGroup.y \
        theUnit.heading = heading\
        table.insert(theGroup.units, theUnit)\
    end;\
\
    function dcsCommon.createSingleUnitGroup(name, theUnitType, x, z, heading) \
        -- create the container \
        local theNewGroup = dcsCommon.createEmptyGroundGroupData(name)\
        local aUnit = {}\
        aUnit = dcsCommon.createGroundUnitData(name .. \"-1\", theUnitType, false)\
--        trigger.action.outText(\"dcsCommon - unit name retval \" .. aUnit.name, 30)\
        dcsCommon.addUnitToGroupData(aUnit, theNewGroup, x, z, heading)\
        return theNewGroup\
    end\
    \
\
    function dcsCommon.arrangeGroupDataIntoFormation(theNewGroup, radius, minDist, formation, innerRadius)\
        -- formations:\
        --    (default) \"line\" (left to right along x) -- that is Y direction\
        --    \"line_v\" a line top to bottom -- that is X direction\
        --    \"chevron\" - left to right middle too top\
        --    \"scattered\", \"random\" -- random, innerRadius used to clear area in center\
        --       \"circle\", \"circle_forward\" -- circle, forward facing\
        --    \"circle_in\" -- circle, inwarf facing\
        --    \"circle_out\" -- circle, outward facing\
        --    \"grid\", \"square\", \"rect\" -- optimal rectangle\
        --    \"2cols\", \"2deep\" -- 2 columns, n deep \
        --    \"2wide\" -- 2 columns wide, 2 deep \
\
        local num = #theNewGroup.units \
        \
        -- now do the formation stuff\
        -- make sure that they keep minimum  distance \
--        trigger.action.outText(\"dcsCommon - processing formation \" .. formation .. \" with radius = \" .. radius, 30)\
        if formation == \"LINE_V\" then \
            -- top to bottom in zone (heding 0). -- will run through x-coordinate \
            -- use entire radius top to bottom \
            local currX = -radius\
            local increment = radius * 2/(num - 1) -- MUST NOT TRY WITH 1 UNIT!\
            for i=1, num do\
            \
                local u = theNewGroup.units[i]\
--                trigger.action.outText(\"formation unit \" .. u.name .. \" currX = \" .. currX, 30)\
                u.x = currX\
                currX = currX + increment\
            end\
        \
        elseif formation == \"LINE\" then \
            -- left to right in zone. runs through Y\
            -- left and right are y because at heading 0, forward is x (not y as expected)\
            local currY = -radius\
            local increment = radius * 2/(num - 1) -- MUST NOT TRY WITH 1 UNIT!\
            for i=1, num do\
                local u = theNewGroup.units[i]\
--                trigger.action.outText(\"formation unit \" .. u.name .. \" currX = \" .. currY, 30)\
                u.y = currY\
                currY = currY + increment\
            end    \
        \
        elseif formation == \"CHEVRON\" then \
            -- left to right in zone. runs through Y\
            -- left and right are y because at heading 0, forward is x (not y as expected)\
            local currY = -radius\
            local currX = 0\
            local incrementY = radius * 2/(num - 1) -- MUST NOT TRY WITH 1 UNIT!\
            local incrementX = radius * 2/(num - 1) -- MUST NOT TRY WITH 1 UNIT!\
            for i=1, num do\
                local u = theNewGroup.units[i]\
--                trigger.action.outText(\"formation unit \" .. u.name .. \" currX = \" .. currX .. \" currY = \" .. currY, 30)\
                u.x = currX\
                u.y = currY\
                -- calc coords for NEXT iteration\
                currY = currY + incrementY -- march left to right\
                if i < num / 2 then -- march up\
                    currX = currX + incrementX \
                elseif i == num / 2 then -- even number, keep height\
                    currX = currX + 0 \
                else \
                    currX = currX - incrementX -- march down \
                end \
                -- note: when unit number even, the wedge is sloped. may need an odd/even test for better looks\
            end    \
\
        elseif formation == \"SCATTERED\" or formation == \"RANDOM\" then \
            -- use randomPointInCircle and tehn iterate over all vehicles for mindelta\
            processedUnits = {}\
            for i=1, num do\
                local emergencyBreak = 1 -- prevent endless loop\
                local lowDist = 10000\
                local uPoint = {}\
                local thePoint = {}\
                repeat     -- get random point intil mindistance to all is kept or emergencybreak\
                    for idx, rUnit in pairs(processedUnits) do -- get min dist to all positioned units\
                        thePoint = dcsCommon.randomPointInCircle(radius, innerRadius) -- returns x, 0, z\
                        uPoint.x = rUnit.x\
                        uPoint.y = 0\
                        uPoint.z = rUnit.y \
                        local dist = dcsCommon.dist(thePoint, uPoint) -- measure distance to unit\
                        if (dist < lowDist) then lowDist = dist end\
                    end\
                    emergencyBreak = emergencyBreak + 1\
                until (emergencyBreak > 20) or (lowDist > minDist)\
                -- we have random x, y \
                local u = theNewGroup.units[i] -- get unit to position\
                u.x = thePoint.x\
                u.y = thePoint.z -- z --> y mapping! \
                -- now add the unit to the 'processed' set \
                table.insert(processedUnits, u)\
            end    \
\
        elseif dcsCommon.stringStartsWith(formation, \"CIRCLE\") then\
            -- units are arranged on perimeter of circle defined by radius \
--            trigger.action.outText(\"formation circle detected\", 30)\
            local currAngle = 0\
            local angleInc = 2 * 3.14157 / num -- increase per spoke \
            for i=1, num do\
                local u = theNewGroup.units[i] -- get unit \
                u.x = radius * math.cos(currAngle)\
                u.y = radius * math.sin(currAngle)\
                \
                -- now baldower out heading \
                -- circle, circle_forward no modifier of heading\
                if dcsCommon.stringStartsWith(formation, \"CIRCLE_IN\") then \
                    -- make the heading inward faceing - that's angle + pi\
                    u.heading = u.heading + currAngle + 3.14157\
                elseif dcsCommon.stringStartsWith(formation, \"CIRCLE_OUT\") then \
                    u.heading = u.heading + currAngle + 0\
                end\
\
                currAngle = currAngle + angleInc\
            end\
        elseif formation == \"GRID\" or formation == \"SQUARE\" or formation == \"RECT\" then \
            if num < 2 then return end \
            -- arrange units in an w x h grid\
            -- e-g- 12 units = 4 x 3. \
            -- calculate w \
            local w = math.floor(num^(0.5) + 0.5)\
            dcsCommon.arrangeGroupInNColumns(theNewGroup, w, radius)\
            --[[--\
            local h = math.floor(num / w)\
            --trigger.action.outText(\"AdcsC: num=\" .. num .. \" w=\" .. w .. \"h=\" .. h .. \" -- num%w=\" .. num%w, 30)\
            if (num % w) > 0 then \
                h = h + 1\
            end\
            \
            --trigger.action.outText(\"BdcsC: num=\" .. num .. \" w=\" .. w .. \"h=\" .. h, 30)\
            \
            -- now w * h always >= num and num items fir in that grid\
            -- w is width, h is height, of course :) \
            -- now calculat xInc and yInc\
            local i = 1\
            local xInc = 0 \
            if w > 1 then xInc = 2 * radius / (w-1) end\
            local yInc = 0\
            if h > 1 then yInc = 2 * radius / (h-1) end \
            local currY = radius \
            if h < 2 then currY = 0 end -- special:_ place in Y middle if only one row)\
            while h > 0 do \
                local currX = radius \
                local wCnt = w \
                while wCnt > 0 and (i <= num) do \
                    local u = theNewGroup.units[i] -- get unit \
                    u.x = currX\
                    u.y = currY\
                    currX = currX - xInc\
                    wCnt = wCnt - 1\
                    i = i + 1\
                end\
                currY = currY - yInc \
                h = h - 1\
            end\
            --]]--\
        elseif formation == \"2DEEP\" or formation == \"2COLS\" then\
            if num < 2 then return end \
            -- arrange units in an 2 x h grid\
            local w = 2\
            dcsCommon.arrangeGroupInNColumnsDeep(theNewGroup, w, radius)\
\
        elseif formation == \"2WIDE\" then\
            if num < 2 then return end \
            -- arrange units in an 2 x h grid\
            local w = 2\
            dcsCommon.arrangeGroupInNColumns(theNewGroup, w, radius)\
        else \
            trigger.action.outText(\"dcsCommon - unknown formation: \" .. formation, 30)\
        end\
    \
    end\
    \
    function dcsCommon.arrangeGroupInNColumns(theNewGroup, w, radius)\
        local num = #theNewGroup.units\
        local h = math.floor(num / w)\
        if (num % w) > 0 then \
            h = h + 1\
        end\
        local i = 1\
        local xInc = 0 \
        if w > 1 then xInc = 2 * radius / (w-1) end\
        local yInc = 0\
        if h > 1 then yInc = 2 * radius / (h-1) end \
        local currY = radius \
        if h < 2 then currY = 0 end -- special:_ place in Y middle if only one row)\
        while h > 0 do \
            local currX = radius \
            local wCnt = w \
            while wCnt > 0 and (i <= num) do \
                local u = theNewGroup.units[i] -- get unit \
                u.x = currX\
                u.y = currY\
                currX = currX - xInc\
                wCnt = wCnt - 1\
                i = i + 1\
            end\
            currY = currY - yInc \
            h = h - 1\
        end\
    end\
    \
    function dcsCommon.arrangeGroupInNColumnsDeep(theNewGroup, w, radius)\
        local num = #theNewGroup.units\
        local h = math.floor(num / w)\
        if (num % w) > 0 then \
            h = h + 1\
        end\
        local i = 1\
        local yInc = 0 \
        if w > 1 then yInc = 2 * radius / (w-1) end\
        local xInc = 0\
        if h > 1 then xInc = 2 * radius / (h-1) end \
        local currX = radius \
        if h < 2 then currX = 0 end -- special:_ place in Y middle if only one row)\
        while h > 0 do \
            local currY = radius \
            local wCnt = w \
            while wCnt > 0 and (i <= num) do \
                local u = theNewGroup.units[i] -- get unit \
                u.x = currX\
                u.y = currY\
                currY = currY - yInc\
                wCnt = wCnt - 1\
                i = i + 1\
            end\
            currX = currX - xInc \
            h = h - 1\
        end\
    end\
    \
    \
    function dcsCommon.createGroundGroupWithUnits(name, theUnitTypes, radius, minDist, formation, innerRadius)\
        if not minDist then mindist = 4 end -- meters\
        if not formation then formation = \"line\" end \
        if not radius then radius = 30 end -- meters \
        if not innerRadius then innerRadius = 0 end\
        formation = formation:upper()\
        -- theUnitTypes can be either a single string or a table of strings\
        -- see here for TypeName https://github.com/mrSkortch/DCS-miscScripts/tree/master/ObjectDB\
        -- formation defines how the units are going to be arranged in the\
        -- formation specified. \
        -- formations:\
        --    (default) \"line\" (left to right along x) -- that is Y direction\
        --    \"line_V\" a line top to bottom -- that is X direction\
        --    \"chevron\" - left to right middle too top\
        --    \"scattered\", \"random\" -- random, innerRadius used to clear area in center\
        --       \"circle\", \"circle_forward\" -- circle, forward facing\
        --    \"circle_in\" -- circle, inwarf facing\
        --    \"circle_out\" -- circle, outward facing\
\
        -- first, we create a group\
        local theNewGroup = dcsCommon.createEmptyGroundGroupData(name)\
        \
        -- now add a single unit or multiple units\
        if type(theUnitTypes) ~= \"table\" then \
--            trigger.action.outText(\"dcsCommon - i am here\", 30)\
--            trigger.action.outText(\"dcsCommon - name \" .. name, 30)\
--            trigger.action.outText(\"dcsCommon - unit type \" .. theUnitTypes, 30)\
            \
            local aUnit = {}\
            aUnit = dcsCommon.createGroundUnitData(name .. \"-1\", theUnitTypes, false)\
--            trigger.action.outText(\"dcsCommon - unit name retval \" .. aUnit.name, 30)\
            dcsCommon.addUnitToGroupData(aUnit, theNewGroup, 0, 0) -- create with data at location (0,0)\
            return theNewGroup\
        end \
\
        -- if we get here, theUnitTypes is a table\
        -- now loop and create a unit for each table\
        local num = 1\
        for key, theType in pairs(theUnitTypes) do \
--            trigger.action.outText(\"creating unit \" .. name .. \"-\" .. num, 30)\
            local aUnit = dcsCommon.createGroundUnitData(name .. \"-\"..num, theType, false)\
            dcsCommon.addUnitToGroupData(aUnit, theNewGroup, 0, 0)\
            num = num + 1\
        end\
        \
        dcsCommon.arrangeGroupDataIntoFormation(theNewGroup, radius, minDist, formation, innerRadius)\
        return theNewGroup\
\
    \
    end\
\
-- create a new group, based on group in mission. Groups coords are 0,0 for group and all\
-- x,y and heading\
    function dcsCommon.createGroupDataFromLiveGroup(name, newName) \
        if not newName then newName = dcsCommon.uuid(\"uniqName\") end\
        -- get access to the group\
        local liveGroup = Group.getByName(name)\
        if not liveGroup then return nil end\
        -- get the categorty\
        local cat = liveGroup:getCategory()\
        local theNewGroup = {}\
        \
        -- create a new empty group at (0,0) \
        if cat == Group.Category.AIRPLANE or cat == Group.Category.HELICOPTER then \
            theNewGroup = dcsCommon.createEmptyAircraftGroupData(newName)\
        elseif cat == Group.Category.GROUND then\
            theNewGroup = dcsCommon.createEmptyGroudGroupData(newName)\
        else \
            trigger.action.outText(\"dcsCommon - unknown category: \" .. cat, 30)\
            return nil\
        end\
        \
\
        -- now get all units from live group and create data units\
        -- note that unit data for group has x=0, y=0\
        liveUnits = liveGroup:getUnits()\
        \
        for index, theUnit in pairs(liveUnits) do \
            -- for each unit we get the desc \
            local desc = theUnit:getDesc() -- of interest is only typename \
            local newUnit = dcsCommon.createGroundUnitData(dcsCommon.uuid(newName),\
                                                           desc.typeName,\
                                                           false)\
            -- we now basically have a ground unit at (0,0) \
            -- add mandatory fields by type\
            if cat == Group.Category.AIRPLANE or cat == Group.Category.HELICOPTER then \
                newUnit.alt = 100 -- make it 100m\
                newUnit.alt_type = \"RADIO\" -- AGL\
                newUnit.speed = 77 -- m/s --> 150 knots\
                newUnit.payload = dcsCommon.createPayload() -- empty payload\
                newUnit.callsign = dcsCommon.createCallsign() -- 'enfield11'\
                \
            elseif cat == Group.Category.GROUND then\
                -- we got all we need\
            else \
                -- trigger.action.outText(\"dcsCommon - unknown category: \" .. cat, 30)\
                -- return nil\
                -- we also got all we need\
            end            \
            \
        end\
    \
    end;\
    \
\
    function dcsCommon.rotatePointAroundOrigin(inX, inY, angle) -- angle in degrees\
        local degrees =  3.14152 / 180 -- ok, it's actually radiants. \
        angle = angle * degrees -- turns into rads\
        local c = math.cos(angle)\
        local s = math.sin(angle)\
        local px\
        local py \
        px = inX * c - inY * s\
        py = inX * s + inY * c\
        return px, py        \
    end\
\
    function dcsCommon.rotateGroupData(theGroup, degrees, cx, cz)\
        if not cx then cx = 0 end\
        if not cy then cy = 0 end\
        local rads = degrees *  3.14152 / 180\
        -- turns all units in group around the group's center by degrees.\
        -- may also need to turn individual units by same amount\
        for i, theUnit in pairs (theGroup.units) do\
            theUnit.x = theUnit.x - cx -- MOVE TO ORIGIN OF ROTATION\
            theUnit.y = theUnit.y - cy                 \
            theUnit.x, theUnit.y = dcsCommon.rotatePointAroundOrigin(theUnit.x, theUnit.y, degrees)\
            theUnit.x = theUnit.x + cx -- MOVE BACK \
            theUnit.y = theUnit.y + cy                 \
\
            -- may also want to increase heading by degreess\
            theUnit.heading = theUnit.heading + rads \
        end\
    end\
\
    function dcsCommon.offsetGroupData(theGroup, dx, dy)\
        -- add dx and dy to group's and all unit's coords\
        for i, theUnit in pairs (theGroup.units) do \
            theUnit.x = theUnit.x + dx\
            theUnit.y = theUnit.y + dy\
        end\
        \
        theGroup.x = theGroup.x + dx\
        theGroup.y = theGroup.y + dy \
    end\
    \
    function dcsCommon.moveGroupDataTo(theGroup, xAbs, yAbs)\
        local dx = xAbs-theGroup.x\
        local dy = yAbs-theGroup.y\
        dcsCommon.offsetGroupData(theGroup, dx, dy)\
    end\
    \
    -- static objectr shapes and types are defined here\
    -- https://github.com/mrSkortch/DCS-miscScripts/tree/master/ObjectDB/Statics\
    \
    function dcsCommon.createStaticObjectData(name, objType, heading, dead, cargo, mass)\
        local staticObj = {}\
        if not heading then heading = 0 end \
        if not dead then dead = false end \
        if not cargo then cargo = false end \
        objType = dcsCommon.trim(objType) \
        \
        staticObj.heading = 0\
        -- staticObj.groupId = 0\
        -- staticObj.shape_name = shape -- e.g. H-Windsock_RW\
        staticObj.type = objType  -- e.g. Windsock\
        -- [\"unitId\"] = 3,\
        staticObj.rate = 1 -- score when killed\
        staticObj.name = name\
        -- staticObj.category = \"Fortifications\",\
        staticObj.y = 0\
        staticObj.x = 0\
        staticObj.dead = dead\
        staticObj.canCargo = cargo -- to cargo\
        if cargo then \
            if not mass then mass = 1234 end \
            staticObj.mass = mass -- to cargo\
        end\
        return staticObj\
    end\
    \
    function dcsCommon.createStaticObjectDataAt(loc, name, objType, heading, dead)\
        local theData = dcsCommon.createStaticObjectData(name, objType, heading, dead)\
        theData.x = loc.x\
        theData.y = loc.z \
        return theData\
    end\
    \
    function dcsCommon.createStaticObjectForCoalitionAtLocation(theCoalition, loc, name, objType, heading, dead) \
        if not heading then heading = math.random(360) * 3.1415 / 180 end\
        local theData = dcsCommon.createStaticObjectDataAt(loc, name, objType, heading, dead)\
        local theStatic = coalition.addStaticObject(theCoalition, theData)\
        return theStatic\
    end\
    \
    function dcsCommon.createStaticObjectForCoalitionInRandomRing(theCoalition, objType, x, z, innerRadius, outerRadius, heading, alive) \
        if not outerRadius then outerRadius = innerRadius end\
        if not heading then heading = math.random(360) * 3.1415 / 180 end\
        local dead = not alive\
        local p = dcsCommon.randomPointInCircle(outerRadius, innerRadius, x, z)\
        local theData = dcsCommon.createStaticObjectData(dcsCommon.uuid(\"static\"), objType, heading, dead)\
        theData.x = p.x\
        theData.y = p.z \
        \
        local theStatic = coalition.addStaticObject(theCoalition, theData)\
        return theStatic\
    end\
    \
    \
    \
    function dcsCommon.linkStaticDataToUnit(theStatic, theUnit, dx, dy, heading)\
        if not theStatic then \
            trigger.action.OutText(\"+++dcsC: NIL theStatic on linkStatic!\", 30)\
            return \
        end\
        -- NOTE: we may get current heading and subtract/add \
        -- to original heading \
        local rotX, rotY = dcsCommon.rotatePointAroundOrigin(dx, dy, -heading)\
        \
        if not theUnit then return end\
        if not theUnit:isExist() then return end \
        theStatic.linkOffset = true \
        theStatic.linkUnit = theUnit:getID()\
        local unitPos = theUnit:getPoint()\
        local offsets = {}\
        offsets.x = rotX  \
        offsets.y = rotY \
        offsets.angle = 0\
        theStatic.offsets = offsets\
    end\
    \
    function dcsCommon.offsetStaticData(theStatic, dx, dy)\
        theStatic.x = theStatic.x + dx\
        theStatic.y = theStatic.y + dy\
        -- now check if thre is a route (for linked objects)\
        if theStatic.route then \
            -- access points[1] x and y and copy from main\
            theStatic.route.points[1].x = theStatic.x\
            theStatic.route.points[1].y = theStatic.y\
        end\
    end\
    \
    function dcsCommon.moveStaticDataTo(theStatic, x, y)\
        theStatic.x = x\
        theStatic.y = y\
        -- now check if thre is a route (for linked objects)\
        if theStatic.route then \
            -- access points[1] x and y and copy from main\
            theStatic.route.points[1].x = theStatic.x\
            theStatic.route.points[1].y = theStatic.y\
        end\
\
    end\
    \
--\
--\
-- M I S C   M E T H O D S \
--\
--\
\
    function dcsCommon.arrayContainsString(theArray, theString) \
        if not theArray then return false end\
        if not theString then return false end\
        for i = 1, #theArray do \
            if theArray[i] == theString then return true end \
        end\
        return false \
    end\
    \
    function dcsCommon.splitString(inputstr, sep) \
        if sep == nil then\
            sep = \"%s\"\
        end\
        if inputstr == nil then \
            inputstr = \"\"\
        end\
        \
        local t={}\
        for str in string.gmatch(inputstr, \"([^\"..sep..\"]+)\") do\
            table.insert(t, str)\
        end\
        return t\
    \
    end\
    \
    function dcsCommon.trimFront(inputstr) \
        if not inputstr then return nil end \
        local s = inputstr\
        while string.len(s) > 1 and string.sub(s, 1, 1) == \" \" do \
            local snew = string.sub(s, 2) -- all except first\
            s = snew\
        end\
        return s\
    end\
    \
    function dcsCommon.trimBack(inputstr)\
        if not inputstr then return nil end \
        local s = inputstr\
        while string.len(s) > 1 and string.sub(s, -1) == \" \" do \
            local snew = string.sub(s, 1, -2) -- all except last\
            s = snew\
        end\
        return s\
    end\
    \
    function dcsCommon.trim(inputstr) \
        local t1 = dcsCommon.trimFront(inputstr)\
        local t2 = dcsCommon.trimBack(t1)\
        return t2\
    end\
    \
    function dcsCommon.trimArray(theArray)\
        local trimmedArray = {}\
        for idx, element in pairs(theArray) do \
            local tel = dcsCommon.trim(element)\
            table.insert(trimmedArray, tel)\
        end\
        return trimmedArray\
    end\
    \
    -- same as cfxZones, this is the commonly used, may need to remove from zones\
    function dcsCommon.stringStartsWith(theString, thePrefix)\
        return theString:find(thePrefix) == 1\
    end\
    \
    function dcsCommon.removePrefix(theString, thePrefix)\
        if not dcsCommon.stringStartsWith(theString, thePrefix) then \
            return theString\
        end;\
        return theString:sub(1 + #thePrefix)\
    end\
    \
    function dcsCommon.stringEndsWith(theString, theEnding)\
        return theEnding == \"\" or str:sub(-#theEnding) == theEnding\
    end\
    \
    function dcsCommon.removeEnding(theString, theEnding) \
        if not dcsCommon.stringEndsWith(theString, theEnding) then \
            return theString\
        end\
        return theString:sub(1, #theString - #theEnding)\
    end\
    \
    function dcsCommon.containsString(inString, what, caseSensitive)\
        if (not caseSensitive) then \
            inString = string.upper(inString)\
            what = string.upper(what)\
        end\
        if inString == what then return true end -- when entire match \
        return string.find(inString, what)\
    end\
    \
    function dcsCommon.bool2Text(theBool) \
        if not theBool then theBool = false end \
        if theBool then return \"true\" end \
        return \"false\"\
    end\
    \
    function dcsCommon.bool2YesNo(theBool)\
        if not theBool then theBool = false end \
        if theBool then return \"yes\" end \
        return \"no\"\
    end\
\
    -- recursively show the contents of a variable\
    function dcsCommon.dumpVar(key, value, prefix, inrecursion)\
        if not inrecursion then \
            -- output a marker to find in the log / screen\
            env.info(\"*** dcsCommon vardump START\")\
        end\
        if not value then value = \"nil\" end\
        if not prefix then prefix = \"\" end\
        prefix = \" \" .. prefix\
        if type(value) == \"table\" then \
            env.info(prefix .. key .. \": [ \")\
            -- iterate through all kvp\
            for k,v in pairs (value) do\
                dcsCommon.dumpVar(k, v, prefix, true)\
            end\
            env.info(prefix .. \" ] - end \" .. key)\
            \
        elseif type(value) == \"boolean\" then \
            local b = \"false\"\
            if value then b = \"true\" end\
            env.info(prefix .. key .. \": \" .. b)\
            \
        else -- simple var, show contents, ends recursion\
            env.info(prefix .. key .. \": \" .. value)\
        end\
        \
        if not inrecursion then \
            -- output a marker to find in the log / screen\
            trigger.action.outText(\"=== dcsCommon vardump END\", 30)\
            env.info(\"=== dcsCommon vardump END\")\
        end\
    end\
    \
    function dcsCommon.dumpVar2Str(key, value, prefix, inrecursion)\
        if not inrecursion then \
            -- output a marker to find in the log / screen\
            trigger.action.outText(\"*** dcsCommon vardump START\",30)\
        end\
        if not value then value = \"nil\" end\
        if not prefix then prefix = \"\" end\
        prefix = \" \" .. prefix\
        if type(value) == \"table\" then \
            trigger.action.outText(prefix .. key .. \": [ \", 30)\
            -- iterate through all kvp\
            for k,v in pairs (value) do\
                dcsCommon.dumpVar2Str(k, v, prefix, true)\
            end\
            trigger.action.outText(prefix .. \" ] - end \" .. key, 30)\
            \
        elseif type(value) == \"boolean\" then \
            local b = \"false\"\
            if value then b = \"true\" end\
            trigger.action.outText(prefix .. key .. \": \" .. b, 30)\
            \
        else -- simple var, show contents, ends recursion\
            trigger.action.outText(prefix .. key .. \": \" .. value, 30)\
        end\
        \
        if not inrecursion then \
            -- output a marker to find in the log / screen\
            trigger.action.outText(\"=== dcsCommon vardump END\", 30)\
            --env.info(\"=== dcsCommon vardump END\")\
        end\
    end\
    \
\
    dcsCommon.simpleUUID = 76543 -- a number to start. as good as any\
    function dcsCommon.numberUUID()\
        dcsCommon.simpleUUID = dcsCommon.simpleUUID + 1\
        return dcsCommon.simpleUUID\
    end\
\
    function dcsCommon.uuid(prefix)\
        dcsCommon.uuIdent = dcsCommon.uuIdent + 1\
        if not prefix then prefix = dcsCommon.uuidStr end\
        return prefix .. \"-\" .. dcsCommon.uuIdent\
    end\
    \
    function dcsCommon.event2text(id) \
        if not id then return \"error\" end\
        if id == 0 then return \"invalid\" end\
        -- translate the event id to text\
        local events = {\"shot\", \"hit\", \"takeoff\", \"land\",\
                        \"crash\", \"eject\", \"refuel\", \"dead\",\
                        \"pilot dead\", \"base captured\", \"mission start\", \"mission end\", -- 12\
                        \"took control\", \"refuel stop\", \"birth\", \"human failure\", \
                        \"det. failure\", \"engine start\", \"engine stop\", \"player enter unit\",\
                        \"player leave unit\", \"player comment\", \"start shoot\", \"end shoot\",\
                        \"mark add\", \"mark changed\", \"makr removed\", \"kill\", \
                        \"score\", \"unit lost\", \"land after eject\", \"Paratrooper land\", \
                        \"chair discard after eject\", \"weapon add\", \"trigger zone\", \"landing quality mark\",\
                        \"BDA\", \"max\"}\
        if id > #events then return \"Unknown (ID=\" .. id .. \")\" end\
        return events[id]\
    end\
\
    function dcsCommon.smokeColor2Text(smokeColor)\
        if (smokeColor == 0) then return \"Green\" end\
        if (smokeColor == 1) then return \"Red\" end\
        if (smokeColor == 2) then return \"White\" end\
        if (smokeColor == 3) then return \"Orange\" end\
        if (smokeColor == 4) then return \"Blue\" end\
        \
        return (\"unknown: \" .. smokeColor)\
    end\
    \
    function dcsCommon.smokeColor2Num(smokeColor)\
        if not smokeColor then smokeColor = \"green\" end \
        if type(smokeColor) ~= \"string\" then return 0 end \
        smokeColor = smokeColor:lower()\
        if (smokeColor == \"green\") then return 0 end \
        if (smokeColor == \"red\") then return 1 end \
        if (smokeColor == \"white\") then return 2 end \
        if (smokeColor == \"orange\") then return 3 end \
        if (smokeColor == \"blue\") then return 4 end \
        return 0\
    end\
    \
    function dcsCommon.markPointWithSmoke(p, smokeColor)\
        local x = p.x \
        local z = p.z -- do NOT change the point directly\
        -- height-correct\
        local y = land.getHeight({x = x, y = z})\
        local newPoint= {x = x, y = y + 2, z = z}\
        trigger.action.smoke(newPoint, smokeColor)\
    end\
\
--\
--\
-- V E C T O R   M A T H \
--\
--\
function dcsCommon.vAdd(a, b) \
    local r = {}\
    if not a then a = {x = 0, y = 0, z = 0} end\
    if not b then b = {x = 0, y = 0, z = 0} end\
    r.x = a.x + b.x \
    r.y = a.y + b.y \
    r.z = a.z + b.z \
    return r \
end\
\
function dcsCommon.vSub(a, b) \
    local r = {}\
    if not a then a = {x = 0, y = 0, z = 0} end\
    if not b then b = {x = 0, y = 0, z = 0} end\
    r.x = a.x - b.x \
    r.y = a.y - b.y \
    r.z = a.z - b.z \
    return r \
end\
\
function dcsCommon.vMultScalar(a, f) \
    local r = {}\
    if not a then a = {x = 0, y = 0, z = 0} end\
    if not f then f = 0 end\
    r.x = a.x * f \
    r.y = a.y * f \
    r.z = a.z * f \
    return r \
end\
\
function dcsCommon.vLerp (a, b, t)\
    if not a then a = {x = 0, y = 0, z = 0} end\
    if not b then b = {x = 0, y = 0, z = 0} end\
    \
    local d = dcsCommon.vSub(b, a)\
    local dt = dcsCommon.vMultScalar(d, t)\
    local r = dcsCommon.vAdd(a, dt)\
    return r\
end\
\
function dcsCommon.mag(x, y, z) \
    if not x then x = 0 end\
    if not y then y = 0 end \
    if not z then z = 0 end \
    \
    return (x * x + y * y + z * z)^0.5\
end\
\
function dcsCommon.vMag(a) \
    if not a then return 0 end \
    if not a.x then a.x = 0 end \
    if not a.y then a.y = 0 end \
    if not a.z then a.z = 0 end\
    return dcsCommon.mag(a.x, a.y, a.z) \
end\
\
function dcsCommon.magSquare(x, y, z) \
    if not x then x = 0 end\
    if not y then y = 0 end \
    if not z then z = 0 end \
    \
    return (x * x + y * y + z * z)\
end\
\
function dcsCommon.dot (a, b) \
    if not a then a = {} end \
    if not a.x then a.x = 0 end \
    if not a.y then a.y = 0 end \
    if not a.z then a.z = 0 end\
    if not b then b = {} end \
    if not b.x then b.x = 0 end \
    if not b.y then b.y = 0 end \
    if not b.z then b.z = 0 end \
    \
    return a.x * b.x + a.y * b.y + a.z * b.z \
end\
--\
-- UNIT MISC\
-- \
function dcsCommon.isSceneryObject(theUnit)\
    if not theUnit then return false end\
    return theUnit.getCoalition == nil -- scenery objects do not return a coalition \
end\
\
function dcsCommon.isTroopCarrier(theUnit)\
    -- return true if conf can carry troups\
    if not theUnit then return false end \
    local uType = theUnit:getTypeName()\
    if dcsCommon.arrayContainsString(dcsCommon.troopCarriers, uType) then \
        -- may add additional tests before returning true\
        return true\
    end\
    return false\
end\
\
function dcsCommon.getUnitAlt(theUnit)\
    if not theUnit then return 0 end\
    if not theUnit:isExist() then return 0 end \
    local p = theUnit:getPoint()\
    return p.y \
end\
\
function dcsCommon.getUnitAGL(theUnit)\
    if not theUnit then return 0 end\
    if not theUnit:isExist() then return 0 end \
    local p = theUnit:getPoint()\
    local alt = p.y \
    local loc = {x = p.x, y = p.z}\
    local landElev = land.getHeight(loc)\
    return alt - landElev\
end \
\
function dcsCommon.getUnitSpeed(theUnit)\
    if not theUnit then return 0 end\
    if not theUnit:isExist() then return 0 end \
    local v = theUnit:getVelocity()\
    return dcsCommon.mag(v.x, v.y, v.z)\
end\
\
-- closing velocity of u1 and u2, seen from u1\
function dcsCommon.getClosingVelocity(u1, u2)\
    if not u1 then return 0 end \
    if not u2 then return 0 end \
    if not u1:isExist() then return 0 end \
    if not u2:isExist() then return 0 end \
    local v1 = u1:getVelocity()\
    local v2 = u2:getVelocity()\
    local dV = dcsCommon.vSub(v1,v2)\
    local a = u1:getPoint()\
    local b = u2:getPoint() \
    local aMinusB = dcsCommon.vSub(a,b) -- vector from u2 to u1\
    local abMag = dcsCommon.vMag(aMinusB) -- distance u1 to u2 \
    if abMag < .0001 then return 0 end \
    -- project deltaV onto vector from u2 to u1 \
    local vClose = dcsCommon.dot(dV, aMinusB) / abMag \
    return vClose \
end\
\
function dcsCommon.getGroupAvgSpeed(theGroup)\
    if not theGroup then return 0 end \
    if not dcsCommon.isGroupAlive(theGroup) then return 0 end \
    local totalSpeed = 0\
    local cnt = 0 \
    local livingUnits = theGroup:getUnits()\
    for idx, theUnit in pairs(livingUnits) do \
        cnt = cnt + 1\
        totalSpeed = totalSpeed + dcsCommon.getUnitSpeed(theUnit)\
    end \
    if cnt == 0 then return 0 end \
    return totalSpeed / cnt \
end\
 \
function dcsCommon.getGroupMaxSpeed(theGroup)\
    if not theGroup then return 0 end \
    if not dcsCommon.isGroupAlive(theGroup) then return 0 end \
    local maxSpeed = 0\
    local livingUnits = theGroup:getUnits()\
    for idx, theUnit in pairs(livingUnits) do \
        currSpeed = dcsCommon.getUnitSpeed(theUnit)\
        if currSpeed > maxSpeed then maxSpeed = currSpeed end \
    end \
    return maxSpeed\
end \
\
function dcsCommon.getUnitHeading(theUnit)\
    if not theUnit then return 0 end \
    if not theUnit:isExist() then return 0 end \
    local pos = theUnit:getPosition() -- returns three vectors, p is location\
\
    local heading = math.atan2(pos.x.z, pos.x.x)\
    -- make sure positive only, add 260 degrees\
    if heading < 0 then\
        heading = heading + 2 * math.pi    -- put heading in range of 0 to 2*pi\
    end\
    return heading \
end\
\
function dcsCommon.getUnitHeadingDegrees(theUnit)\
    local heading = dcsCommon.getUnitHeading(theUnit)\
    return heading * 57.2958 -- 180 / math.pi \
end\
\
function dcsCommon.unitIsInfantry(theUnit)\
    if not theUnit then return false end \
    if not theUnit:isExist() then return end\
    local theType = theUnit:getTypeName()\
    local isInfantry =  \
                dcsCommon.containsString(theType, \"infantry\", false) or \
                dcsCommon.containsString(theType, \"paratrooper\", false) or\
                dcsCommon.containsString(theType, \"stinger\", false) or\
                dcsCommon.containsString(theType, \"manpad\", false) or\
                dcsCommon.containsString(theType, \"soldier\", false)\
    return isInfantry\
end\
\
function dcsCommon.coalition2county(inCoalition)\
    -- simply return UN troops for 0 neutral,\
    -- joint red for 1  red\
    -- joint blue for 2 blue \
    if inCoalition == 1 then return 81 end -- cjtf red\
    if inCoalition == 2 then return 80 end -- blue \
    if type(inCoalition) == \"string\" then \
            inCoalition = inCoalition:lower()\
            if inCoalition == \"red\" then return 81 end\
            if inCoalition == \"blue\" then return 80 end\
    end\
        \
    trigger.action.outText(\"+++dcsC: coalition2county in (\" .. inCoalition .. \") converts to UN (82)!\", 30)\
    return 82 -- UN \
    \
end\
\
--\
--\
-- INIT\
--\
--\
    -- init any variables the lib requires internally\
    function dcsCommon.init()\
        cbID = 0\
        dcsCommon.uuIdent = 0\
        if (dcsCommon.verbose) then\
          trigger.action.outText(\"dcsCommon v\" .. dcsCommon.version .. \" loaded successfully\", 10)\
        end\
    end\
\
    \
-- do init. \
dcsCommon.init()\
\
--[[--\
\
to do: \
- formation 2Column\
- formation 3Column\
\
-]]--\
",
                    ["predicate"] = "a_do_script",
                }, -- end of [1]
                [2] = 
                {
                    ["text"] = "-- cf/x zone management module\
-- reads dcs zones and makes them accessible and mutable \
-- by scripting.\
--\
-- Copyright (c) 2021 by Christian Franz and cf/x AG\
--\
\
cfxZones = {}\
cfxZones.version = \"2.4.10\"\
--[[-- VERSION HISTORY\
 - 2.2.4 - getCoalitionFromZoneProperty\
         - getStringFromZoneProperty\
 - 2.2.5 - createGroundUnitsInZoneForCoalition corrected coalition --> country \
 - 2.2.6 - getVectorFromZoneProperty(theZone, theProperty, defaultVal)\
 - 2.2.7 - allow 'yes' as 'true' for boolean attribute \
 - 2.2.8 - getBoolFromZoneProperty supports default \
         - cfxZones.hasProperty\
 - 2.3.0 - property names are case insensitive \
 - 2.3.1 - getCoalitionFromZoneProperty allows 0, 1, 2 also\
 - 2.4.0 - all zones look for owner attribute, and set it to 0 (neutral) if not present \
 - 2.4.1 - getBoolFromZoneProperty upgraded by expected bool \
         - markZoneWithSmoke raised by 3 meters\
 - 2.4.2 - getClosestZone also returns delta \
 - 2.4.3 - getCoalitionFromZoneProperty() accepts 'all' as neutral \
           createUniqueZoneName()\
           getStringFromZoneProperty returns default if property value = \"\"\
           corrected bug in addZoneToManagedZones\
 - 2.4.4 - getPoint(aZone) returns uip-to-date pos for linked and normal zones\
         - linkUnit can use \"useOffset\" property to keep relative position\
 - 2.4.5 - updated various methods to support getPoint when referencing \
           zone.point  \
 - 2.4.6 - corrected spelling in markZoneWithSmoke\
 - 2.4.7 - copy reference to dcs zone into cfx zone \
 - 2.4.8 - getAllZoneProperties\
 - 2.4.9 - createSimpleZone no longer requires location \
         - parse dcs adds empty .properties = {} if none tehre \
         - createCircleZone adds empty properties \
         - createPolyZone adds empty properties \
 - 2.4.10 - pickRandomZoneFrom now defaults to all cfxZones.zones\
          - getBoolFromZoneProperty also recognizes 0, 1\
          - removed autostart\
 \
--]]--\
cfxZones.verbose = true\
cfxZones.caseSensitiveProperties = false -- set to true to make property names case sensitive \
cfxZones.ups = 1 -- updates per second. updates moving zones\
\
cfxZones.zones = {} -- these are the zone as retrieved from the mission.\
                    -- ALWAYS USE THESE, NEVER DCS's ZONES!!!!\
\
-- a zone has the following attributes\
-- x, z -- coordinate of center. note they have correct x, 0, z coordinates so no y-->z mapping\
-- radius (zero if quad zone)\
-- isCircle (true if quad zone)\
-- poly the quad coords are in the poly attribute and are a \
-- 1..n, wound counter-clockwise as (currently) in DCS:\
-- lower left, lower right upper left, upper right, all coords are x, 0, z \
-- bounds - contain the AABB coords for the zone: ul (upper left), ur, ll (lower left), lr \
--          for both circle and poly, all (x, 0, z)\
\
-- zones can carry information in their names that can get processed into attributes\
-- use \
-- zones can also carry information in their 'properties' tag that ME allows to \
-- edit. cfxZones provides an easy method to access these properties \
--  - getZoneProperty (returns as string)\
--  - getMinMaxFromZoneProperty\
--  - getBoolFromZoneProperty\
--  - getNumberFromZoneProperty\
\
\
-- SUPPORTED PROPERTIES\
-- - \"linkedUnit\" - zone moves with unit of that name. must be exact match\
--   can be combined with other attributes that extend (e.g. scar manager and\
--   limited pilots/airframes \
--\
\
--\
-- readZonesFromDCS is executed exactly once at the beginning\
-- from then on, use only the cfxZones.zones table \
-- WARNING: cfxZones is NOT case-sensitive. All zone names are \
-- indexed by upper case. If you have two zones with same name but \
-- different case, one will be replaced\
--\
\
function cfxZones.readFromDCS(clearfirst)\
    if (clearfirst) then\
        cfxZones.zones = {}\
    end\
    -- not all missions have triggers or zones\
    if not env.mission.triggers then \
        if cfxZones.verbose then \
            trigger.action.outText(\"cf/x zones: no env.triggers defined\", 10)\
        end\
        return\
    end\
    \
    if not env.mission.triggers.zones then \
        if cfxZones.verbose then \
            trigger.action.outText(\"cf/x zones: no zones defined\", 10)\
        end\
        return;\
    end\
\
    -- we only retrive the data we need. At this point it is name, location and radius\
    -- and put this in our own little  structure. we also convert to all upper case name for index\
    -- and assume that the name may also carry meaning, e.g. 'LZ:' defines a landing zone\
    -- so we can quickly create other sets from this\
    -- zone object. DCS 2.7 introduced quads, so this is supported as well\
    --   name - name in upper case\
    --   isCircle - true if circular zone \
    --   isPoly - true if zone is defined by convex polygon, e.g. quad \
    --   point - vec3 (x 0 z) - zone's in-world center, used to place the coordinate\
    --   radius - number, zero when quad\
    --   bounds - aabb with attributes ul, ur, ll, lr (upper left .. lower right) as (x, 0, z)\
    --   poly - array 1..n of poly points, wound counter-clockwise \
    \
    for i, dcsZone in pairs(env.mission.triggers.zones) do\
        if type(dcsZone) == 'table' then -- hint taken from MIST: verify type when reading from dcs\
                                         -- dcs data is like a box of chocolates...\
            local newZone = {}\
            -- name, converted to upper is used only for indexing\
            -- the original name remains untouched\
            newZone.dcsZone = dcsZone\
            newZone.name = dcsZone.name\
            newZone.isCircle = false\
            newZone.isPoly = false\
            newZone.radius = 0\
            newZone.poly = {}\
            newZone.bounds = {}\
            newZone.properties = {} -- dcs has this too, copy if present\
            if dcsZone.properties then \
                newZone.properties = dcsZone.properties \
            else\
                newZone.properties = {}\
            end -- WARNING: REF COPY. May need to clone \
            \
            local upperName = newZone.name:upper()\
            \
            -- location as 'point'\
            -- WARNING: zones locs are 2D (x,y) pairs, whily y in DCS is altitude.\
            --          so we need to change (x,y) into (x, 0, z). Since Zones have no\
            --          altitude (they are an infinite cylinder) this works. Remember to \
            --          drop y from zone calculations to see if inside. \
            newZone.point = cfxZones.createPoint(dcsZone.x, 0, dcsZone.y)\
\
\
            -- start type processing. if zone.type exists, we have a mission \
            -- created with 2.7 or above, else earlier \
            local zoneType = 0\
            if (dcsZone.type) then \
                zoneType = dcsZone.type \
            end\
            \
            if zoneType == 0 then \
                -- circular zone \
                newZone.isCircle = true \
                newZone.radius = dcsZone.radius\
    \
            elseif zoneType == 2 then\
                -- polyZone\
                newZone.isPoly = true \
                newZone.radius = dcsZone.radius -- radius is still written in DCS, may change later\
                -- now transfer all point in the poly\
                -- note: DCS in 2.7 misspells vertices as 'verticies'\
                -- correct vor this \
                local verts = {}\
                if dcsZone.verticies then verts = dcsZone.verticies \
                else \
                    -- in later versions, this was corrected\
                    verts = dcsZone.vertices -- see if this is ever called\
                end\
                \
                for v=1, #verts do\
                    local dcsPoint = verts[v]\
                    local polyPoint = cfxZones.createPointFromDCSPoint(dcsPoint) -- (x, y) -- (x, 0, y-->z)\
                    newZone.poly[v] = polyPoint\
                end\
            else \
                \
                trigger.action.outText(\"cf/x zones: malformed zone #\" .. i .. \" unknown type \" .. zoneType, 10)\
            end\
            \
\
            -- calculate bounds\
            cfxZones.calculateZoneBounds(newZone) \
\
            -- add to my table\
            cfxZones.zones[upperName] = newZone -- WARNING: UPPER ZONE!!!\
        else\
            if cfxZones.verbose then \
                trigger.action.outText(\"cf/x zones: malformed zone #\" .. i .. \" dropped\", 10)\
            end\
        end -- else var not a table\
        \
    end -- for all zones kvp\
end -- readFromDCS\
\
function cfxZones.calculateZoneBounds(theZone)\
    if not (theZone) then return \
    end\
    \
    local bounds = theZone.bounds -- copy ref!\
    \
    if theZone.isCircle then \
        -- aabb are easy: center +/- radius \
        local center = theZone.point\
        local radius = theZone.radius \
        -- dcs uses z+ is down on map\
        -- upper left is center - radius \
        bounds.ul = cfxZones.createPoint(center.x - radius, 0, center.z - radius)\
        bounds.ur = cfxZones.createPoint(center.x + radius, 0, center.z - radius)\
        bounds.ll = cfxZones.createPoint(center.x - radius, 0, center.z + radius)\
        bounds.lr = cfxZones.createPoint(center.x + radius, 0, center.z + radius)\
        \
    elseif theZone.isPoly then\
        local poly = theZone.poly -- ref copy!\
        -- create the four points\
        local ll = cfxZones.createPointFromPoint(poly[1])\
        local lr = cfxZones.createPointFromPoint(poly[1])\
        local ul = cfxZones.createPointFromPoint(poly[1])\
        local ur = cfxZones.createPointFromPoint(poly[1])\
\
        -- now iterate through all points and adjust bounds accordingly \
        for v=2, #poly do \
             local vertex = poly[v]\
             if (vertex.x < ll.x) then ll.x = vertex.x; ul.x = vertex.x end \
             if (vertex.x > lr.x) then lr.x = vertex.x; ur.x = vertex.x end \
             if (vertex.z < ul.z) then ul.z = vertex.z; ur.z = vertex.z end\
             if (vertex.z > ll.z) then ll.z = vertex.z; lr.z = vertex.z end \
            \
        end\
        \
        -- now keep the new point references\
        -- and store them in the zone's bounds\
        bounds.ll = ll\
        bounds.lr = lr\
        bounds.ul = ul\
        bounds.ur = ur \
    else \
        -- huston, we have a problem\
        if cfxZones.verbose then \
            trigger.action.outText(\"cf/x zones: calc bounds: zone \" .. theZone.name .. \" has unknown type\", 30)\
        end\
    end\
    \
end\
\
function cfxZones.createPoint(x, y, z)\
    local newPoint = {}\
    newPoint.x = x\
    newPoint.y = y\
    newPoint.z = z \
    return newPoint\
end\
\
function cfxZones.copyPoint(inPoint) \
    local newPoint = {}\
    newPoint.x = inPoint.x\
    newPoint.y = inPoint.y\
    newPoint.z = inPoint.z \
    return newPoint    \
end\
\
function cfxZones.createHeightCorrectedPoint(inPoint) -- this should be in dcsCommon\
    local cP = cfxZones.createPoint(inPoint.x, land.getHeight({x=inPoint.x, y=inPoint.z}),inPoint.z)\
    return cP\
end\
\
function cfxZones.getHeightCorrectedZonePoint(theZone)\
    return cfxZones.createHeightCorrectedPoint(theZone.point)\
end\
\
function cfxZones.createPointFromPoint(inPoint)\
    return cfxZones.copyPoint(inPoint)\
end\
\
function cfxZones.createPointFromDCSPoint(inPoint) \
    return cfxZones.createPoint(inPoint.x, 0, inPoint.y)\
end\
\
\
function cfxZones.createRandomPointInsideBounds(bounds)\
    local x = math.random(bounds.ll.x, ur.x)\
    local z = math.random(bounds.ll.z, ur.z)\
    return cfxZones.createPoint(x, 0, z)\
end\
\
function cfxZones.addZoneToManagedZones(theZone)\
    local upperName = string.upper(theZone.name) -- newZone.name:upper()\
    cfxZones.zones[upperName] = theZone\
end\
\
function cfxZones.createUniqueZoneName(inName, searchSet)\
    if not inName then return nil end \
    if not searchSet then searchSet = cfxZones.zones end \
    inName = inName:upper()\
    while searchSet[inName] ~= nil do \
        inName = inName .. \"X\"\
    end\
    return inName\
end\
\
function cfxZones.createSimpleZone(name, location, radius, addToManaged)\
    if not radius then radius = 10 end\
    if not addToManaged then addToManaged = false end \
    if not location then \
        location = {}\
    end\
    if not location.x then location.x = 0 end \
    if not location.z then location.z = 0 end \
    \
    local newZone = cfxZones.createCircleZone(name, location.x, location.z, radius)\
    \
    if addToManaged then \
        cfxZones.addZoneToManagedZones(newZone)\
    end\
    return newZone\
end\
\
function cfxZones.createCircleZone(name, x, z, radius) \
    local newZone = {}\
    newZone.isCircle = true\
    newZone.isPoly = false\
    newZone.poly = {}\
    newZone.bounds = {}\
            \
    newZone.name = name\
    newZone.radius = radius\
    newZone.point = cfxZones.createPoint(x, 0, z)\
 \
    -- props \
    newZone.properties = {}\
    \
    -- calculate my bounds\
    cfxZones.calculateZoneBounds(newZone)\
    \
    return newZone\
end\
\
function cfxZones.createPolyZone(name, poly) -- poly must be array of point type\
local newZone = {}\
    newZone.isCircle = false\
    newZone.isPoly = true\
    newZone.poly = {}\
    newZone.bounds = {}\
            \
    newZone.name = name\
    newZone.radius = 0\
    -- copy poly\
    for v=1, #poly do \
        local theVertex = poly[v] \
        newZone.poly[v] = cfxZones.createPointFromPoint(theVertex) \
    end\
    \
    -- properties \
    newZone.properties = {}\
    \
    cfxZones.calculateZoneBounds(newZone)\
end\
\
\
\
function cfxZones.createRandomZoneInZone(name, inZone, targetRadius, entirelyInside)\
    -- create a new circular zone with center placed inside inZone\
    -- if entirelyInside is false, only the zone's center is guaranteed to be inside\
    -- inZone.\
    \
--    trigger.action.outText(\"Zones: creating rZiZ with tr = \" .. targetRadius .. \" for \" .. inZone.name .. \" that as r = \" .. inZone.radius, 10)\
    \
    if inZone.isCircle then \
        local sourceRadius = inZone.radius\
        if entirelyInside and targetRadius > sourceRadius then targetRadius = sourceRadius end\
        if entirelyInside then sourceRadius = sourceRadius - targetRadius end\
    \
        -- ok, let's first create a random percentage value for the new radius\
        local percent = 1 / math.random(100)\
        -- now lets get a random degree\
        local degrees = math.random(360) * 3.14152 / 180 -- ok, it's actually radiants. \
        local r = sourceRadius * percent \
        local x = inZone.point.x + r * math.cos(degrees)\
        local z = inZone.point.z + r * math.sin(degrees)\
        -- construct new zone\
        local newZone = cfxZones.createCircleZone(name, x, z, targetRadius)\
        return newZone\
    \
    elseif inZone.isPoly then \
        -- we have a poly zone. the way we do this is simple:\
        -- generate random x, z with ranges of the bounding box \
        -- until the point falls within the polygon.\
        local newPoint = {}\
        local emergencyBrake = 0\
        repeat\
            newPoint = cfxZones.createRandomPointInsideBounds(inZone.bounds)\
            emergencyBrake = emergencyBrake + 1\
            if (emergencyBrake > 100) then \
                newPoint = cfxZones.copyPoint(inZone.Point)\
                trigger.action.outText(\"CreateZoneInZone: mergency brake for inZone\" .. inZone.name,  10)\
                break\
            end\
        until cfxZones.isPointInsidePoly(newPoint, inZone.poly)\
        \
        -- construct new zone\
        local newZone = cfxZones.createCircleZone(name, newPoint.x, newPoint.z, targetRadius)\
        return newZone\
        \
    else \
        -- zone type unknown\
        trigger.action.outText(\"CreateZoneInZone: unknown zone type for inZone =\" .. inZone.name ,  10)\
        return nil \
    end\
end\
\
-- polygon inside zone calculations\
\
\
-- isleft returns true if point P is to the left of line AB \
-- by determining the sign (up or down) of the normal vector of \
-- the two vectors PA and PB in the y coordinate. We arbitrarily define\
-- left as being > 0, so right is <= 0. As long as we always use the \
-- same comparison, it does not matter what up or down mean.\
-- this is important because we don't know if dcs always winds quads\
-- the same way, we must simply assume that they are wound as a polygon \
function cfxZones.isLeftXZ(A, B, P)\
    return ((B.x - A.x)*(P.z - A.z) - (B.z - A.z)*(P.x - A.x)) > 0\
end\
\
-- returns true/false for inside\
function cfxZones.isPointInsideQuad(thePoint, A, B, C, D) \
    -- Inside test (only convex polygons): \
    -- point lies on the same side of each quad's vertex AB, BC, CD, DA\
    -- how do we find out which side a point lies on? via the cross product\
    -- see isLeft below\
    \
    -- so all we need to do is make sure all results of isLeft for all\
    -- four sides are the same\
    mustMatch = isLeftXZ(A, B, thePoint) -- all test results must be the same and we are ok\
                                       -- they just must be the same side.\
    if (cfxZones.isLeftXZ(B, C, thePoint ~= mustMatch)) then return false end -- on other side than all before\
    if (cfxZones.isLeftXZ(C, D, thePoint ~= mustMatch)) then return false end \
    if (cfxZones.isLeftXZ(D, A, thePoint ~= mustMatch)) then return false end\
    return true\
end\
\
-- generalized version of insideQuad, assumes winding of poly, poly convex, poly closed\
function cfxZones.isPointInsidePoly(thePoint, poly)\
    local mustMatch = cfxZones.isLeftXZ(poly[1], poly[2], thePoint)\
    for v=2, #poly-1 do \
        if cfxZones.isLeftXZ(poly[v], poly[v+1], thePoint) ~= mustMatch then return false end\
    end\
    -- final test\
    if cfxZones.isLeftXZ(poly[#poly], poly[1], thePoint) ~= mustMatch then return false end\
    \
    return true\
end;\
\
function cfxZones.isPointInsideZone(thePoint, theZone)\
    local p = {x=thePoint.x, y = 0, z = thePoint.z} -- zones have no altitude\
    if (theZone.isCircle) then \
        local d = dcsCommon.dist(p, theZone.point)\
        return d < theZone.radius\
    end \
    \
    if (theZone.isPoly) then \
        return (cfxZones.isPointInsidePoly(p, theZone.poly))\
    end\
\
    trigger.action.outText(\"isPointInsideZone: Unknown zone type for \" .. outerZone.name, 10)\
end\
\
-- isZoneInZone returns true if center of innerZone is inside  outerZone\
function cfxZones.isZoneInsideZone(innerZone, outerZone) \
    return cfxZones.isPointInsideZone(innerZone.point, outerZone)\
\
    \
end\
\
function cfxZones.getZonesContainingPoint(thePoint, testZones) -- return array \
    if not testZones then \
        testZones = cfxZones.zones \
    end \
    \
    local containerZones = {}\
    for tName, tData in pairs(testZones) do \
        if cfxZones.isPointInsideZone(thePoint, tData) then \
            table.insert(containerZones, tData)\
        end\
    end\
\
    return containerZones\
end\
\
function cfxZones.getFirstZoneContainingPoint(thePoint, testZones)\
    if not testZones then \
        testZones = cfxZones.zones \
    end \
    \
    for tName, tData in pairs(testZones) do \
        if cfxZones.isPointInsideZone(thePoint, tData) then \
            return tData\
        end\
    end\
\
    return nil\
end\
\
function cfxZones.getAllZonesInsideZone(superZone, testZones) -- returnes array!\
    if not testZones then \
        testZones = cfxZones.zones \
    end \
    \
    local containedZones = {}\
    for zName, zData in pairs(testZones) do\
        if cfxZones.isZoneInsideZone(zData, superZone) then \
            if zData ~= superZone then \
                -- we filter superzone because superzone usually resides \
                -- inside itself \
                table.insert(containedZones, zData)\
            end\
        end\
    end\
    return containedZones \
end\
\
function cfxZones.getZonesWithAttributeNamed(attributeName, testZones)\
    if not testZones then testZones = cfxZones.zones end \
    local attributZones = {}\
    for aName,aZone in pairs(testZones) do\
        local attr = cfxZones.getZoneProperty(aZone, attributeName)\
        if attr then \
            -- this zone has the requested attribute\
            table.insert(attributZones, aZone)\
        end\
    end\
    return attributZones\
end\
\
--\
-- units / groups in zone\
--\
function cfxZones.groupsOfCoalitionPartiallyInZone(coal, theZone, categ) -- categ is optional\
    local groupsInZone = {}\
    local allGroups = coalition.getGroups(coal, categ)\
    for key, group in pairs(allGroups) do -- iterate all groups\
        if group:isExist() then\
            \
            \
            if cfxZones.isGroupPartiallyInZone(group, theZone) then\
                \
                table.insert(groupsInZone, group)\
            else \
                \
            \
            end\
        end\
    end\
    return groupsInZone\
end\
\
function cfxZones.isGroupPartiallyInZone(aGroup, aZone)\
    if not aGroup then return false end \
    if not aZone then return false end \
    \
    \
    -- needs to be implemented\
    if not aGroup:isExist() then return false end \
    local allUnits = aGroup:getUnits()\
    for uk, aUnit in pairs (allUnits) do \
        if aUnit:isExist() and aUnit:getLife() > 1 then \
        \
            local p = aUnit:getPoint()\
--            p.y = 0 -- zones have no altitude\
            -- modification of isPointInsideZone now takes care of this\
            if cfxZones.isPointInsideZone(p, aZone) then             \
                return true\
            else \
                        \
            end \
        end\
    end\
    return false\
end\
\
function cfxZones.isEntireGroupInZone(aGroup, aZone)\
    if not aGroup then return false end \
    if not aZone then return false end \
    -- needs to be implemented\
    if not aGroup:isExist() then return false end \
    local allUnits = aGroup:getUnits()\
    for uk, aUnit in pairs (allUnits) do \
        if aUnit:isExist() and aUnit:getLife() > 1 then \
            local p = aUnit:getPoint()\
            if not cfxZones.isPointInsideZone(p, aZone) then \
                return false\
            end\
        end\
    end\
    return true\
end\
\
\
--\
-- Zone Manipulation\
--\
\
function cfxZones.offsetZone(theZone, dx, dz)\
    -- first, update center \
    theZone.point.x = theZone.point.x + dx\
    theZone.point.z = theZone.point.z + dz \
    \
    -- now process all polygon points - it's empty for circular, so don't worry\
    for v=1, #theZone.poly do \
        theZone.poly[v].x = theZone.poly[v].x + dx\
        theZone.poly[v].z = theZone.poly[v].z + dz \
    end\
end\
\
function cfxZones.moveZoneTo(theZone, x, z)\
    local dx = x - theZone.point.x\
    local dz = z - theZone.point.z \
    cfxZones.offsetZone(theZone, dx, dz)\
end;\
\
function cfxZones.centerZoneOnUnit(theZone, theUnit) \
    local thePoint = theUnit:getPoint()\
    cfxZones.moveZoneTo(theZone, thePoint.x, thePoint.z)\
end\
\
\
--[[\
-- no longer makes sense with poly zones\
function cfxZones.isZoneEntirelyInsideZone(innerZone, outerZone)\
    if (innerZone.radius > outerZone.radius) then return false end -- cant fit inside\
    local d = dcsCommon.dist(innerZone.point, outerZone.point)\
    local reducedR = outerZone.radius - innerZone.radius\
    return d < reducedR\
end;\
--]]\
\
function cfxZones.dumpZones(zoneTable)\
    if not zoneTable then zoneTable = cfxZones.zones end \
    \
    trigger.action.outText(\"Zones START\", 10)\
    for i, zone in pairs(zoneTable) do \
        local myType = \"unknown\"\
        if zone.isCircle then myType = \"Circle\" end\
        if zone.isPoly then myType = \"Poly\" end \
        \
        trigger.action.outText(\"#\".. i .. \": \" .. zone.name .. \" of type \" .. myType, 10)\
    end\
    trigger.action.outText(\"Zones END\", 10)\
end\
\
function cfxZones.stringStartsWith(theString, thePrefix)\
    return theString:find(thePrefix) == 1\
end\
\
function cfxZones.keysForTable(theTable)\
    local keyset={}\
    local n=0\
\
    for k,v in pairs(tab) do\
        n=n+1\
        keyset[n]=k\
    end\
    return keyset\
end\
\
\
--\
-- return all zones that have a specific named property\
--\
function cfxZones.zonesWithProperty(propertyName, searchSet)\
    if not searchSet then searchSet = cfxZones.zones end \
    local theZones = {}\
    for k, aZone in pairs(searchSet) do \
        local lU = cfxZones.getZoneProperty(aZone, propertyName)\
        if lU then \
            table.insert(theZones, aZone)\
        end\
    end    \
    return theZones\
end\
\
--\
-- return all zones from the zone table that begin with string prefix\
--\
function cfxZones.zonesStartingWithName(prefix, searchSet)\
    \
    if not searchSet then searchSet = cfxZones.zones end \
    \
--    trigger.action.outText(\"Enter: zonesStartingWithName for \" .. prefix , 30)\
    local prefixZones = {}\
    prefix = prefix:upper() -- all zones have UPPERCASE NAMES! THEY SCREAM AT YOU\
    for name, zone in pairs(searchSet) do\
--        trigger.action.outText(\"testing \" .. name:upper() .. \" starts with \" .. prefix , 30)\
        if cfxZones.stringStartsWith(name:upper(), prefix) then\
            prefixZones[name] = zone -- note: ref copy!\
            --trigger.action.outText(\"zone with prefix <\" .. prefix .. \"> found: \" .. name, 10)\
        end\
    end\
    \
    return prefixZones\
end\
\
--\
-- return all zones from the zone table that begin with the string or set of strings passed in prefix \
-- if you pass 'true' as second (optional) parameter, it will first look for all zones that begin\
-- with '+' and return only those. Use during debugging to force finding a specific zone\
--\
function cfxZones.zonesStartingWith(prefix, searchSet, debugging)\
    -- you can force zones by having their name start with \"+\"\
    -- which will force them to return immediately if debugging is true for this call\
\
    if (debugging) then \
        local debugZones = cfxZones.zonesStartingWithName(\"+\", searchSet)\
        if not (next(debugZones) == nil) then -- # operator only works on array elements \
            --trigger.action.outText(\"returning zones with prefix <\" .. prefix .. \">\", 10)\
            return debugZones \
        end \
    end\
    \
    --trigger.action.outText(\"#debugZones is  <\" .. #debugZones .. \">\", 10)\
\
    if (type(prefix) == \"string\") then \
        return cfxZones.zonesStartingWithName(prefix, searchSet)\
    end\
    \
    local allZones = {}\
    for i=1, #prefix do \
        -- iterate through all names in prefix set\
        local theName = prefix[i]\
        local newZones = cfxZones.zonesStartingWithName(theName, searchSet)\
        -- add them all to current table\
        for zName, zInfo in pairs(newZones) do \
            allZones[zName] = zInfo -- will also replace doublets\
        end\
    end\
    \
    return allZones\
end\
\
function cfxZones.getZoneByName(aName, searchSet) \
    if not searchSet then searchSet = cfxZones.zones end \
    aName = aName:upper()\
    return searchSet[aName] -- the joys of key value pairs\
end\
\
function cfxZones.getZonesContainingString(aString, searchSet) \
    if not searchSet then searchSet = cfxZones.zones end\
    aString = string.upper(aString)\
    resultSet = {}\
    for zName, zData in pairs(searchSet) do \
        if aString == string.upper(zData.name) then \
            resultSet[zName] = zData\
        end\
    end\
    \
end;\
\
-- filter zones by range to a point. returns indexed set\
function cfxZones.getZonesInRange(point, range, theZones)\
    if not theZones then theZones = cfxZones.zones end\
    \
    local inRangeSet = {}\
    for zName, zData in pairs (theZones) do \
        if dcsCommon.dist(point, zData.point) < range then \
            table.insert(inRangeSet, zData)\
        end\
    end\
    return inRangeSet \
end\
\
-- get closest zone returns the zone that is closest to point \
function cfxZones.getClosestZone(point, theZones)\
    if not theZones then theZones = cfxZones.zones end\
    local currDelta = math.huge \
    local closestZone = nil\
    for zName, zData in pairs(theZones) do \
        local zPoint = cfxZone.getPoint(zData)\
        local delta = dcsCommon.dist(point, zPoint)\
        if (delta < currDelta) then \
            currDelta = delta\
            closestZone = zData\
        end\
    end\
    return closestZone, currDelta \
end\
\
-- return a random zone from the table passed in zones\
function cfxZones.pickRandomZoneFrom(zones)\
    if not zones then zones = cfxZones.zones end\
    local indexedZones = dcsCommon.enumerateTable(zones)\
    local r = math.random(#indexedZones)\
    return indexedZones[r]\
end\
\
-- return an zone element by index \
function cfxZones.getZoneByIndex(theZones, theIndex) \
    local enumeratedZones = dcsCommon.enumerateTable(theZones)\
    if (theIndex > #enumeratedZones) then\
        trigger.action.outText(\"WARNING: zone index \" .. theIndex .. \" out of bounds - max = \" .. #enumeratedZones, 30)\
        return nil end\
    if (theIndex < 1) then return nil end\
    \
    return enumeratedZones[theIndex]\
end\
\
-- place a smoke marker in center of zone, offset by dx, dy \
function cfxZones.markZoneWithSmoke(theZone, dx, dz, smokeColor)\
    local point = cfxZones.getPoint(theZone) --{} -- theZone.point\
    point.x = point.x + dx -- getpoint updates and returns copy \
    point.z = point.z + dz \
    -- get height at point \
    point.y = land.getHeight({x = point.x, y = point.z}) + 5\
    -- height-correct\
    --local newPoint= {x = point.x, y = land.getHeight({x = point.x, y = point.z}) + 3, z= point.z}\
    trigger.action.smoke(point, smokeColor)\
end\
\
-- place a smoke marker in center of zone, offset by radius and degrees \
function cfxZones.markZoneWithSmokePolar(theZone, radius, degrees, smokeColor)\
    local rads = degrees * math.pi / 180\
    local dx = radius * math.sin(rads)\
    local dz = radius * math.cos(rads)\
    cfxZones.markZoneWithSmoke(theZone, dx, dz, smokeColor)\
end\
\
-- place a smoke marker in center of zone, offset by radius and randomized degrees \
function cfxZones.markZoneWithSmokePolarRandom(theZone, radius, smokeColor)\
    local degrees = math.random(360)\
    cfxZones.markZoneWithSmokePolar(theZone, radius, degrees, smokeColor)\
end\
\
\
-- unitInZone returns true if theUnit is inside the zone \
-- the second value returned is the percentage of distance\
-- from center to rim, with 100% being entirely in center, 0 = outside\
-- the third value returned is the distance to center\
function cfxZones.pointInZone(thePoint, theZone)\
    if not (theZone) then return false, 0, 0 end\
        \
    local pflat = {x = thePoint.x, y = 0, z = thePoint.z}\
    \
    local zpoint = cfxZones.getPoint(theZone) -- updates zone if linked \
    local ppoint = thePoint -- xyz\
    local pflat = {x = ppoint.x, y = 0, z = ppoint.z}\
    local dist = dcsCommon.dist(zpoint, pflat)\
    \
    if theZone.isCircle then \
        if theZone.radius <= 0 then \
            return false, 0, 0\
        end\
\
        local success = dist < theZone.radius\
        local percentage = 0\
        if (success) then \
            percentage = 1 - dist / theZone.radius \
        end\
        return success, percentage, dist \
    \
    elseif theZone.isPoly then\
        local success = cfxZones.isPointInsidePoly(pflat, theZone.poly)\
        return success, 0, dist\
    else \
        trigger.action.outText(\"pointInZone: Unknown zone type for \" .. theZone.name, 10)\
    end\
\
    return false\
end\
\
function cfxZones.unitInZone(theUnit, theZone)\
    if not (theUnit) then return false, 0, 0 end\
    if not (theUnit:isExist()) then return false, 0, 0 end\
    -- force zone update if it is linked to another zone \
    -- pointInZone does update\
    local thePoint = theUnit:getPoint()\
    return cfxZones.pointInZone(thePoint, theZone)\
    \
end\
\
-- returns all units of the input set that are inside the zone \
function cfxZones.unitsInZone(theUnits, theZone)\
    if not theUnits then return {} end\
    if not theZone then return {} end\
    \
    local zoneUnits = {}\
    for index, aUnit in pairs(theUnits) do \
        if cfxZones.unitInZone(aUnit, theZone) then \
            table.insert( zoneUnits, aUnit)\
        end\
    end\
    return zoneUnits\
end\
\
function cfxZones.closestUnitToZoneCenter(theUnits, theZone)\
    -- does not care if they really are in zone. call unitsInZone first\
    -- if you need to have them filtered\
    -- theUnits MUST BE ARRAY\
    if not theUnits then return nil end\
    if #theUnits == 0 then return nil end\
    local closestUnit = theUnits[1]\
    for i=2, #theUnits do\
        local aUnit = theUnits[i]\
        if dcsCommon.dist(theZone.point, closestUnit:getPoint()) > dcsCommon.dist(theZone.point, aUnit:getPoint()) then \
            closestUnit = aUnit\
        end\
    end\
    return closestUnit\
end\
\
function cfxZones.anyPlayerInZone(theZone) -- returns first player it finds\
    for pname, pinfo in pairs(cfxPlayer.playerDB) do\
        local playerUnit = pinfo.unit\
        if (cfxZones.unitInZone(playerUnit, theZone)) then \
            return true, playerUnit\
        end\
    end -- for all players \
    return false, nil\
end\
\
\
-- grow zone\
function cfxZones.growZone()\
    -- circular zones simply increase radius\
    -- poly zones: not defined \
    \
end\
\
\
-- creating units in a zone\
function cfxZones.createGroundUnitsInZoneForCoalition (theCoalition, groupName, theZone, theUnits, formation, heading) \
    -- theUnits can be string or table of string \
    if not groupName then groupName = \"G_\"..theZone.name end \
    -- group name will be taken from zone name and prependend with \"G_\"\
    local theGroup = dcsCommon.createGroundGroupWithUnits(groupName, theUnits, theZone.radius, nil, formation)\
    \
    -- turn the entire formation to heading\
    if (not heading) then heading = 0 end\
    dcsCommon.rotateGroupData(theGroup, heading) -- currently, group is still at origin, no cx, cy\
    \
    \
    -- now move the group to center of theZone\
    dcsCommon.moveGroupDataTo(theGroup, \
                          theZone.point.x, \
                          theZone.point.z) -- watchit: Z!!!\
\
\
    -- create the group in the world and return it\
    -- first we need to translate the coalition to a legal \
    -- country. we use UN for neutral, cjtf for red and blue \
    local theSideCJTF = dcsCommon.coalition2county(theCoalition)\
    return coalition.addGroup(theSideCJTF, Group.Category.GROUND, theGroup)\
\
end\
\
-- parsing zone names. The first part of the name until the first blank \" \" \
-- is the prefix and is dropped unless keepPrefix is true. \
-- all others are regarded as key:value pairs and are then added \
-- to the zone \
-- separated by equal sign \"=\" AND MUST NOT CONTAIN BLANKS\
--\
-- example usage \"followZone unit=rotary-1 dx=30 dy=25 rotateWithHeading=true\
--\
-- OLD DEPRECATED TECH -- TO BE DECOMMISSIONED SOON, DO NOT USE\
-- \
--[[--\
function cfxZones.parseZoneNameIntoAttributes(theZone, keepPrefix)\
--    trigger.action.outText(\"Parsing zone:  \".. theZone.name, 30)\
    if not keepPrefix then keepPrefix = false end -- simply for clarity\
    -- now split the name into space-separated strings\
    local attributes = dcsCommon.splitString(theZone.name, \" \")\
    if not keepPrefix then table.remove(attributes, 1) end -- pop prefix\
\
    -- now parse all substrings and add them as attributes to theZone\
    for i=1, #attributes do \
        local a = attributes[i]\
        local kvp = dcsCommon.splitString(a, \"=\")\
        if #kvp == 2 then \
            -- we have key value pair\
            local theKey = kvp[1]\
            local theValue = kvp[2]\
            theZone[theKey] = theValue \
--            trigger.action.outText(\"Zone \".. theZone.name .. \" parsed: Key = \" .. theKey .. \", Value = \" .. theValue, 30)\
        else \
--            trigger.action.outText(\"Zone \".. theZone.name .. \": dropped attribute \" .. a, 30)\
        end\
    end \
end\
--]]--\
-- OLD DEPRECATED TECH -- TO BE DECOMMISSIONED SOON, DO NOT USE\
--[[--\
function cfxZones.processCraterZones ()\
    local craters = cfxZones.zonesStartingWith(\"crater\")\
\
    \
\
    -- all these zones need to be processed and their name infor placed into attributes\
    for cName, cZone in pairs(craters) do\
        cfxZones.parseZoneNameIntoAttributes(cZone)\
        \
        -- blow stuff up at the location of the zone \
        local cPoint = cZone.point\
        cPoint.y = land.getHeight({x = cPoint.x, y = cPoint.z})  -- compensate for ground level\
        trigger.action.explosion(cPoint, 900)\
         \
        -- now interpret and act on the crater info \
        -- to destroy and place fire. \
        \
        -- fire has small, medium, large \
        -- eg. fire=large\
        \
    end\
end\
--]]--\
\
--\
-- PROPERTY PROCESSING \
--\
\
function cfxZones.getAllZoneProperties(theZone, caseInsensitive) -- return as dict \
    if not caseInsensitive then caseInsensitive = false end \
    if not theZone then return {} end \
    \
    local dcsProps = theZone.properties -- zone properties in dcs format \
    local props = {}\
    -- dcs has all properties as array with values .key and .value \
    -- so convert them into a dictionary \
    for i=1, #dcsProps do \
        local theProp = dcsProps[i]\
        local theKey = \"dummy\"\
        if string.len(theProp.key) > 0 then theKey = theProp.key end \
        if caseInsensitive then theKey = theKey:upper() end \
        props[theKey] = theProp.value\
    end\
    return props \
end\
\
function cfxZones.extractPropertyFromDCS(theKey, theProperties)\
--    make lower case conversion if not case sensitive\
    if not cfxZones.caseSensitiveProperties then \
        theKey = string.lower(theKey)\
    end\
\
-- iterate all keys and compare to what we are looking for     \
    for i=1, #theProperties do\
        local theP = theProperties[i]\
        local existingKey = theP.key \
        if not cfxZones.caseSensitiveProperties then \
            existingKey = string.lower(existingKey)\
        end\
        if existingKey == theKey then \
            return theP.value\
        end\
    end\
    return nil \
end\
\
function cfxZones.getZoneProperty(cZone, theKey)\
    local props = cZone.properties\
    local theVal = cfxZones.extractPropertyFromDCS(theKey, props)\
    return theVal\
end\
\
function cfxZones.getStringFromZoneProperty(theZone, theProperty, default)\
    if not default then default = \"\" end\
    local p = cfxZones.getZoneProperty(theZone, theProperty)\
    if not p then return default end\
    if type(p) == \"string\" then \
        if p == \"\" then p = default end \
        return p\
    end\
    return default -- warning. what if it was a number first?\
end\
\
function cfxZones.getMinMaxFromZoneProperty(theZone, theProperty)\
    local p = cfxZones.getZoneProperty(theZone, theProperty)\
    local theNumbers = dcsCommon.splitString(p, \" \")\
\
    return tonumber(theNumbers[1]), tonumber(theNumbers[2])\
    \
end\
\
function cfxZones.hasProperty(theZone, theProperty) \
    return cfxZones.getZoneProperty(theZone, theProperty) ~= nil \
end\
\
\
function cfxZones.getBoolFromZoneProperty(theZone, theProperty, defaultVal)\
    if not defaultVal then defaultVal = false end \
    if type(defaultVal) ~= \"boolean\" then \
        defaultVal = false \
    end\
\
    if not theZone then \
        trigger.action.outText(\"WARNING: NIL Zone in getBoolFromZoneProperty\", 30)\
        return defaultVal\
    end\
\
\
    local p = cfxZones.getZoneProperty(theZone, theProperty)\
    if not p then return defaultVal end\
\
    -- make sure we compare so default always works when \
    -- answer isn't exactly the opposite\
    p = p:lower() \
    if defaultVal == false then \
        -- only go true if exact match to yes or true \
        theBool = false \
        theBool = (p == 'true') or (p == 'yes') or p == \"1\"\
        return theBool\
    end\
    \
    local theBool = true \
    -- only go false if exactly no or false or \"0\"\
    theBool = (p ~= 'false') and (p ~= 'no') and (p ~= \"0\") \
    return theBool\
end\
\
function cfxZones.getCoalitionFromZoneProperty(theZone, theProperty, default)\
    if not default then default = 0 end\
    local p = cfxZones.getZoneProperty(theZone, theProperty)\
    if not p then return default end  \
    if type(p) == \"number\" then -- can't currently really happen\
        if p == 1 then return 1 end \
        if p == 2 then return 2 end \
        return 0\
    end\
    \
    if type(p) == \"string\" then \
        if p == \"1\" then return 1 end \
        if p == \"2\" then return 2 end \
        if p == \"0\" then return 0 end \
        \
        p = p:lower()\
        \
        if p == \"red\" then return 1 end \
        if p == \"blue\" then return 2 end \
        if p == \"neutral\" then return 0 end\
        if p == \"all\" then return 0 end \
        return default \
    end\
    \
    return default \
end\
\
function cfxZones.getNumberFromZoneProperty(theZone, theProperty, default)\
--TODO: trim string \
    if not default then default = 0 end\
    local p = cfxZones.getZoneProperty(theZone, theProperty)\
    p = tonumber(p)\
    if not p then return default else return p end\
end\
\
function cfxZones.getVectorFromZoneProperty(theZone, theProperty, minDims, defaultVal)\
    if not minDims then minDims = 0 end \
    if not defaultVal then defaultVal = 0 end \
    local s = cfxZones.getStringFromZoneProperty(theZone, theProperty, \"\")\
    local sVec = dcsCommon.splitString(s, \",\")\
    local nVec = {}\
    for idx, numString in pairs (sVec) do \
        local n = tonumber(numString)\
        if not n then n = defaultVal end\
        table.insert(nVec, n)\
    end\
    -- make sure vector contains at least minDims values \
    while #nVec < minDims do \
        table.insert(nVec, defaultVal)\
    end\
    \
    return nVec \
end\
\
\
--\
-- Moving Zones. They contain a link to their unit\
-- they are always located at an offset (x,z) or delta, phi \
-- to their master unit. delta phi allows adjustment for heading\
-- The cool thing about moving zones in cfx is that they do not\
-- require special handling, they are always updated \
-- and work with 'pointinzone' etc automatically\
\
-- Always works on cfx Zones, NEVER on DCS zones.\
--\
-- requires that readFromDCS has been done\
--\
function cfxZones.getPoint(aZone) -- always works, wven linked, point can be reused \
    if aZone.linkedUnit then \
        local theUnit = aZone.linkedUnit\
        -- has a link. is link existing?\
        if theUnit:isExist() then \
            -- updates zone position \
            cfxZones.centerZoneOnUnit(aZone, theUnit)\
            cfxZones.offsetZone(aZone, aZone.dx, aZone.dy)\
        end\
    end\
    local thePos = {}\
    thePos.x = aZone.point.x\
    thePos.y = 0 -- aZone.y \
    thePos.z = aZone.point.z\
    return thePos \
end\
\
function cfxZones.linkUnitToZone(theUnit, theZone, dx, dy) -- note: dy is really Z, don't get confused!!!!\
    theZone.linkedUnit = theUnit\
    if not dx then dx = 0 end\
    if not dy then dy = 0 end \
    theZone.dx = dx\
    theZone.dy = dy \
end\
\
function cfxZones.updateMovingZones()\
    cfxZones.updateSchedule = timer.scheduleFunction(cfxZones.updateMovingZones, {}, timer.getTime() + 1/cfxZones.ups)\
    -- simply scan all cfx zones for the linkedUnit property and if there\
    -- update the zone's points\
    for aName,aZone in pairs(cfxZones.zones) do\
        if aZone.linkedUnit then \
            local theUnit = aZone.linkedUnit\
            -- has a link. is link existing?\
            if theUnit:isExist() then \
                cfxZones.centerZoneOnUnit(aZone, theUnit)\
                cfxZones.offsetZone(aZone, aZone.dx, aZone.dy)\
                --trigger.action.outText(\"cf/x zones update \" .. aZone.name, 30)\
            end\
        end\
    end\
end\
\
function cfxZones.startMovingZones()\
    -- read all zoness, and look for a property called 'linkedUnit'\
    -- which will make them a linked zone if there is a unit that exists\
    for aName,aZone in pairs(cfxZones.zones) do\
        local lU = cfxZones.getZoneProperty(aZone, \"linkedUnit\")\
        if lU then \
            -- this zone is linked to a unit\
            theUnit = Unit.getByName(lU)\
            local useOffset = cfxZones.getBoolFromZoneProperty(aZone, \"useOffset\", false)\
            if useOffset then aZone.useOffset = true end\
            if theUnit then\
                local dx = 0\
                local dz = 0\
                if useOffset then \
                    local delta = dcsCommon.vSub(aZone.point,theUnit:getPoint()) -- delta = B - A \
                    dx = delta.x \
                    dz = delta.z\
                end\
                cfxZones.linkUnitToZone(theUnit, aZone, dx, dz)\
                --trigger.action.outText(\"cf/x zones: linked \" .. aZone.name .. \" to \" .. theUnit:getName(), 30)\
                if useOffset then \
                    --trigger.action.outText(\"and dx = \" .. dx .. \" dz = \" .. dz, 30)\
                end\
            end\
 \
        end\
    end\
end\
\
--\
-- init\
--\
\
function cfxZones.init()\
    -- read all zones into my own db\
    cfxZones.readFromDCS(true) -- true: erase old\
    \
    -- now, pre-read zone owner for all zones\
    -- note, all zones with this property are by definition owned zones.\
    -- and hence will be read anyway. this will merely ensure that the \
    -- ownership is established right away\
    local pZones = cfxZones.zonesWithProperty(\"owner\")\
    for n, aZone in pairs(pZones) do\
        aZone.owner = cfxZones.getCoalitionFromZoneProperty(aZone, \"owner\", 0)\
    end\
        \
    \
    -- now initialize moving zones\
    cfxZones.startMovingZones()\
    cfxZones.updateMovingZones() -- will auto-repeat\
    \
    trigger.action.outText(\"cf/x Zones v\".. cfxZones.version .. \": loaded\", 10)\
end\
\
-- get everything rolling\
cfxZones.init()\
",
                    ["predicate"] = "a_do_script",
                }, -- end of [2]
                [3] = 
                {
                    ["text"] = "-- cfx player handler for DCS Missions by cf/x AG\
-- \
-- a module that provides easy access to a mission's player data\
-- multi-player only\
--\
\
cfxPlayer = {}\
                           -- a call to cfxPlayer.start()\
cfxPlayer.version = \"3.0.0\"\
--[[-- VERSION HISTORY\
\
- 2.2.3 - fixed isPlayerUnit() wrong return of true instead of nil\
- 2.2.4 - getFirstGroupPlayer\
- 2.3.0 - added event filtering for monitors\
        - limited code clean-up\
        - removed XXXmatchUnitToPlayer\
        - corrected isPlayerUnit once more\
        - removed autostart option\
        - removed detectPlayersLeaving option \
- 3.0.0 - added detection of network players \
        - added new events newPlayer, changePlayer \
        - and leavePlayer (never called)\
--]]--\
\
cfxPlayer.verbose = false;\
cfxPlayer.running = false \
cfxPlayer.ups = 1 -- updates per second: how often do we query the players \
                  -- a good value is 1\
cfxPlayer.playerDB = {} -- the list of all player UNITS\
        -- attributes\
            -- name - name of unit occupied by player\
            -- unit - unit this player is controlling\
            -- unitName - same as name\
            -- group - group this unit belongs to. can't change without also changing unit\
            -- groupName - name of group\
            -- coalition\
cfxPlayerGroups = {} -- GLOBAL VAR \
-- list of all current groups that have players in them \
-- can call out to handlers if group is added or removed\
-- use this in MP games to organise messaging and keep score\
-- by default, groupinfo merely contains the .group reference \
-- and is accessed by name as key which is also accessible by .name\
            \
cfxPlayer.netPlayers = {} -- new for version 3: real player detection\
-- a dict sorted by player name that containts the unit name for last pass \
\
cfxPlayer.updateSchedule = 0 -- ID used for scheduling update\
cfxPlayer.coalitionSides = {0, 1, 2} -- we currently have neutral, red, blue\
\
cfxPlayer.monitors = {} -- callbacks for events\
\
---\
-- structure of playerInfo\
--   - name - player's unit name\
--   - unit - the unit the player is occupying. Multi-Crew: many people can be in same unit\
--   - unitName same as name \
\
--   - coalition - the side the unit is on, as a number \
function cfxPlayer.dumpRawPlayers()\
    trigger.action.outText(\"+++ debug: raw player dump ---\", 30)\
    for i=1, #cfxPlayer.coalitionSides do \
        local theSide = cfxPlayer.coalitionSides[i] \
        -- get all players for this side\
        local thePlayers = coalition.getPlayers(theSide) \
        for p=1, #thePlayers do \
            aPlayerUnit = thePlayers[p] -- docs say this is a unit table, not a person table!\
            trigger.action.outText(i .. \"-\" .. p ..\": unit: \" .. aPlayerUnit:getName() .. \" controlled by \" .. aPlayerUnit:getPlayerName() , 30)\
        end\
    end\
    trigger.action.outText(\"+++ debug: END DUMP ----\", 30)\
end\
\
\
function cfxPlayer.getAllPlayers()\
    return cfxPlayer.playerDB -- get entire db. make sure not to screw around with it\
end\
\
\
function cfxPlayer.getPlayerInfoByName(theUnitName) -- note: UNIT name\
    thePlayer = cfxPlayer.playerDB[theUnitName] -- access the entry, not we are accessing by unit name\
    return thePlayer\
end\
\
function cfxPlayer.getPlayerInfoByIndex(theIndex) \
    local enumeratedInfo = dcsCommon.enumerateTable(cfxPlayer.playerDB)\
    if (theIndex > #enumeratedInfo) then\
        trigger.action.outText(\"WARNING: player index \" .. theIndex .. \" out of bounds - max = \" .. #enumeratedInfo, 30)\
        return nil end\
    if (theIndex < 1) then return nil end\
    \
    return enumeratedInfo[theIndex]\
end\
\
-- this is now a true/false function that returns true if unit is player \
function cfxPlayer.XXXmatchUnitToPlayer(theUnit) -- what's difference to getPlayerInfo? GetPlayerInfo ALLOCATES if not exists \
\
    if not (theUnit) then return false end\
    if not (theUnit:isExist()) then return false end \
    \
    -- PATCH: if theUnit:getPlayerName() returns anything but nil\
    -- this is a player unit\
    -- unfortunately, this can sometimes fail\
    -- so make sure the function existst\
    -- it failed because the next level up function \
    -- returned true if i returned anything but nil, and I return \
    -- true or false, both not nil \
    -- this proc works \
    if not theUnit.getPlayerName then return false end \
    \
    local pName = theUnit:getPlayerName()\
    if pName ~= nil then \
        -- trigger.action.outText(\"+++matchUnit: player name \" .. pName .. \" for unit \" .. theUnit:getName(), 30)\
        return true \
    end \
    \
    if (true) then \
        return false\
    end \
    \
    -- ignmore old code below\
\
    for pname, pInfo in pairs(cfxPlayer.playerDB) do \
        if (pInfo.unit == theUnit) then \
            return pInfo\
        end\
    end\
    return nil\
end\
\
function cfxPlayer.XXXisPlayerUnitAlt(theUnit)\
    for pname, pInfo in pairs(cfxPlayer.playerDB) do \
        if (pInfo.unit == theUnit) then \
            return true\
        end\
    end\
    return false\
end\
\
function cfxPlayer.isPlayerUnit(theUnit)\
    -- new patch. simply check if getPlayerName returns something\
    if not theUnit then return false end \
    local pName = theUnit:getPlayerName()\
    if pName then return true end \
    return false \
    --\
    -- fixed, erroneously expected a nil from matchUnitToPlayer \
    --return (cfxPlayer.matchUnitToPlayer(theUnit)) -- was: ~=nil, wrong because match returns true/false\
end\
\
\
\
function cfxPlayer.getPlayerUnitType(thePlayerInfo) -- \
    if (thePlayerInfo) then \
        theUnit = thePlayerInfo.unit\
        if (theUnit) and (theUnit:isExist()) then \
            return theUnit:getTypeName()\
        end\
    end\
    return nil \
end\
\
\
-- get player's unit info\
-- accesses player DB and returns the player's info record for the\
-- player's Unit. If record does not exist in db, a new record is allocated\
-- returns true if verification succeeeds: player unit existed before, and\
-- false otherwise. in the latter case, A NEW playerInfo object is returned\
function cfxPlayer.getPlayerInfo(theUnit)\
    local playerName = theUnit:getPlayerName() -- retrieve the name \
    --- PATCH!!!!!!!\
    --- on multi-crew, we only have the pilot as getPlayerName. \
    --- we now switch to the unit's name instead \
    playerName = theUnit:getName() \
    \
    -- trigger.action.outText(\"Player: \".. playerName, 10)\
\
    local existingPlayer = cfxPlayer.getPlayerInfoByName(playerName) -- try and access DB\
    if existingPlayer then\
        -- this player exists in the db. return the record\
        return true, existingPlayer;\
\
    else\
        -- this is a new player.\
        -- set up a new playerinfo record for this name\
        local newPlayerInfo = {}\
        newPlayerInfo.name = playerName\
        newPlayerInfo.unit = theUnit\
        newPlayerInfo.unitName = theUnit:getName()\
        newPlayerInfo.group = theUnit:getGroup()\
        newPlayerInfo.groupName = newPlayerInfo.group:getName()\
        newPlayerInfo.coalition = theUnit:getCoalition() -- seems to work when first param is class self\
        -- note that this record did not exist, and return record\
        return false, newPlayerInfo\
    end\
    \
end;\
\
function cfxPlayer.getSinglePlayerAirframe()\
    -- ALWAYS return a string! This is for debugging purposes\
    local thePlayers = {}\
    local count = 0\
    local theAirframe = \"(none)\"\
    for pname, pinfo in pairs(cfxPlayer.playerDB) do \
        count = count + 1\
        theAirframe = pinfo.unit:getTypeName()\
    end\
    if count < 2 then return theAirframe end -- also returns if count == 0\
    return \"<Multiplayer Not Yet Supported>\"\
end\
\
function cfxPlayer.getAnyPlayerAirframe()\
    -- use this for debugging, in single-player missions, or where it \
    -- is unimportant which player, just a player\
    -- assumes that all players use the same airframe or are in the \
    -- same group / unit \
    for pname, pinfo in pairs(cfxPlayer.playerDB) do \
        if (pinfo.unit:isExist()) then \
            -- player may just have crashed or left\
            local theAirframe = pinfo.unit:getTypeName()\
            return theAirframe -- we simply stop after first successfuly access\
        end\
    end\
    return \"error: no player\"\
end\
\
function cfxPlayer.getFirstGroupPlayerName(theGroup)\
 -- get the name of player of the first \
 -- player-controlled unit I come across in \
 -- this group \
    local allGroupUnits = theGroup:getUnits()\
    for ukey, uvalue in pairs(allGroupUnits) do \
        -- iterate units in group\
        if (uvalue:isExist())  then -- and cfxPlayer.isPlayerUnit(uvalue)) \
            -- player may just have crashed or left\
            -- but all units in the same group have the same type when they are aircraft\
            if cfxPlayer.isPlayerUnit(uvalue) then \
                return uvalue:getPlayerName(), uvalue \
            end\
        end\
    end\
    return nil \
end\
\
function cfxPlayer.getAnyGroupPlayerAirframe(theGroup)\
    -- get the first player-driven unit in the group\
    -- and pass back the airframe that is being used \
    local allGroupUnits = theGroup:getUnits()\
    for ukey, uvalue in pairs(allGroupUnits) do \
        \
        if (uvalue:isExist())  then -- and cfxPlayer.isPlayerUnit(uvalue)) \
            -- player may just have crashed or left\
            -- but all units in the same group have the same type when they are aircraft\
            local theAirframe = uvalue:getTypeName()\
            return theAirframe -- we simply stop after first successfuly access\
        end\
    end\
    return \"error: no live player in group \"\
end\
\
\
\
function cfxPlayer.getAnyPlayerPosition()\
    -- use this for debugging, in single-player missions, or where it \
    -- is unimportant which player, just a player\
    -- will cause issues when you derive location info or group info \
    -- from that player\
    for pname, pinfo in pairs(cfxPlayer.playerDB) do\
        if (pinfo.unit:isExist()) then \
            local thePoint = pinfo.unit:getPoint()\
            return thePoint -- we simply stop after first successfuly access\
        end\
    end\
    return nil\
end\
\
function cfxPlayer.getAnyGroupPlayerPosition(theGroup)\
    -- enter with dcs group to search for player units within\
    -- step one: get all units that belong to that group\
    local allGroupUnits = theGroup:getUnits()\
    -- we now iterate all returned units and look for \
    -- a unit that is a player unit.\
    for ukey, uvalue in pairs(allGroupUnits) do \
        -- we currently assume single-unit groups for players\
        if (uvalue:isExist()) then -- and cfxPlayer.isPlayerUnit(uvalue))\
            -- player may just have crashed or left\
            local thePoint = uvalue:getPoint()\
            return thePoint -- we simply stop after first successfuly access\
        end\
    \
    end\
    return nil\
end\
\
function cfxPlayer.getAnyGroupPlayerInfo(theGroup)\
    for pname, pinfo in pairs(cfxPlayer.playerDB) do \
        if (pinfo.unit:isExist() and pinfo.group == theGroup) then \
            return pinfo -- we simply stop after first successfuly access\
        end\
    end\
    return \"error: no player\"\
end\
\
\
function cfxPlayer.getAllPlayerGroups()\
    -- merely accessot. better would be returning a copy \
    return cfxPlayerGroups    \
end\
\
function cfxPlayer.getGroupDataForGroupNamed(name)\
    if not name then return nil end \
    return cfxPlayerGroups[name]\
end\
\
function cfxPlayer.getPlayersInGroup(theGroup)\
    if not theGroup then return {} end\
    if not theGroup:isExist() then return {} end \
    local gName = theGroup:getName()\
    local thePlayers = {}\
    \
    for pname, pinfo in pairs(cfxPlayer.playerDB) do         \
        local pgName = \"\"\
        if pinfo.group:isExist() then pgName = pinfo.group:getName() end \
        if (gName == pgName) then \
            table.insert(thePlayers, pinfo)\
        end\
    end\
    return thePlayers\
end\
\
-- update() is called regularly to check up on the players\
-- when a mismatch to last player state is found, callbacks \
-- can be invoked\
\
function cfxPlayer.update()\
    \
    -- first, re-schedule my next invocation\
    cfxPlayer.updateSchedule = timer.scheduleFunction(cfxPlayer.update, {}, timer.getTime() + 1/cfxPlayer.ups)\
    \
    -- now scan the coalitions for all players\
    local currCount = 0 -- number of players found this pass\
    local currDB = {} -- db of player units this pass\
    local currPlayerUnitsByNames = {}    \
    -- iterate over all colaitions \
    for i=1, #cfxPlayer.coalitionSides do \
        local theSide = cfxPlayer.coalitionSides[i] \
        -- get all player units for this side\
        local thePlayers = coalition.getPlayers(theSide) -- returns UNITs!!!\
\
        for p=1, #thePlayers do \
            -- we now iterate the Units and compare what we find\
            local thePlayerUnit = thePlayers[p]\
            local isExistingPlayerUnit, theInfo = cfxPlayer.getPlayerInfo(thePlayerUnit)\
            \
            if (not isExistingPlayerUnit) then \
                -- add Unit (not player!) to db\
                cfxPlayer.playerDB [theInfo.name] = theInfo\
                cfxPlayer.invokeMonitorsForEvent(\"new\", \"Player Unit \" .. theInfo.name .. \" entered mission\", theInfo, {})\
\
            else\
                -- player's unit existed last time around\
                -- see if something changed:\
    \
-- currently, we track units, not players. side changes for units can't happen AT ALL \
                \
                if theInfo.coalition ~= thePlayerUnit:getCoalition() then    \
                    local theData = {}\
                    theData.old = theInfo.coalition\
                    theData.new = thePlayerUnit:getCoalition()\
\
                    -- we invoke a callback\
                    cfxPlayer.invokeMonitorsForEvent(\"side\", \"Player \" .. theInfo.name .. \" switched sides to \" .. thePlayerUnit:getCoalition(), theInfo, theData)\
\
                end;\
\
-- we now check if the player has changed groups\
-- sinced we track units, this CANT HAPPEN AT ALL \
\
                if theInfo.group ~= thePlayerUnit:getGroup() then \
                    local theData = {}\
                    theData.old = theInfo.group\
                    theData.new = thePlayerUnit:getGroup()\
                    cfxPlayer.invokeMonitorsForEvent(\"group\", \"Player changed group to \" .. thePlayerUnit:getGroup():getName(), theInfo, theData)\
                    trigger.action.outText(\"+++ debug: Player \" .. theInfo.name .. \" changed GROUP to: \" .. thePlayerUnit:getGroup():getName(), 30)\
                end\
\
                -- we should now check if the player has changed units\
-- since we track units, this cant happen at all\
                if theInfo.unit ~= thePlayerUnit then\
                    -- player changed unit \
                    local theData = {}\
                    theData.old = theInfo.unit\
                    -- the old unit's name is still available in theInfo.unitName \
                    theData.oldUnitName = theInfo.unitName \
                    theData.new = thePlayerUnit\
                    -- update Player Info\
                    cfxPlayer.invokeMonitorsForEvent(\"unit\", \"Player changed unit to \" .. thePlayerUnit:getName(), theInfo, theData)\
                    \
                end\
                -- update the playerEntry. always done\
                theInfo.unit = thePlayerUnit\
                theInfo.unitName = thePlayerUnit:getName()\
                theInfo.coalition = thePlayerUnit:getCoalition()\
                theInfo.group = thePlayerUnit:getGroup()        \
            end;\
            \
            -- add this entry to current pass db so we can detect\
            -- any discrepancies to last pass\
            currDB[theInfo.name] = theInfo \
            \
            -- now update current network player name db\
            local playerUnitName = thePlayerUnit:getName()\
            if not thePlayerUnit:isExist() then playerUnitName = \"<none>\" end \
            currPlayerUnitsByNames[thePlayerUnit:getPlayerName()] = playerUnitName\
        end -- for all player units of this side\
    end -- for all sides\
    \
    -- we can now check if a player unit has disappeared    \
    -- we do this by checking that all old entries from cfxPlayer.playerDB\
    -- have an existing counterpart in new currDB\
    for name, info in pairs(cfxPlayer.playerDB) do\
        local matchingEntry = currDB[name]\
        if matchingEntry then \
            -- allright nothing to do\
        else\
            -- whoa, this record is missing!\
            -- do we care?\
            if true then -- (cfxPlayer.detectPlayersLeaving) then\
                -- yes! trigger an event\
                cfxPlayer.invokeMonitorsForEvent(\"leave\", \"Player left mission\", info, {})\
                -- we don't need to destroy entry, as we simply replace the\
                -- playerDB with currDB at end of update\
            else \
                -- no, just copy old data over. They'll be back\
                currDB[name] = info\
            end\
        end \
    end;\
    \
    -- we now perform a group check and update all groups for players \
    local currPlayerGroups = {}\
    for pName, pInfo in pairs(currDB) do \
        -- retrieve player unit and make sure it still exists\
        local theUnit = pInfo.unit\
        if theUnit:isExist() then \
            -- yeah, it exists allright. let's get to the group\
            local theGroup = theUnit:getGroup()\
            local gName = theGroup:getName()\
            -- see if this group is new\
            local thePGroup = cfxPlayerGroups[gName]\
            if not thePGroup then \
                -- allocate new group\
                thePGroup = {}\
                thePGroup.group = theGroup\
                thePGroup.name = gName \
                thePGroup.primeUnit = theUnit -- may be used as fallback\
                thePGroup.primeUnitName = theUnit:getName() -- also fallback only\
                thePGroup.id = theGroup:getID()\
                cfxPlayer.invokeMonitorsForEvent(\"newGroup\", \"New Player Group \" .. gName .. \" appeared\", nil, thePGroup)\
            end\
            currPlayerGroups[gName] = thePGroup -- update group table\
        end\
    end\
\
    -- now check if a player group has disappeared\
    for gkey, gval in pairs(cfxPlayerGroups) do \
        if not currPlayerGroups[gkey] then \
            cfxPlayer.invokeMonitorsForEvent(\"removeGroup\", \"A Player Group \" .. gkey .. \" vanished\", nil, gval) -- gval is OLD set, contains group \
        end\
    end\
    \
    -- version 3 addion: track network players\
    -- see if a new player has appeared \
    for aPlayerName, aPlayerUnitName in pairs(currPlayerUnitsByNames) do \
        -- see if this name was already in last \
        if cfxPlayer.netPlayers[aPlayerName] then \
            -- yes. but was it the same unit?\
            if cfxPlayer.netPlayers[aPlayerName] == currPlayerUnitsByNames[aPlayerName] then \
                -- all is well, no change \
            else \
                -- player has changed units \
                -- since they can't disappear, \
                -- this event can happen \
                local data = {}\
                data.oldUnitName = cfxPlayer.netPlayers[aPlayerName]\
                data.newUnitName = aPlayerUnitName\
                data.playerName = aPlayerName\
                if aPlayerUnitName == \"\" then aPlayerUnitName = \"<none>\" end \
                if aPlayerUnitName == \"<none>\" then \
                    -- unit no longer exists, player probably dead,\
                    -- parachuting or spectating. Maybe even left game\
                    -- resgisters as 'change' -- is 'left unit'\
                    cfxPlayer.invokeMonitorsForEvent(\"changePlayer\", \"A Player left unit \" .. data.oldUnitName, nil, data)\
                else \
                    -- changed to new unit\
                    cfxPlayer.invokeMonitorsForEvent(\"changePlayer\", \"A Player changed to unit \" .. aPlayerUnitName, nil, data)\
                end \
            end\
        else \
            -- this is a new player\
            local data = {}\
            data.playerName = aPlayerName\
            data.newUnitName = aPlayerUnitName\
            cfxPlayer.invokeMonitorsForEvent(\"newPlayer\", \"New Player appeared \" .. aPlayerName .. \" in unit \" .. aPlayerUnitName, nil, data)\
        end\
    end\
\
    -- version 3: detect if a player left \
    for oldPlayerName, oldUnitName in pairs(cfxPlayer.netPlayers) do \
        if not currPlayerUnitsByNames[oldPlayerName] then \
            --local data = {}\
            --data.playerName = oldPlayerName\
            --data.oldUnitName = oldUnitName\
            --cfxPlayer.invokeMonitorsForEvent(\"leavePlayer\", \"Player \" .. oldPlayerName .. \" disappeared from unit \" .. oldUnitName, nil, data)\
            --\
            -- we keep the player in the db by copying \
            -- it over and set the unit name to \"\"\
            -- will cause at least once 'change' event later \
            -- probably two in MP\
            currPlayerUnitsByNames[oldPlayerName] = \"<none>\"\
        end\
    end\
    \
    -- update playerGroups for this cycle\
    cfxPlayerGroups = currPlayerGroups\
    \
    -- update network player for this c<cle \
    cfxPlayer.netPlayers = currPlayerUnitsByNames\
    \
    -- finally, we simply replace the old db with the new one\
    cfxPlayer.playerDB = currDB;\
end\
\
function cfxPlayer.getAllNetPlayerNames ()\
    local themAll = {}\
    for aName, aUnitName in cfxPlayer.netPlayers do \
        table.insert(themAll, aName)\
    end\
    return themAll\
end\
\
function cfxPlayer.getPlayerUnitName(aPlayerName) \
    if not aPlayerName then return nil end \
    return cfxPlayer.netPlayers[aPlayerName]\
end\
\
function cfxPlayer.isPlayerSeated(aPlayerName)\
    local unitName = cfxPlayer.getPlayerUnitName(aPlayerName)\
    if not unitName then return false end \
    if unitName == \"\" or unitName == \"<none>\" then return false end \
    return true \
end\
\
-- add a monitor to be notified of player events\
-- may provide a whitelist of events as array of strings\
function cfxPlayer.addMonitor(callback, events)\
    local newMonitor = {}\
    newMonitor.callback = callback\
    newMonitor.events = events \
    cfxPlayer.monitors[callback] = newMonitor\
end;\
\
function cfxPlayer.removeMonitor(callback) \
    if (cfxMonitos[callback]) then \
        cfxMonitos[callback] = nil \
    end\
end\
\
function cfxPlayer.invokeMonitorsForEvent(evType, description, player, data)\
    for callback, monitor in pairs(cfxPlayer.monitors) do\
        -- should filter if evType is in monitor.events\
        if monitor.events and #monitor.events > 0 then \
            -- only invoke if this event is listed\
            if dcsCommon.arrayContainsString(monitor.events, evType) then \
                monitor.callback(evType, description, player, data)\
            end\
        else \
            monitor.callback(evType, description, player, data)\
        end\
    end\
end\
\
function cfxPlayer.getAllExistingPlayerUnitsRaw()\
    local apu = {}\
    for i=1, #cfxPlayer.coalitionSides do \
        local theSide = cfxPlayer.coalitionSides[i] \
        -- get all players for this side\
        local thePlayers = coalition.getPlayers(theSide) \
        for p=1, #thePlayers do \
            local aUnit = thePlayers[p]\
            if aUnit and aUnit:isExist() then \
                table.insert(apu, aUnit)\
            end\
        end\
    end\
    return apu \
end\
\
-- evType that can actually happen are 'new', 'leave' for units,\
-- 'newGroup' and 'removeGroup' for groups     \
function cfxPlayer.defaultMonitor(evType, description, info, data)\
    if cfxPlayer.verbose then\
        trigger.action.outText(\"+++Plr - evt '\".. evType ..\"': <\" .. description .. \">\", 30)\
        if (info) then \
            trigger.action.outText(\"+++Plr: for unit named: \" .. info.name, 30) \
        else \
            --trigger.action.outText(\"+++Plr: no player data\", 30)\
        end\
        --trigger.action.outText(\"+++Plr: desc: '\".. evType ..\"'<\" .. description .. \">\", 30)\
        -- we ignore the data block\
    end\
end\
\
function cfxPlayer.start()\
    trigger.action.outText(\"cf/x player v\".. cfxPlayer.version .. \": started\", 10)\
    cfxPlayer.running = true\
    cfxPlayer.update()    \
end\
\
function cfxPlayer.stop()\
    if cfxPlayer.verbose then \
        trigger.action.outText(\"cf/x player v\".. cfxPlayer.version .. \": stopped\", 10)\
    end\
    timer.removeFunction(cfxPlayer.updateSchedule) -- will require another start() to resume\
    cfxPlayer.running = false\
end\
\
function cfxPlayer.init()\
    trigger.action.outText(\"cf/x player v\".. cfxPlayer.version .. \": loaded\", 10)\
    -- when verbose, we also add a monitor to display player event\
    if cfxPlayer.verbose then \
        cfxPlayer.addMonitor(cfxPlayer.defaultMonitor, {})\
        trigger.action.outText(\"cf/x player isd verbose\", 10)\
    end\
    \
    cfxPlayer.start()\
end\
\
-- get everything rolling, but will only start if autostart is true\
cfxPlayer.init()\
\
--TODO: player status: ground, air, dead, none \
-- TODO: event when status changes ground/air/...",
                    ["predicate"] = "a_do_script",
                }, -- end of [3]
                [4] = 
                {
                    ["text"] = "-- cfxCommander - issue dcs commands to groups etc\
--\
-- supports scheduling\
-- *** EXTENDS ZONES: 'pathing' attribute \
--\
cfxCommander = {}\
cfxCommander.version = \"1.1.2\"\
--[[-- VERSION HISTORY\
 - 1.0.5 - createWPListForGroupToPointViaRoads: detect no road found \
 - 1.0.6 - build in more group checks in assign wp list \
         - added sanity checks for doScheduledTask\
         - assignWPListToGroup now can schedule tasks \
         - makeGroupGoThere supports scheduling\
         - makeGroupGoTherePreferringRoads supports scheduling \
         - scheduleTaskForGroup supports immediate execution\
         - makeGroupHalt\
 - 1.0.7 - warning if road shorter than direct\
         - forceOffRoad option\
         - noRoadsAtAll option \
 - 1.1.0 - load libs \
         - pathing zones. Currently only supports \
         - offroad to override road-usage\
         - pathing zones are overridden by noRoadsAtAll\
         - CommanderConfig zones \
 - 1.1.1 - default pathing for pathing zone is normal, not offroad \
 - 1.1.2 - makeGroupTransmit \
         - makeGroupStopTransmitting\
         - verbose check before path warning\
         - added delay defaulting for most scheduling functions \
--]]--\
\
cfxCommander.requiredLibs = {\
    \"dcsCommon\", -- common is of course needed for everything\
    \"cfxZones\", -- zones management for pathing zones \
}\
\
cfxCommander.verbose = false \
cfxCommander.forceOffRoad = true -- if true, vehicles path follow roads, but may drive offroad (they follow vertex points from path but not the road as they are still commanded 'offroad')\
cfxCommander.noRoadsAtAll = true  -- if true, always go direct, overrides forceOffRoad when true. Always a two-point path. Here, there, bang! \
cfxCommander.pathZones = {} -- zones that can override road settings\
\
--\
-- path zone\
--\
function cfxCommander.processPathingZone(aZone) -- process attribute and add to zone\
    local pathing = cfxZones.getStringFromZoneProperty(aZone, \"pathing\", \"normal\") -- must be \"offroad\" to force offroad\
    pathing = pathing:lower()\
    -- currently no validation of attribute \
    aZone.pathing = pathing\
end \
\
function cfxCommander.addPathingZone(aZone)\
    table.insert(cfxCommander.pathZones, aZone)\
end \
\
function cfxCommander.hasPathZoneFor(here, there)\
    for idx, aZone in pairs(cfxCommander.pathZones) do \
        if cfxZones.pointInZone(here, aZone) then return aZone end \
        if cfxZones.pointInZone(there, aZone) then return aZone end\
    end\
    return nil\
end\
\
--\
-- Config Zone Reading if present \
--\
function cfxCommander.readConfigZone()\
    -- note: must match exactly!!!!\
    local theZone = cfxZones.getZoneByName(\"CommanderConfig\") \
    if not theZone then \
        trigger.action.outText(\"+++cmdr: no config zone!\", 30) \
        return \
    end \
    \
    trigger.action.outText(\"+++cmdr: found config zone!\", 30) \
    \
    cfxCommander.verbose = cfxZones.getBoolFromZoneProperty(theZone, \"verbose\", false)\
    cfxCommander.forceOffRoad = cfxZones.getBoolFromZoneProperty(theZone, \"forceOffRoad\", false) -- if true, vehicles path follow roads, but may drive offroad\
    cfxCommander.noRoadsAtAll = cfxZones.getBoolFromZoneProperty(theZone, \"noRoadsAtAll\", false)\
\
end\
\
--\
-- Options are key, value pairs. Scheduler when you are creating groups\
-- \
\
function cfxCommander.doOption(data) \
    if cfxCommander.verbose then \
        trigger.action.outText(\"Commander: setting option \" .. data.key .. \" --> \" .. data.value, 30)\
    end\
\
    local theController = data.group:getController()\
    theController:setOption(data.key, data.value)\
end\
\
function cfxCommander.scheduleOptionForGroup(group, key, value, delay) \
    local data = {}\
    if not delay then delay = 0.1 end \
    data.group = group\
    data.key = key\
    data.value = value \
    timer.scheduleFunction(cfxCommander.doOption, data, timer.getTime() + delay)\
end\
\
--\
-- performCommand is a special version of issuing a command\
-- that can be easily schduled by pushing the commandData on \
-- the stack with scheduling it \
-- group or name must be filled to get the group,\
-- and the command table is what is going to be passed to the setCommand\
-- commands are given in an array, so you can stack commands \
function cfxCommander.performCommands(commandData)\
    -- see if we have a group\
    if not commandData.group then \
        commandData.group = Group.getByName(commandData.name) -- better be inited!\
    end\
    -- get the AI\
    local theController = commandData.group:getController()\
    for i=1, #commandData.commands do\
        if cfxCommander.verbose then \
            trigger.action.outText(\"Commander: performing \" .. commandData.commands[i].id, 30)\
        end\
        theController:setCommand(commandData.commands[i])\
    end\
    \
    return nil -- a timer called us, so we return no desire to be rescheduled\
end\
\
function cfxCommander.scheduleCommands(data, delay)\
    if not delay then delay = 1 end \
    timer.scheduleFunction(cfxCommander.performCommands, data, timer.getTime() + delay)\
end\
\
function cfxCommander.scheduleSingleCommand(group, command, delay) \
    if not delay then delay = 1 end \
    local data = createCommandDataTableFor(group)\
    cfxCommander.addCommand(data, command)\
    cfxCommander.scheduleCommands(data, delay)\
end\
\
\
function cfxCommander.createCommandDataTableFor(group, name)\
    local cD = {}\
    if not group then \
        cD.name = name\
    else\
        cD.group = group\
    end\
    cD.commands={}\
    return cD\
end\
\
function cfxCommander.addCommand(theCD, theCommand)\
    if not theCD then return end \
    if not theCommand then return end \
    \
    table.insert(theCD.commands, theCommand)\
end\
\
function cfxCommander.createSetFrequencyCommand(freq, modulator)\
    local theCmd = {}\
    if not freq then freq = 100 end \
    if not modulator then modulator = 0 end -- AM = 0, default\
    theCmd.id = 'SetFrequency'\
    theCmd.params = {}\
    theCmd.params.frequency = freq * 10000 -- 88 --> 880000. 124 --> 1.24 MHz\
    theCmd.params.modulation = modulator\
    return theCmd\
end\
\
-- oneShot is optional. if present and anything but false, will cause message to \
-- me sent only once, no loops\
function cfxCommander.createTransmissionCommand(filename, oneShot)\
    local looping = true\
    if not filename then filename = \"dummy\" end \
    if oneShot then looping = false end\
    local theCmd = {}\
    theCmd.id = 'TransmitMessage'\
    theCmd.params = {}\
    theCmd.params.loop = looping\
    theCmd.params.file = \"l10n/DEFAULT/\" .. filename -- need to prepend the resource string\
    return theCmd\
end\
\
function cfxCommander.createStopTransmissionCommand()\
    local theCmd = {}\
    theCmd.id = 'stopTransmission'\
    theCmd.params = {}\
    return theCmd\
end\
\
--\
-- tasks\
-- \
\
function cfxCommander.doScheduledTask(data) \
    if cfxCommander.verbose then \
        trigger.action.outText(\"Commander: setting task \" .. data.task.id .. \" for group \" .. data.group:getName(), 30)\
    end\
    local theGroup = data.group \
    if not theGroup then return end \
    if not theGroup.isExist then return end\
    \
    local theController = theGroup:getController()\
    theController:pushTask(data.task)\
end\
\
function cfxCommander.scheduleTaskForGroup(group, task, delay)\
    if not delay then delay = 0 end \
    local data = {}\
    data.group = group\
    data.task = task\
    if delay < 0.001 then \
        cfxCommander.doScheduledTask(data) -- immediate execution\
        return \
    end\
    timer.scheduleFunction(cfxCommander.doScheduledTask, data, timer.getTime() + delay)\
end\
\
function cfxCommander.createAttackGroupCommand(theGroupToAttack)\
    local task = {}\
    task.id = 'AttackGroup'\
    task.params = {}\
    task.params.groupID = theGroupToAttack:getID()\
    return task\
end\
\
function cfxCommander.createEngageGroupCommand(theGroupToAttack)\
    local task = {}\
    task.id = 'EngageGroup'\
    task.params = {}\
    task.params.groupID = theGroupToAttack:getID()\
    return task\
end\
\
--\
-- waypoints, routes etc \
--\
\
-- basic waypoint is for ground units. point can be xyz or xy \
function cfxCommander.createBasicWaypoint(point, speed, formation)\
    local wp = {}\
    wp.x = point.x\
    -- support xyz and xy format\
    if point.z then \
        wp.y = point.z\
    else\
        wp.y = point.y\
    end\
    \
    if not speed then speed = 6 end -- 6 m/s = 20 kph\
    wp.speed = speed \
    \
    if cfxCommander.forceOffRoad then \
        formation = \"Off Road\"\
    end\
    \
    if not formation then formation = \"Off Road\" end\
    -- legal formations:\
    -- Off road\
    -- On Road -- second letter upper case?\
    -- Cone \
    -- Rank\
    -- Diamond\
    -- Vee\
    -- EchelonR\
    -- EchelonL\
    wp.action = formation -- silly name, but that's how ME does it\
    wp.type = 'Turning Point'\
    return wp\
\
end\
\
function cfxCommander.buildTaskFromWPList(wpList)\
    -- build the task that will make a group follow the WP list\
    -- we do this by creating a \"Mission\" task around the WP List\
    -- WP list is consumed by this action\
    local missionTask = {}\
    missionTask.id = \"Mission\"\
    missionTask.params = {}\
    missionTask.params.route = {}\
    missionTask.params.route.points=wpList\
    return missionTask\
end\
\
function cfxCommander.assignWPListToGroup(group, wpList, delay)\
    if not delay then delay = 0 end \
    if not group then return end \
    if type(group) == 'string' then -- group name, nice mist trick \
        group = Group.getByName(group)\
    end\
    if not group then return end \
    if not group:isExist() then return end \
    \
    local theTask = cfxCommander.buildTaskFromWPList(wpList)\
    local ctrl = group:getController()\
\
--[[--\
    if delay < 0.001 then -- immediate action\
        if ctrl then\
            ctrl:setTask(theTask)\
        end\
    else \
        -- delay execution of this command by the specified amount \
        -- of seconds \
        cfxCommander.scheduleTaskForGroup(group, theTask, delay)\
    end\
--]]--\
    cfxCommander.scheduleTaskForGroup(group, theTask, delay)\
end\
\
function cfxCommander.createWPListForGroupToPoint(group, point, speed, formation)\
    if type(group) == 'string' then -- group name\
        group = Group.getByName(group)\
    end\
\
    local wpList = {}\
    -- here we are, and we want to go there. In DCS, this means that\
    -- we need to create a wp list consisting of here and there\
    local here = dcsCommon.getGroupLocation(group)\
    local wpHere = cfxCommander.createBasicWaypoint(here, speed, formation)\
    local wpThere = cfxCommander.createBasicWaypoint(point, speed, formation)\
    wpList[1] = wpHere\
    wpList[2] = wpThere\
    return wpList\
end\
\
-- make a ground units group head to a waypoint by replacing the entire mission\
-- with a two-waypoint lsit from (here) to there at speed and formation. formation\
-- default is 'off road'\
function cfxCommander.makeGroupGoThere(group, there, speed, formation, delay)\
    if not delay then delay = 0 end \
    if type(group) == 'string' then -- group name\
        group = Group.getByName(group)\
    end\
    local wp = cfxCommander.createWPListForGroupToPoint(group, there, speed, formation)\
    \
    cfxCommander.assignWPListToGroup(group, wp, delay)\
end\
\
function cfxCommander.calculatePathLength(roadPoints)\
    local totalLen = 0\
    if #roadPoints < 2 then return 0 end\
    for i=1, #roadPoints-1 do\
        totalLen = totalLen + dcsCommon.dist(roadPoints[i], roadPoints[i+1])\
    end\
    return totalLen\
end\
\
-- make ground units go from here (group location) to there, using roads if possible\
function cfxCommander.createWPListForGroupToPointViaRoads(group, point, speed)\
    if type(group) == 'string' then -- group name\
        group = Group.getByName(group)\
    end\
\
    local wpList = {}\
    -- here we are, and we want to go there. In DCS, this means that\
    -- we need to create a wp list consisting of here and there\
    -- when going via roads, we add to more wayoints:\
    -- go on-roads and leaveRoads. \
    -- only if we can get these two additional points, we do that, else we \
    -- fall back to direct route \
    \
    local here = dcsCommon.getGroupLocation(group)\
\
    -- now generate a list of all points from here to there that uses roads\
    local rawRoadPoints = land.findPathOnRoads('roads', here.x, here.z, point.x, point.z)\
    -- this is the entire path. calculate the length and make \
    -- sure that path on-road isn't more than twice as long \
    -- that can happen if a bridge is out or we need to go around a hill\
    if not rawRoadPoints or #rawRoadPoints<3 then \
        trigger.action.outText(\"+++ no roads leading there. Taking direct approach\", 30)\
        return cfxCommander.createWPListForGroupToPoint(group, point, speed)\
    end\
    \
    local pathLength = cfxCommander.calculatePathLength(rawRoadPoints)\
    local direct = dcsCommon.dist(here, point)\
    if pathLength < direct and cfxCommander.verbose then \
        trigger.action.outText(\"+++dcsC: WARNING road path (\" .. pathLength .. \") shorter than direct route(\" .. direct .. \"), will not path correctly\", 30)\
    end\
    \
    if pathLength > (2 * direct) then \
        -- road takes too long, take direct approach\
        --trigger.action.outText(\"+++ road path (\" .. pathLength .. \") > twice direct route(\" .. direct .. \"), commencing direct off-road\", 30)\
        return cfxCommander.createWPListForGroupToPoint(group, point, speed)\
    end\
    \
    --trigger.action.outText(\"+++ \".. group:getName() .. \": choosing road path l=\" .. pathLength .. \" over direct route d=\" .. direct, 30)\
    \
    -- if we are here, the road trip is valid \
    for idx, wp in pairs(rawRoadPoints) do \
        -- createBasic... supports w.xy format\
        local theNewWP = cfxCommander.createBasicWaypoint(wp, speed, \"On Road\") -- force off road for better compatibility?\
        table.insert(wpList, theNewWP)\
    end\
    \
    \
    \
    -- now make first and last entry OFF Road\
    local wpc = wpList[1]\
    wpc.action = \"Off Road\"\
    wpc = wpList[#wpList]\
    wpc.action = \"Off Road\"\
\
    return wpList\
end\
\
function cfxCommander.makeGroupGoTherePreferringRoads(group, there, speed, delay)\
    if type(group) == 'string' then -- group name\
        group = Group.getByName(group)\
    end\
    if not delay then delay = 0 end \
\
\
    if cfxCommander.noRoadsAtAll then \
        -- we don't even follow roads, completely forced off\
        cfxCommander.makeGroupGoThere(group, there, speed, \"Off Road\", delay)\
        return \
    end\
\
    -- see if we have an override situation \
    -- for one of the two points where a pathing Zone \
    -- overrides the roads setting \
    if #cfxCommander.pathZones > 0 then  \
        local here = dcsCommon.getGroupLocation(group)\
        local oRide = cfxCommander.hasPathZoneFor(here, there)\
        if oRide and oRide.pathing == \"offroad\" then \
            -- yup, override road preference\
            cfxCommander.makeGroupGoThere(group, there, speed, \"Off Road\", delay)\
            --trigger.action.outText(\"pathing: override offroad\")\
            return \
        end\
    end\
\
    -- viaRoads will only use roads if the road trip isn't more than twice \
    -- as long as the direct route \
    local wp = cfxCommander.createWPListForGroupToPointViaRoads(group, there, speed)\
    cfxCommander.assignWPListToGroup(group, wp, delay)\
end\
\
\
function cfxCommander.makeGroupHalt(group, delay)\
    if not group then return end \
    if not group:isExist() then return end \
    if not delay then delay = 0 end \
    local theTask = {id = 'Hold', params = {}}\
    cfxCommander.scheduleTaskForGroup(group, theTask, delay)\
end\
\
function cfxCommander.makeGroupTransmit(group, tenKHz, filename, oneShot, delay)\
    if not group then return end \
    if not tenKHz then tenKHz = 20 end -- default to 200KHz\
    if not delay then delay = 1.0 end \
    if not filename then return end \
    if not oneShot then oneShot = false end \
    \
    -- now build the transmission command\
    local theCommands = cfxCommander.createCommandDataTableFor(group)\
    local cmd = cfxCommander.createSetFrequencyCommand(tenKHz) -- freq in 10000 Hz\
    cfxCommander.addCommand(theCommands, cmd)\
    cmd = cfxCommander.createTransmissionCommand(filename, oneShot)\
    cfxCommander.addCommand(theCommands, cmd)\
    cfxCommander.scheduleCommands(theCommands, delay)\
end \
\
function cfxCommander.makeGroupStopTransmitting(group, delay)\
    if not delay then delay = 1 end \
    if not group then return end \
    local theCommands = cfxCommander.createCommandDataTableFor(group)\
    local cmd = cfxCommander.createStopTransmissionCommand()\
    cfxCommander.addCommand(theCommands, cmd)\
    cfxCommander.scheduleCommands(theCommands, delay)\
end\
\
\
function cfxCommander.start()\
    -- make sure we have loaded all relevant libraries \
    if not dcsCommon.libCheck(\"cfx Commander\", cfxCommander.requiredLibs) then \
        trigger.action.outText(\"cf/x Commander aborted: missing libraries\", 30)\
        return false \
    end\
    \
    -- identify and process all 'pathing' zones\
    local pathZones = cfxZones.getZonesWithAttributeNamed(\"pathing\")\
    \
    -- now create a spawner for all, add them to the spawner updater, and spawn for all zones that are not\
    -- paused \
    for k, aZone in pairs(pathZones) do \
        cfxCommander.processPathingZone(aZone) -- process attribute and add to zone\
        cfxCommander.addPathingZone(aZone) -- remember it so we can smoke it\
    end\
    \
    -- read config overides \
    cfxCommander.readConfigZone()\
    \
    return true\
end\
\
if cfxCommander.start() then \
    trigger.action.outText(\"cfxCommander v\" .. cfxCommander.version .. \" loaded\", 30)\
else \
    trigger.action.outText(\"+++cfxCommander load FAILED\", 30)\
    cfxCommander = nil\
end\
\
--[[-- known issues\
\
- troops remain motionless until all are repaired or produced after cature\
- long roads / roads not taken in persia \
- all troops red and blue become motionless when one zone is occupied\
- after capture, the troop capturing remains, all others can go on. one will always remain there \
- rethink the factor to add to road, and simply add 100m \
\
 TODO: break long distances into smaller paths, and gravitate towards pathing zones if they have a 'gravitate' or similar attribute \
--]]--\
",
                    ["predicate"] = "a_do_script",
                }, -- end of [4]
                [5] = 
                {
                    ["text"] = "cfxGroundTroops = {}\
cfxGroundTroops.version = \"1.7.3\"\
cfxGroundTroops.ups = 1\
cfxGroundTroops.requiredLibs = {\
    \"dcsCommon\", -- common is of course needed for everything\
                 -- pretty stupid to check for this since we \
                 -- need common to invoke the check, but anyway\
    \"cfxCommander\", -- generic data module for weight \
    -- cfxOwnedZones is optional \
}\
-- ground troops: a module to manage ground toops. makes groups of ground troops\
-- patrol and engage enemies and signal idle\
-- understands cfxOwnedZones orders 'attackOwnedZone' and will re-direct\
-- troops when a zone was captured by interacting with cfxOwnedZones to \
-- find the nearest non-owned zone and direct the group there \
\
-- USAGE\
-- Allocate a group in game and issue them marching orders towars a goal \
-- then createGroundTroops to allocate a structure used by this \
-- module and addTroopsToPool to have them then managed by this \
-- module \
\
cfxGroundTroops.deployedTroops = {}\
\
-- version history\
--   1.3.0 - added \"wait-\" prefix to have toops do nothing \
--         - added lazing \
--   1.3.1 - sound for lazing msg is \"UI_SCI-FI_Tone_Bright_Dry_20_stereo.wav\"\
--         - lazing --> lasing in text \
--   1.3.2 - set ups to 2 \
--   1.4.0 - queued updates except for lazers \
--   1.4.1 - makeTroopsEngageZone now issues hold before moving on 5 seconds later\
--         - getTroopReport\
--           - include size of group \
--   1.4.2 - uses unitIsInfantry from dcsCommon \
--   1.5.0 - new scheduled updates per troop to reduce processor load \
--         - tiebreak code \
--   1.5.1 - small bugfix in scheduled code \
--   1.5.2 - checkSchedule \
--         - speed warning in scheduler\
--         - go off road when speed warning too much \
--   1.5.3 - monitor troops \
--         - managed queue for ground troops \
--         - on second switch to offroad now removed from MQ\
--   1.5.4 - removed debugging messages\
--   1.5.5 - removed bug in troop report reading nil destination \
--   1.6.0 - check modules \
--   1.6.1 - troopsCallback management so you can be informed if a \
--           troop you have added to the pool is dead or has achieved a goal.\
--           callback will list reasons \"dead\" and \"arrived\"\
--           updateAttackers\
--   1.6.2 - also accept 'lase' as 'laze', translate directly \
--   1.7.0 - now can use groundTroopsConfig zone\
--   1.7.1 - addTroopsDeadCallback() renamed to addTroopsCallback() \
--         - invokeCallbacksFor also accepts and passes on data block\
--         - troops is always passed in data block as .troops \
--   1.7.2 - callback when group is neutralized on guard orders\
--         - callback when group is being engaged under guard orders \
--   1.7.3 - callbacks for lase:tracking and lase:stop \
\
\
\
\
-- an entry into the deployed troop has the following attributes\
--  - group - the group \
--  - orders: \"guard\" - will guard the spot and look for enemies in range\
--            \"patrol\" - will walk between way points back and forth \
--            \"laze\" - will stay in place and try to laze visible vehicles in range\
--              \"attackOwnedZone\" - interface to cfxOwnedZones module, seeks out\
--              enemy zones to attack and capture them\
--            \"wait-<some other orders>\" do nothing. the \"wait\" prefix will be removed some time and <some other order> then revealed. Used at least by heloTroops\
--            \"train\" - target dummies. ROE=HOLD, no ground loop \
--            \"attack\" - transition to destination, once there, stop and \
--            switch to guard. requires destination zone be sez to a valid cfxZone\
--  - coalition - the coalition from the group\
--  - enemy - if set, the group this group it is engaging. this means the group is fighting and not idle\
--  - name - name of group, dan be freely changed\
--  - signature - \"cfx\" to tell apart from dcs groups \
--  - range = range to look for enemies. default is 300m. In \"laze\" orders, range to laze\
--  - lazeTarget - target currently lazing\
--  - lazeCode - laser code. default is 1688\
\
-- \
-- usage:\
-- take a dcs group of ground troops and create a cfx ground troop record with \
--   createGroundTroops()\
-- then add this to the manager with \
--   addGroundTroopsToPool()\
-- \
-- you can control what the group is to do by changing the cfx troop attribute orders \
-- you can install a callback that will notify you if a troop reached a goal or\
-- was killed with addTroopsCallback() which will also give a reason\
-- callback pattern is myCallback(reason, theGroup, orders, data) with troop being the \
-- group, and orders the original orders, and reason a string containing why the \
-- callback was invoked. Currently defined reasons are\
--   - \"dead\" - entire group was killed \
--   - \"arrived\" - at least a part of group arrived at destination (only with some orders)\
--\
\
--\
-- UPDATE MODELS\
-- standard is update all every time: fastest, but may cause \
-- performance issues\
-- queued will work one every pass (except for lazed), distributing the load much better \
-- schedueld installs a callback for each group separately and thus distributes the load over time much better \
\
cfxGroundTroops.queuedUpdates = false -- set to true to process one group per turn. To work this way, scheduledUpdates must be false \
cfxGroundTroops.scheduledUpdates = true -- set to false to allow queing of standard updates. overrides queuedUpdates \
cfxGroundTroops.monitorNumbers = false -- set to true to debug managed group size \
\
cfxGroundTroops.standardScheduleInterval = 30 -- 30 seconds between calls\
cfxGroundTroops.guardUpdateInterval = 30 -- every 30 seconds we check up on guards\
cfxGroundTroops.trackingUpdateInterval = 0.5 -- 0.5 seconds for lazer tracking etc \
\
cfxGroundTroops.maxManagedTroops = 67 -- -1 is infinite, any positive number turn on cap on managed troops and palces excess troops in queue \
cfxGroundTroops.troopQueue = {} -- FIFO stack \
-- return the best tracking interval for this type of orders \
\
--\
-- READ CONFIG ZONE TO OVERRIDE SETTING\
--\
function cfxGroundTroops.readConfigZone()\
    -- note: must match exactly!!!!\
    local theZone = cfxZones.getZoneByName(\"groundTroopsConfig\") \
    if not theZone then \
        trigger.action.outText(\"***gndT: NO config zone!\", 30) \
        return \
    end \
    \
    trigger.action.outText(\"+++gndT: found config zone!\", 30) \
    \
    -- ok, for each property, load it if it exists\
    if cfxZones.hasProperty(theZone, \"queuedUpdates\")  then \
        cfxGroundTroops.queuedUpdates = cfxZones.getBoolFromZoneProperty(theZone, \"queuedUpdates\", false)\
    end\
    \
    if cfxZones.hasProperty(theZone, \"scheduledUpdates\")  then \
        cfxGroundTroops.scheduledUpdates = cfxZones.getBoolFromZoneProperty(theZone, \"scheduledUpdates\", false)\
    end\
    \
    if cfxZones.hasProperty(theZone, \"maxManagedTroops\")  then \
        cfxGroundTroops.maxManagedTroops = cfxZones.getNumberFromZoneProperty(theZone, \"maxManagedTroops\", 65)\
    end\
    \
    if cfxZones.hasProperty(theZone, \"monitorNumbers\")  then \
        cfxGroundTroops.monitorNumbers = cfxZones.getBoolFromZoneProperty(theZone, \"monitorNumbers\", false)\
    end\
    \
    if cfxZones.hasProperty(theZone, \"standardScheduleInterval\")  then \
        cfxGroundTroops.standardScheduleInterval = cfxZones.getNumberFromZoneProperty(theZone, \"standardScheduleInterval\", 30)\
    end\
    \
    if cfxZones.hasProperty(theZone, \"guardUpdateInterval\")  then \
        cfxGroundTroops.guardUpdateInterval = cfxZones.getNumberFromZoneProperty(theZone, \"guardUpdateInterval\", 30)\
    end\
    \
    if cfxZones.hasProperty(theZone, \"trackingUpdateInterval\")  then \
        cfxGroundTroops.trackingUpdateInterval = cfxZones.getNumberFromZoneProperty(theZone, \"trackingUpdateInterval\", 0.5)\
    end\
    \
    \
end\
\
\
-- \
-- Callback handling\
--\
\
cfxGroundTroops.troopsCallback = {}\
\
function cfxGroundTroops.addTroopsCallback(theCallback)\
    table.insert(cfxGroundTroops.troopsCallback, theCallback)\
end\
\
function cfxGroundTroops.invokeCallbacksFor(reason, troops, data)\
    if not data then data = {} end\
    data.troops = troops \
    for idx, theCB in pairs (cfxGroundTroops.troopsCallback) do \
        theCB(reason, troops.group, troops.orders, data)\
    end\
end\
\
function cfxGroundTroops.getScheduleInterval(orders)\
    if orders == \"laze\" then \
        return cfxGroundTroops.trackingUpdateInterval\
    end\
    return cfxGroundTroops.standardScheduleInterval\
end\
\
-- create controller commands to attack a group \"enemies\"\
-- enemies are an attribute of the troop structure\
function cfxGroundTroops.makeTroopsEngageEnemies(troop)\
    local group = troop.group\
    local enemies = troop.enemy\
    local from = dcsCommon.getGroupLocation(group)\
    if not from then return end -- the commandos died\
    local there = dcsCommon.getGroupLocation(enemies)\
    if not there then return end\
    \
    -- we lerp to 2/3 of enemy location\
    there = dcsCommon.vLerp(from, there, 0.66) \
    \
    local speed = 10 -- m/s = 10 km/h\
    cfxCommander.makeGroupGoThere(group, there, speed)\
    local attask = cfxCommander.createAttackGroupCommand(enemies)\
    cfxCommander.scheduleTaskForGroup(group, attask, 0.5)\
end\
\
-- make the troops engage a cfxZone passed in the destination \
-- attribute \
function cfxGroundTroops.makeTroopsEngageZone(troop)\
    local group = troop.group\
    local enemyZone = troop.destination -- must be cfxZone \
    local from = dcsCommon.getGroupLocation(group)\
    if not from then return end -- the group died\
    local there = enemyZone.point -- access zone position\
    if not there then return end\
    \
    -- we lerp to 102% of enemy location to force overshoot and engagement\
    --there = dcsCommon.vLerp(from, there, 1.02) \
    \
    local speed = 14 -- m/s; 10 m/s = 36 km/h\
    -- we prefer going over roads since we don't know \
    -- what is there \
    \
    -- make troops stop in 1 second, then start in 5 seconds to give AI respite \
    cfxCommander.makeGroupHalt(group, 1) -- 1 second delay\
    cfxCommander.makeGroupGoTherePreferringRoads(group, there, speed, 5)\
    -- no attack command since we don't know what is there\
    -- but mayhaps we should issue weapons free?\
    -- we'll soon test that by sticking in a troop on the way \
    \
--    local attask = cfxCommander.createAttackGroupCommand(enemies)\
--    cfxCommander.scheduleTaskForGroup(group, attask, 0.5)\
end\
\
function cfxGroundTroops.switchToOffroad(troops)\
    -- we may need to test if we already did this, \
    -- but not for now \
    \
    -- this is called when troops are stuck \
    -- on their route for longer than allowed\
    -- we now force a direct approach \
    local group = troops.group\
    local enemies = troops.destination\
    local from = dcsCommon.getGroupLocation(group)\
    if not from then return end -- the commandos died\
    local there = enemies.point\
    if not there then return end\
        \
    local speed = 14 -- m/s; 10 m/s = 36 km/h\
    \
    cfxCommander.makeGroupHalt(group, 0) -- no delay, halt now\
    cfxCommander.makeGroupGoThere(group, there, speed, \"Off Road\", 5)\
    \
    troops.lastOrderDate = timer.getTime()\
    troops.speedWarning = 0\
end\
\
--\
-- update loop for troops that have 'attackOwnedZones' as \
-- their orders\
-- if they have no destination zone, or the zone they are \
-- are heading for is already owned by their side, then look for \
-- the closest enemy zone, and cut attack orders to move there \
function cfxGroundTroops.getClosestEnemyZone(troop)\
    local p = dcsCommon.getGroupLocation(troop.group)\
    local tempZone = cfxZones.createSimpleZone(\"tz\", p, 100)\
    tempZone.owner = troop.side\
    local newTarget = cfxOwnedZones.getNearestEnemyOwnedZone(tempZone, true) -- 'true' will also target neutral zones \
    return newTarget\
end\
\
function cfxGroundTroops.updateZoneAttackers(troop)\
    if not troop then return end \
    troop.insideDestination = false -- mark as not inside \
    \
    local newTargetZone = cfxGroundTroops.getClosestEnemyZone(troop)\
    if not newTargetZone then\
        -- all target zones are friendly, go to guard mode\
--        trigger.action.outTextForCoalition(troop.side, troop.name .. \" holding position\", 30)\
        troop.orders = \"guard\"\
        return \
    end\
    \
    if newTargetZone ~= troop.destination then \
--        trigger.action.outTextForCoalition(troop.side, troop.name .. \" enroute to \" .. newTargetZone.name, 30)\
        troop.destination = newTargetZone \
        cfxGroundTroops.makeTroopsEngageZone(troop)\
        troop.lastOrderDate = timer.getTime()\
        troop.speedWarning = 0\
        return\
    end\
    \
    -- if we get here, we are under way to troop.destination\
    -- check if we are inside the zone, and if so, set variable to true \
    local p = dcsCommon.getGroupLocation(troop.group)\
    troop.insideDestination = cfxZones.isPointInsideZone(p, troop.destination)\
    \
--    if we get here, we need no change \
\
    \
end\
\
-- attackers simply travel to their destination, and then switch to \
-- guard orders once they arrive \
function cfxGroundTroops.updateAttackers(troop) \
    if not troop then return end \
    if not troop.destination then return end \
    \
    if cfxZones.isGroupPartiallyInZone(troop.group, troop.destination) then\
        -- we have arrived\
        -- we could now also initiate a general callback with reason\
        cfxGroundTroops.invokeCallbacksFor(\"arrived\", troop)\
        troop.orders = \"guard\"\
        return \
    end\
    \
    \
--    if we get here, we need no change \
end\
\
-- update loop for a group that has \"guard\" orders.\
-- basically it stands around and looks for enemies \
-- until it finds a group, and then engages the enemy\
-- when engaged, it is not looking for other enemies\
-- 'engaged' means that the troop.enemy attribute is set\
 \
function cfxGroundTroops.updateGuards(troop)\
    local theEnemy = troop.enemy\
    if theEnemy then \
        -- see if enemy is dead \
        if not dcsCommon.isGroupAlive(theEnemy) then \
            troop.enemy = nil\
            -- yup, zed's dead. next time around, we won't be checking this again\
            trigger.action.outText(troop.name .. \" has neutralized enemy forces\", 30)\
            --DONE: invoke callback for defeating troops\
            local data = {}\
            data.enemy = theEnemy\
            cfxGroundTroops.invokeCallbacksFor(\"neutralized\", troop, data)\
            return\
        end\
        -- yes, we are still engaged\
        return \
    end\
    \
    -- we are currently unengaged. look for an enemy\
    if not troop.range then troop.range = 300 end\
    troop.coalition = troop.group:getCoalition()\
    local enemyCoal = dcsCommon.getEnemyCoalitionFor(troop.coalition)\
    local cat = Group.Category.GROUND\
    local p = dcsCommon.getGroupLocation(troop.group)\
    local enemies, enemyDist = dcsCommon.getClosestLivingGroupToPoint(p, enemyCoal, cat) \
    local maxRange = troop.range -- meters \
    -- if we have enemies then schedule a path to go there\
    if enemies and (enemyDist < maxRange) then \
        troop.enemy = enemies\
        --timer.scheduleFunction(cfxGroundTroops.makeGroupEngageEnemies, troop, timer.getTime() + 1.0)\
        cfxGroundTroops.makeTroopsEngageEnemies(troop)\
        trigger.action.outText(troop.name .. \" is engaging enemy forces at range \" .. math.floor(enemyDist) .. \"meters\", 30)\
        --DONE: invoke callback for engaging troops, pass data \
        local data = {}\
        data.enemy = enemies\
        cfxGroundTroops.invokeCallbacksFor(\"engaging\", troop, data)\
    elseif enemies then \
        --trigger.action.outText(troop.name .. \" enemiy out of range: \" .. math.floor(enemyDist) .. \"meters\", 30)\
    else \
        --trigger.action.outText(troop.name .. \" no enemies\", 30)\
    end\
end\
\
--\
-- update loop for units that laze targets.\
-- they can only laze if they are alive, but update \
-- will take care of that, so when we are here, there \
-- is at least one of them alive\
-- \
\
function cfxGroundTroops.findLazeTarget(troop)\
    local here = troop.group:getUnit(1):getPoint()\
    troop.coalition = troop.group:getCoalition()\
    local enemyCoal = dcsCommon.getEnemyCoalitionFor(troop.coalition)\
    --local enemySide = dcsCommon.getEnemyCoalitionFor(troop.side)\
    local cat = Group.Category.GROUND\
    local enemyGroups = dcsCommon.getLivingGroupsAndDistInRangeToPoint(here, troop.range, enemyCoal, cat) \
    -- we now have a list of possible targets in range\
    if #enemyGroups < 1 then     \
        -- no targets in range\
        return nil \
    end\
\
    here = {x = here.x, y = here.y + 2.0, z = here.z} -- raise by 2.0m\
    \
    -- iterate through the list until we find the first target \
    -- that fits the bill and return it\
--    trigger.action.outText(\"+++ looking at \" .. #enemyGroups .. \" laze groups\", 30)\
    for i=1, #enemyGroups do    \
        -- get all units for this group \
        local aGroup = enemyGroups[i].group -- remember, they are in a {dist, group} tuple\
        local theUnits = aGroup:getUnits()\
        -- iterate all units \
        for udx, aUnit in pairs(theUnits) do \
            if (aUnit:isExist() and aUnit:getLife() > 1) then \
                -- unit lives \
                -- now, we need to filter infantry. we do this by \
                -- pre-fetching the typeString\
                --troop.lazeTargetType = aUnit:getTypeName()\
                -- and checking if the name contains some infantry-\
                -- typical strings. Idea taken from JTAC script \
                local isInfantry =  dcsCommon.unitIsInfantry(theUnit)\
    \
                \
                if not isInfantry then \
                    -- this is a vehicle, is it in line of sight?\
                    -- raise the point 2m above ground for both points\
                    -- as done in jtac script\
                    local there = aUnit:getPoint()  \
                    there = {x = there.x, y = there.y + 2.0, z = there.z}\
                   \
                    if land.isVisible(here, there) then \
                        -- we found a visible vehicle in \
                        -- the nearest group to us in range \
                        -- that is visible!\
                        return aUnit\
                    else \
                        --trigger.action.outText(\"+++ \".. aUnit:getName() ..\"cant be seen\", 30)\
                    end -- if visible\
                else \
                    -- trigger.action.outText(\"+++ \".. aUnit:getName() ..\" (\".. troop.lazeTargetType .. \") is infantry\", 30)\
                end -- if not infantry \
            end -- if alive \
        end -- for all units\
    end -- for all enemy groups\
    --trigger.action.outText(\"+++ find nearest laze target did not find anything to laze\", 30)\
    return nil -- no unit found \
end\
\
function cfxGroundTroops.lazerOff(troop)\
    if troop.lazerPointer then \
        troop.lazerPointer:destroy()\
    end\
    troop.lazerPointer = nil \
    troop.lazingUnit = nil \
end\
\
function cfxGroundTroops.trackLazer(troop)\
    -- the only thing that must be set when entering here is\
    -- lazeTarget. We set up the rest\
    if not troop.lazingUnit then \
        troop.lazingUnit = troop.group:getUnit(1) -- get first unit\
        if troop.lazingUnit:getLife() < 1 then \
            trigger.action.outText(\"+++ LazingUnit is dead, getUnit works differently from what docs say, need to filter for lively units\", 30)\
        end\
    end\
    \
    if not troop.lazerPointer then\
        local there = troop.lazeTarget:getPoint()\
        troop.lazerPointer = Spot.createLaser(troop.lazingUnit,{x = 0, y = 2, z = 0}, there, 1688)\
        troop.lazeTargetType = troop.lazeTarget:getTypeName()\
        trigger.action.outTextForCoalition(troop.side, troop.name .. \" tally target - lasing \" .. troop.lazeTargetType .. \"!\", 30)\
         trigger.action.outSoundForCoalition(troop.side, \"UI_SCI-FI_Tone_Bright_Dry_20_stereo.wav\")\
        troop.lastLazerSpot = there -- remember last spot\
        local data = {}\
        data.enemy = troop.lazeTarget\
        data.tracker = troop.lazingUnit\
        cfxGroundTroops.invokeCallbacksFor(\"lase:tracking\", troop, data)\
        return\
    end\
    \
    -- if true then return end \
    \
    -- if we get here, we update the lazerPointer\
    local there = troop.lazeTarget:getPoint()\
    -- we may only want to update the laser spot when dist > trigger\
    troop.lazerPointer:setPoint(there)\
    -- we may want to report dist\
    troop.lastLazerSpot = there\
end\
\
function cfxGroundTroops.updateLaze(troop)\
    -- check if we have a laze target. \
    -- check if lazing unit was killed, and therefore lost target\
    if troop.lazingUnit then \
        -- check that unit still alive\
        if troop.lazingUnit:isExist() and \
        troop.lazingUnit:getLife() >= 1 then\
        else \
            cfxGroundTroops.lazerOff(troop)\
            troop.lazeTarget = nil\
            trigger.action.outTextForCoalition(troop.side, troop.name .. \" reports lasing \" .. troop.lazeTargetType .. \" interrupted. Re-acquiring.\", 30)\
            trigger.action.outSoundForCoalition(troop.side, \"UI_SCI-FI_Tone_Bright_Dry_20_stereo.wav\")\
            troop.lazingUnit = nil \
            cfxGroundTroops.invokeCallbacksFor(\"lase:stop\", troop)\
            return -- we'll re-acquire through a new unit next round\
        end\
    end\
    \
    -- if we get here, a lazing unit \
    --local here = troop.lazingUnit:getPoint()\
    \
    if troop.lazeTarget then \
        -- check if that target is alive and in range\
        if troop.lazeTarget:isExist() and troop.lazeTarget:getLife() >= 1 then\
            -- note: when we laze a target, we know that we have a lazing unit\
            local here = troop.lazingUnit:getPoint()\
            -- check if it has moved out of range \
            local there = troop.lazeTarget:getPoint()\
            if dcsCommon.dist(here, there) > troop.range then \
                -- troop out of range\
                trigger.action.outTextForCoalition(troop.side, troop.name .. \" lost sight of lazed target \" .. troop.lazeTargetType, 30)\
                trigger.action.outSoundForCoalition(troop.side, \"UI_SCI-FI_Tone_Bright_Dry_20_stereo.wav\")\
                troop.lazeTarget = nil\
                cfxGroundTroops.lazerOff(troop)\
                troop.lazingUnit = nil\
                cfxGroundTroops.invokeCallbacksFor(\"lase:stop\", troop)\
                return \
            end\
            \
            -- if we get here, we need to update the target point \
            cfxGroundTroops.trackLazer(troop)\
            return\
        else\
            -- target died\
            trigger.action.outTextForCoalition(troop.side, troop.name .. \" confirms kill for \" .. troop.lazeTargetType, 30)\
            trigger.action.outSoundForCoalition(troop.side, \"UI_SCI-FI_Tone_Bright_Dry_20_stereo.wav\")\
            troop.lazeTarget = nil\
            cfxGroundTroops.lazerOff(troop)\
            troop.lazingUnit = nil\
            cfxGroundTroops.invokeCallbacksFor(\"lase:stop\", troop)\
            return\
        end        \
    end\
    \
    -- if we get here, we must look for a laze target \
    troop.lazeTarget = cfxGroundTroops.findLazeTarget(troop)\
    if troop.lazeTarget then \
        cfxGroundTroops.trackLazer(troop) -- will also set up lazing unit \
    end\
end\
\
\
function cfxGroundTroops.updateWait(troop)\
    -- currently nothing to do\
    \
end\
\
function cfxGroundTroops.updateTroops(troop)\
    -- if orders start with \"wait-\" then the troops \
    -- simply do nothing\
    if dcsCommon.stringStartsWith(troop.orders, \"wait-\") then\
        -- the troops are waiting to be picked update\
        -- when they are dropped again, thre prefix to \
        -- their order is removed, and the 'real' orders \
        -- are revealed. For now, do nothing\
        cfxGroundTroops.updateWait(troop)\
    \
    elseif troop.orders == \"guard\" then \
        cfxGroundTroops.updateGuards(troop)\
    \
    elseif troop.orders == \"attackOwnedZone\" then \
        cfxGroundTroops.updateZoneAttackers(troop)\
\
    elseif troop.orders == \"laze\" then \
        cfxGroundTroops.updateLaze(troop)\
    \
    elseif troop.orders == \"attackZone\" then \
        cfxGroundTroops.updateAttackers(troop)\
        \
    else \
        trigger.action.outText(\"+++ updated troops \" .. troop.name .. \" have unknown orders \" .. troop.orders, 30)\
    end\
    \
end\
\
--\
-- we have to systems to process during update: \
-- once all, and one per turn, with the exception \
-- of lazers, who get updated every turn\
-- \
\
--\
-- all at once \
--\
function cfxGroundTroops.update()\
    cfxGroundTroops.updateSchedule = timer.scheduleFunction(cfxGroundTroops.update, {}, timer.getTime() + 1/cfxGroundTroops.ups)\
    -- iterate all my troops and build next \
    -- versions pool\
    local liveTroops = {}\
    for idx, troop in pairs(cfxGroundTroops.deployedTroops) do \
        local group = troop.group \
        if not dcsCommon.isGroupAlive(group) then \
            -- group dead. remove from pool\
            -- this happens by not copying it into the poos\
        --    trigger.action.outText(\"+++ removing ground troops \" .. troop.name, 30)\
            cfxGroundTroops.invokeCallbacksFor(\"dead\", troop) -- notify anyone who is interested that we are no longer proccing these \
        else \
            -- work with this groop according to its orders\
            cfxGroundTroops.updateTroops(troop)\
--            trigger.action.outText(\"+++ updated troops \" .. troop.name, 30)\
            -- since group is alive remember it for next loop\
            --table.insert(liveTroops, troop)\
            liveTroops[idx] = troop -- do NOT use insert as we have indexed table\
        end\
    end\
    -- liveTroops holds all troops that are still alive and will\
    -- be revisited next loop\
    cfxGroundTroops.deployedTroops = liveTroops\
end\
\
--\
-- UpdateQueued looks for the first unordered (.receivedOrders == false) group\
-- and processes them. if orders are 'laze', it will always be ordered \
--\
\
\
function cfxGroundTroops.updateQueued()\
    cfxGroundTroops.updateSchedule = timer.scheduleFunction(cfxGroundTroops.updateQueued, {}, timer.getTime() + 1/cfxGroundTroops.ups)\
    -- iterate all my troops and build next \
    -- versions pool\
    local liveTroops = {}\
    local hasOrdered = false -- so far, no orders have been given \
    for idx, troop in pairs(cfxGroundTroops.deployedTroops) do \
        local group = troop.group \
        if not dcsCommon.isGroupAlive(group) then \
            -- group dead. remove from pool\
            -- this happens by not copying it to liveTroops \
            -- trigger.action.outText(\"+++ removing ground troops \" .. troop.name, 30)\
            cfxGroundTroops.invokeCallbacksFor(\"dead\", troop) -- notify anyone who is interested that we are no longer proccing these \
        else \
            -- check if this is a lazer \
            if troop.orders == \"laze\" then \
                -- lazers are updated each turn \
                cfxGroundTroops.updateLaze(troop)\
            else \
                if not hasOrdered and not (troop.receivedOrders) then \
                -- work with this groop according to its orders\
                cfxGroundTroops.updateTroops(troop)\
                troop.receivedOrders = true -- this one has received orders \
                hasOrdered = true \
                end \
            end\
            liveTroops[idx] = troop -- do NOT use insert as we have indexed table\
        end\
    end\
    -- liveTroops holds all troops that are still alive and will\
    -- be revisited next loop\
    cfxGroundTroops.deployedTroops = liveTroops\
    \
    -- if no orders have been passed, clear all troop's .receivedOrders flag \
    -- and the loop starts anew next loop \
    if not hasOrdered then \
        for idx, troop in pairs(cfxGroundTroops.deployedTroops) do\
            troop.receivedOrders = nil  \
        end\
    end\
end\
\
--\
-- in updateCheckOnly we simply check the ground queue \
-- if there are troops added that need scheduling (i.e. have \
-- been passed in by addTroops and schedule them \
--\
function cfxGroundTroops.updateCheckOnly()\
    -- re-schedule myself in 1 second \
    timer.scheduleFunction(cfxGroundTroops.updateCheckOnly, {}, timer.getTime() + 1)\
    \
    -- iterate through all troops, and \
    -- see if there are any that have not been scheduled \
    -- to schedule them for updates in 1 second\
    -- that will be the first time that they are scheduled,\
    -- all others will be self-scheduled \
    for idx, troop in pairs(cfxGroundTroops.deployedTroops) do \
        if not troop.hasBeenScheduled then \
            local params = {troop}\
            troop.hasBeenScheduled = true \
            troop.updateID = timer.scheduleFunction(cfxGroundTroops.updateSingleScheduled, params, timer.getTime() + 1)\
            --trigger.action.outText(\"+++groundT: scheduling troops <\".. troop.group:getName() ..\"> with orders <\" .. troop.orders .. \">\", 30)\
        end\
    end\
    -- note that alive checks are now done during the scheduled\
    -- update, not every time for all\
\
end\
\
function cfxGroundTroops.updateSingleScheduled(params)\
    local troops = params[1]\
    troops.updateID = nil -- erase update id \
    if not troops then \
        trigger.action.outText(\"+++groundT WARNING: nil troop in updateSingle\", 30)\
        return -- no further action required, no longer updates\
    end\
    \
    local group = troops.group \
    -- see if we have been taken out of the pool or updated\
    -- if so, exit \
    \
    if not group:isExist() then \
        -- simply never again look at it. \
        return \
    end\
    \
    if cfxGroundTroops.deployedTroops[troops.group:getName()] ~= troops then \
        -- trigger.action.outText(\"+++groundT NOTE: troops <\".. troops.group:getName() ..\"> was removed from pool. Cancel Update\", 30)\
        return -- no further reschedule\
    end\
    \
    -- see if scheduling is turned off\
    if not troops.reschedule then \
        trigger.action.outText(\"+++groundT NOTE: no longer updating <\".. troops.group:getName() ..\"> per reschedule param\", 30)\
        return \
    end\
    \
    -- now, check if still alive \
    if not dcsCommon.isGroupAlive(group) then \
        -- group dead, no longer updates \
        --trigger.action.outText(\"+++groundT NOTE: <\".. troops.group:getName() ..\"> dead, removing\", 30)\
        cfxGroundTroops.invokeCallbacksFor(\"dead\", troops) -- notify anyone who is interested that we are no longer proccing these \
        cfxGroundTroops.removeTroopsFromPool(troops)\
        return -- nothing else to do\
    end\
    \
    -- now, execute the update itself, standard update \
    --trigger.action.outText(\"+++groundT: singleU troop <\".. troops.group:getName() ..\"> with orders <\" .. troops.orders .. \">\", 30)\
    cfxGroundTroops.updateTroops(troops)\
    \
    -- check max speed of group. if < 0.1 then note and increase \
    -- speedWarning. if not, reset speed warning \
    if troops.orders == \"attackOwnedZone\" and dcsCommon.getGroupMaxSpeed(troops.group) < 0.1 then \
        if not troops.speedWarning then troops.speedWarning = 0 end\
        troops.speedWarning = troops.speedWarning + 1\
    else\
        troops.speedWarning = 0 -- reset\
    end\
    \
    if troops.speedWarning > 5 then -- make me 5\
        lastOrder = timer.getTime() - troops.lastOrderDate \
        --trigger.action.outText(\"+++groundT WARNING: <\".. troops.group:getName() ..\"> (S:\".. troops.side .. \") to \" .. troops.destination.name .. \": stopped for \" .. troops.speedWarning .. \" iters, orderage=\" .. lastOrder, 30)\
        -- this may be a matter of too many waypoints. \
        -- maybe issue orders to go to their destination directly?\
        -- now force an order to go directly.\
        if troops.speedWarning > 5 then \
            if troops.isOffroad then \
                -- we already switched to off-road. take me \
                -- out of the managed queue, I'm not going \
                -- anywhere\
                -- trigger.action.outText(\"+++groundT <\".. troops.group:getName() ..\"> is going nowhere. Removed from managed troops\", 30)\
                cfxGroundTroops.removeTroopsFromPool(troops)\
            else \
                cfxGroundTroops.switchToOffroad(troops)\
                -- trigger.action.outText(\"+++groundT <\".. troops.group:getName() ..\"> SWITCHED TO OFFROAD\", 30)\
                troops.isOffroad = true -- so we know that we already did that\
            end\
        end \
    end\
    \
    -- now reschedule updte for my best time \
    local updateTime = cfxGroundTroops.getScheduleInterval(troops.orders)\
    troops.updateID = timer.scheduleFunction(cfxGroundTroops.updateSingleScheduled, params, timer.getTime() + updateTime)\
end\
\
\
--\
-- PILEUP and TIE BRAKERS\
--\
-- there may come a situation where troops gather in \
-- one zone because the zone isn't won - some other troops \
-- are there and noone moves. \
-- a tie-break is required\
--\
\
-- checkpile up: every so often, we test if we have run into a \
-- pileup-situation. this happens if there are more than n \
-- units with group-attacker order in the same zone, and that \
-- zone is their destination \
-- this can be easily detected by the insideDestination flag \
-- checkPileUp should be run every minute or so \
 \
function cfxGroundTroops.checkPileUp()\
    -- schedule my next call \
    --trigger.action.outText(\"+++groundT: pileup check\", 30)\
    timer.scheduleFunction(cfxGroundTroops.checkPileUp, {}, timer.getTime() + 60)\
    local thePiles = {}\
    if not cfxOwnedZones then \
        -- trigger.action.outText(\"+++groundT: pileUp - owned zones not yet ready\", 30)\
        return \
    end\
    \
    -- create a list of all piles \
    for idx, oz in pairs(cfxOwnedZones.zones) do \
        local newPile = {}\
        newPile[1] = 0 -- no red inZone here \
        newPile[2] = 0 -- no blue inZone here \
        newPile.zone = oz -- the zone we are looking at \
        thePiles[oz] = newPile \
    end\
    \
    -- now iterate through all currently alive groups and \
    -- attribute them to their piles \
    for idx, troop in pairs(cfxGroundTroops.deployedTroops) do \
        -- get each group and count them if they are inside\
        -- their destination \
        if troop.insideDestination then\
            local side = troop.group:getCoalition()\
            local thePile = thePiles[troop.destination]\
            local theSide = troop.group:getCoalition()\
            thePile[theSide] = thePile[theSide] + 1 -- we count groups, not units  \
        end\
    end\
    \
    -- a pileup happens, if there are more than 3 groups in destination zone\
    -- with NO other troops present (usually the case)\
    -- or when there are 5 groups more than the number for the other side \
    -- so now scan all piles\
    for idx, thePile in pairs(thePiles) do \
        -- check red pileup \
        if thePile[1] > 3 and thePile[2] == 0 then \
            -- simple pileup. 3 groups, no others except defenders and \
            -- perhaps transients \
            cfxGroundTroops.breakTie(thePile, 1)\
        elseif thePile[1] >= thePile[2] + 5 then \
            -- numerical pileup \
            cfxGroundTroops.breakTie(thePile, 1)\
        end\
        \
        -- check blue loside \
        if thePile[2] >= 3 and thePile[1] == 0 then \
            -- simple pileup. 3 groups, no others except defenders and \
            -- perhaps transients \
            cfxGroundTroops.breakTie(thePile, 2)\
        elseif thePile[2] >= thePile[1] + 5 then \
            -- numerical pileup \
            cfxGroundTroops.breakTie(thePile, 2)\
        end\
    end\
end\
\
function cfxGroundTroops.breakTie(thePile, winner)\
    trigger.action.outText(\"+++ groundT: TIEBREAK - winner is \" .. winner .. \" in zone \" .. thePile.zone.name .. \": \" .. thePile[1] .. \":\" .. thePile[2] , 30)\
    -- now add some code to do the actual tie breaking: remove all units that \
    -- are inside the zone and who belong to the other side \
    local loser = 1 -- red default \
    local theZone = thePile.zone \
    if winner == 1 then loser = 2 end \
    -- now get all ground groups for the losing side\
    local losingGround = coalition.getGroups(loser, Group.Category.GROUND)\
    for idx, theGroup in pairs(losingGround) do \
        -- if alive, check if inside the zone \
        if theGroup:isExist() and dcsCommon.isGroupAlive(theGroup) then \
            -- make sure it's not a transient\
            if not isDeployedGroundTroop(theGroup) then \
                local p = dcsCommon.getGroupLocation(theGroup) \
                if cfxZones.isPointInsideZone(p, theZone) then \
                    trigger.action.outText(\"+++ groundT: TIEBREAK - destroying group \" .. theGroup:getName() , 30)\
                    -- we delete this group now\
                    theGroup:destroy()\
                end\
            end\
        end\
    end\
end\
\
--\
-- sanity checks for rescheduling\
--\
function cfxGroundTroops.checkSchedules()\
    timer.scheduleFunction(cfxGroundTroops.checkSchedules, {}, timer.getTime() + 10)\
    for idx, troop in pairs(cfxGroundTroops.deployedTroops) do\
        -- check if troop is not scheduled \
        -- if this happens to a group more than a certain times,\
        -- it has somehow dropped out of the reschedule \
        -- plan and needs to be scheduled \
        if troop.updateID == nil then \
            troop.unscheduleCount = troop.unscheduleCount + 1\
            if (troop.unscheduleCount > 1) then \
                trigger.action.outText(\"+++ groundT: unscheduled group  \" .. troop.group:getName() .. \" cnt=\" .. troop.unscheduleCount , 30)\
            end \
        end\
    end\
end\
\
--\
-- REPORTING \
--\
-- \
-- get a report of troops as string \
-- \
function cfxGroundTroops.getTroopReport(theSide, ignoreInfantry)\
    if not ignoreInfantry then ignoreInfantry = false end \
    local report = \"GROUND FORCES REPORT\"\
    for idx, troop in pairs(cfxGroundTroops.deployedTroops) do \
        if troop.side == theSide then \
            local unitNum = troop.group:getSize()\
            report = report .. \"\\n\" .. troop.name .. \" (\".. unitNum ..\"): <\" .. troop.orders .. \">\" \
            if troop.orders == \"attackOwnedZone\" then \
                if troop.destination then     \
                    report = report .. \" move towards \" .. troop.destination.name \
                else \
                    report = report .. \" (selecting destination)\"\
                end\
            end\
        end\
    end\
    report = report .. \"\\n---END REPORT\\n\"\
    return report \
end\
\
\
--\
-- CREATE / ADD / REMOVE \
--\
\
--\
-- createGroundTroop\
-- use this to create a cfxGroundTroops from a dcs group\
--\
function cfxGroundTroops.createGroundTroops(inGroup, range, orders) \
    local newTroops = {}\
    if not orders then \
        orders = \"guard\" \
        --trigger.action.outText(\"+++ adding ground troops <\".. inGroup:getName() ..\">with default orders\", 30)\
    else \
        --trigger.action.outText(\"+++ adding ground troops <\".. inGroup:getName() ..\">with orders \" .. orders, 30)\
    end\
    if orders:lower() == \"lase\" then \
        orders = \"laze\" -- we use WRONG spelling here, cause we're cool\
    end\
    newTroops.insideDestination = false\
    newTroops.unscheduleCount = 0 -- will count up as we aren't scheduled\
    newTroops.speedWarning = 0\
    newTroops.isOffroad = false -- if true, we switched to direct orders, not roads, after standstill\
    newTroops.group = inGroup\
    newTroops.orders = orders\
    newTroops.coalition = inGroup:getCoalition()\
    newTroops.side = newTroops.coalition -- because we'e been using both.\
    newTroops.name = inGroup:getName()\
    newTroops.signature = \"cfx\" -- to verify this is groundTroop group, not dcs groups\
    if not range then range = 300 end\
    newTroops.range = range\
    return newTroops\
end\
\
function cfxGroundTroops.addGroundTroopsToPool(troops) -- troops MUST be a table that I understand, with \
    if not troops then return end\
    if troops.signature ~= \"cfx\" then \
        trigger.action.outText(\"+++ adding ground troops with unsupported troop signature\", 30)\
        return \
    end\
    \
    troops.reschedule = true -- in case we use scheduled update \
    -- we now add to internal array. this is worked on by all \
    -- update meths, on scheduled upadtes, it is only used to \
    -- pick up, and do the initial schedule, after that they \
    -- all re-schedule themselves \
    troops.hasBeenScheduled = false -- so far, no updates \
    -- hasBeenScheduled is used by updateCheckOnly when scheduled \
    -- updates are used. \
    \
    -- now add to actively managed table or queue it if enabled\
    if cfxGroundTroops.maxManagedTroops > 0 and dcsCommon.getSizeOfTable(cfxGroundTroops.deployedTroops) >= cfxGroundTroops.maxManagedTroops then \
        -- we need to queue \
        table.insert(cfxGroundTroops.troopQueue, troops)\
        -- trigger.action.outText(\"enqued \" .. troops.group:getName() .. \" at pos \".. #cfxGroundTroops.troopQueue ..\", manage cap surpassed.\", 30)\
    else\
        -- add to deployed set\
        cfxGroundTroops.deployedTroops[troops.group:getName()] = troops\
    end\
end\
\
function cfxGroundTroops.removeTroopsFromPool(troops)\
    if not troops then return end \
    if troops.signature ~= \"cfx\" then return end\
    \
    if cfxGroundTroops.deployedTroops[troops.group:getName()] then \
        local troop = cfxGroundTroops.deployedTroops[troops.group:getName()]\
        troops.reschedule = false -- so a reschedule wont update any more\
        cfxGroundTroops.deployedTroops[troops.group:getName()] = nil\
        return \
    end\
    \
    -- if we get here, we need to check if perhaps the troops \
    -- are in the queue\
    for i=1, #cfxGroundTroops.troopQueue do \
        if cfxGroundTroops.troopQueue[i] == troops then \
            table.remove(cfxGroundTroops.troopQueue, i)\
            return\
        end\
    end\
end\
\
function isDeployedGroundTroop(aGroup) \
    if not aGroup then return false end \
    -- see if its already managed\
    if cfxGroundTroops.deployedTroops[aGroup:getName()] ~= nil then \
        return true \
    end \
    \
    -- see if it's in the queue \
    for i=1, #cfxGroundTroops.troopQueue do \
        if cfxGroundTroops.troopQueue[i] == troops then \
            return true\
        end\
    end\
    -- if we get here, it's neither managed nor queued\
    return false \
--    return cfxGroundTroops.deployedTroops[aGroup:getName()] ~= nil \
end\
\
function cfxGroundTroops.getGroundTroopsForGroup(aGroup) \
    if not (cfxGroundTroops.deployedTroops[aGroup:getName()]) then\
        -- see if it's queued \
        for i=1, #cfxGroundTroops.troopQueue do \
            local troops = cfxGroundTroops.troopQueue[i]\
            if troops.group == aGroup then \
                return troops\
            end\
        end\
        \
        trigger.action.outText(\"+++ WARNING: cannot find group \" .. aGroup:getName() .. \" for troop retrieval. Known troops are:\", 30)\
        for k,v in pairs(cfxGroundTroops.deployedTroops) do \
            trigger.action.outText(\"+++ \".. k .. \": has v: \" .. v.name, 30)\
        end\
        return nil\
    end\
    \
    return cfxGroundTroops.deployedTroops[aGroup:getName()]\
end\
\
function cfxGroundTroops.monitorQueues()\
    timer.scheduleFunction(cfxGroundTroops.monitorQueues, {}, timer.getTime() + 5)\
    \
    -- calculate the numbers \
    local num = dcsCommon.getSizeOfTable(cfxGroundTroops.deployedTroops)\
    \
    local msg = \"+++ gT - Groups Managed: <\" .. num .. \">\"\
    -- display the numbers\
    if cfxGroundTroops.maxManagedTroops > 0 then \
        msg = msg .. \" capped at \" .. cfxGroundTroops.maxManagedTroops .. \", q size is <\" .. #cfxGroundTroops.troopQueue .. \">\"\
    end\
    trigger.action.outText(msg, 30)\
end\
\
\
-- manageQueue: if depth of deployedTroops is below max and we have \
-- items in queue, pop off first one and put in managed table \
-- checked once every 2 seconds \
function cfxGroundTroops.manageQueues() \
    timer.scheduleFunction(cfxGroundTroops.manageQueues, {}, timer.getTime() + 2)\
    if cfxGroundTroops.maxManagedTroops < 1 then return end\
    \
    -- if we get here, we have a limit on managed \
    -- items \
    if #cfxGroundTroops.troopQueue < 1 then return end \
    \
    -- if we here, there are items waiting in the queue\
    while dcsCommon.getSizeOfTable(cfxGroundTroops.deployedTroops) < cfxGroundTroops.maxManagedTroops and #cfxGroundTroops.troopQueue > 0 do \
        -- trnasfer items from the front to the managed queue \
        local theTroops = cfxGroundTroops.troopQueue[1]\
        table.remove(cfxGroundTroops.troopQueue, 1)\
        cfxGroundTroops.deployedTroops[theTroops.group:getName()] = theTroops\
        -- trigger.action.outText(\"+++gT: dequed and activaed \" .. theTroops.group:getName(), 30)\
    end\
end\
\
\
function cfxGroundTroops.start()\
    if not dcsCommon.libCheck(\"cfx Ground Troops\",\
                              cfxGroundTroops.requiredLibs)\
    then \
        trigger.action.outText(\"cf/x Ground Troops aborted: missing libraries\", 30)\
        return false \
    end\
    \
    -- read optional config zone \
    cfxGroundTroops.readConfigZone()\
    \
    if cfxGroundTroops.scheduledUpdates then \
        cfxGroundTroops.queuedUpdates = false \
        cfxGroundTroops.updateCheckOnly()\
        cfxGroundTroops.checkSchedules() -- check regularly if all troops have been updated by checking their ID\
    elseif cfxGroundTroops.queuedUpdates then \
        cfxGroundTroops.updateQueued()\
    else     \
        cfxGroundTroops.update()\
    end \
    -- now install a regular pileup check \
    timer.scheduleFunction(cfxGroundTroops.checkPileUp, {}, timer.getTime() + 60) \
    \
    if cfxGroundTroops.monitorNumbers then \
        timer.scheduleFunction(cfxGroundTroops.monitorQueues, {}, timer.getTime() + 5) \
    end\
    \
    if cfxGroundTroops.maxManagedTroops > 0 then\
        timer.scheduleFunction(cfxGroundTroops.manageQueues, {}, timer.getTime() + 1) \
    end \
    \
    trigger.action.outText(\"cf/x Ground Troops v\" .. cfxGroundTroops.version .. \" started\", 30)\
    \
    if not cfxOwnedZones then \
        --trigger.action.outText(\"+++groundT: pileUp - owned zones not yet ready\", 30)\
    end\
    return true \
end\
\
if not cfxGroundTroops.start() then \
    cfxGroundTroops = nil \
    trigger.action.outText(\"cfxGroundTroops aborted load\", 30)\
end\
\
--[[--\
 TO DO \
 \
 - implement 'patrol' orders!!! \
   \
   when ordering a new route, issue a command to stop in 1 second\
 and another with new marching orders in 5 seconds \
 look at setTask() and resetTask() for controller\
 - change group logic to set itself up to 'requestOrders' with group as parameter, so they can decide themselves how quickly they want to be re-tasked\
 \
 - DONE enqueue and dequeue methods with capped ground troops size \
 - named locs have strategic values attached (default = 1), and distance is divided by strat value to get at priority when rerouting \
 \
 - difficulty increase: make enemy troops better by raining their spawned level \
 \
 - check out simple slot block SSB (pre-moose) to see if we can implement slot blocking for downed pilots \
 \
 - new 'wanda' (wander) module to make airports more lively: zone, have individuals/single vehicle wander around. two waypoints (start and stop), that are zones, and whenever they reach one or are at speed 0, they get a new one. may have pause before they go to next. \
 variant on above: selection of zones that are somehow connected, and destinations are made between these for patrolling zone. can force order, loop, and ping-pong. \
--]]--",
                    ["predicate"] = "a_do_script",
                }, -- end of [5]
                [6] = 
                {
                    ["text"] = "cfxSpawnZones = {}\
cfxSpawnZones.version = \"1.4.6\"\
cfxSpawnZones.requiredLibs = {\
    \"dcsCommon\", -- common is of course needed for everything\
                 -- pretty stupid to check for this since we \
                 -- need common to invoke the check, but anyway\
    \"cfxZones\", -- Zones, of course \
    \"cfxCommander\", -- to make troops do stuff\
    \"cfxGroundTroops\", -- generic data module for weight \
}\
cfxSpawnZones.ups = 1\
\
--\
-- Zones that conform with this requirements spawn toops automatically\
--   *** DOES NOT EXTEND ZONES *** LINKED OWNER via masterOwner ***\
-- \
\
-- version history\
--   1.3.0 \
--         - maxSpawn\
--         - orders\
--         - range\
--   1.3.1 - spawnWithSpawner correct translation of country to coalition \
--         - createSpawner - corrected reading from properties\
--   1.3.2 - createSpawner - correct reading 'owner' from properties, now \
--           directly reads coalition\
--   1.4.0 - checks modules \
--         - orders 'train' or 'training' - will make the \
--           ground troops be issued HOLD WEAPS and \
--           not added to any queue. 'Training' troops \
--           are target dummies.\
--         - optional heading attribute \
--         - typeMult: repeate type this many time (can produce army in one call)\
--   1.4.1 - 'requestable' attribute. will automatically set zone to \
--         - paused, so troops can be produced on call\
--         - getRequestableSpawnersInRange \
--   1.4.2 - target attribute. used for\
--         - orders: attackZone \
--         - spawner internally copies name from cfxZone used for spawning (convenience only)\
--   1.4.3 - can subscribe to callbacks. currently called when spawnForSpawner is invoked, reason is \"spawned\"\
--         - masterOwner to link ownership to other zone \
--   1.4.4 - autoRemove flag to instantly start CD and respawn \
--   1.4.5 - verify that maxSpawns ~= 0 on initial spawn on start-up \
--   1.4.6 - getSpawnerForZoneNamed(aName)\
--         - nil-trapping orders before testing for 'training'\
--   1.4.7 - defaulting orders to 'guard'\
--         - also accept 'dummy' and 'dummies' as substitute for training \
--\
-- new version requires cfxGroundTroops, where they are \
--\
-- How do we recognize a spawn zone?\
-- contains a \"spawner\" attribute\
-- a spawner must also have the following attributes\
--  - spawner - anything, must be present to signal. put in 'ground' to be able to expand to other types  \
--  - types    - type strings, comma separated \
-- see here: https://github.com/mrSkortch/DCS-miscScripts/tree/master/ObjectDB\
--  - typeMult - repeat types n times to create really LOT of troops. optional, defaults to 1\
--  - country  - defaults to 2 (usa) -- see here https://wiki.hoggitworld.com/view/DCS_enum_country\
--    some important: 0 = Russia, 2 = US, 82 = UN neutral\
--    country is converted to coalition and then assigned to\
--    Joint Task Force <side> upon spawn\
--  - masterOwner - optional name of master cfxZone used to determine whom the surrounding \
--    territory belongs to. Spwaner will only spawn if the owner coalition is the \
--    the same as the coalition my own county belongs to.\
--    if not given, spawner spawns even if inside a zone owned by opposing force \
--  - baseName - for naming spawned groups - MUST BE UNIQUE!!!!\
--  \
-- the following attributes are optional \
--  - cooldown, defaults to 60 (seconds) after troops are removed from zone,\
--    then the next group spawns. This means troops will only spawn after \
--    troops are removed and cooldown timed out \
--  - autoRemove - instantly removes spwaned troops, will spawn again \
--    again after colldown \
--  - formation - default is  circle_out; other formations are \
--        - line - left lo right (west-east) facing north\
--      - line_V - vertical line, facing north\
--      - chevron - west-east, point growing to north \
--      - scattered, random\
--      - circle, circle_forward (all fact north)\
--        - circle-in (all face in)\
--      - circle-out (all face out)\
--      - grid, square, rect arrayed in optimal grid\
--      - 2deep, 2cols two columns, deep \
--      - 2wide 2 columns wide (2 deep) \
--  - heading in DEGREES (deafult 0 = north ) direction entire group is facing \
--  - destination - zone name to go to, no destination = stay where you are \
--  - paused - defaults to false. If present true, spawning will not happen\
--    you can then manually invoke cfxSpawnZones.spawnWithSpawner(spawner) to \
--    spawn the troops as they are described in the spawner \
--  - orders - tell them what to do. \"train\" makes them dummies, \"guard\" \
--    \"laze\", \"wait-laze\" etc \
--    other orders are as defined by cfxGroundTroops, at least \
--      guard - hold and defend (default)\
--      laze - laze targets \
--      wait-xxx for helo troops, stand by until dropped from helo \
--      attackOwnedZone - seek nearest owned zone and attack\
--      attackZone - move towards the named cfxZone. will generate error if zone not found \
--      name of zone to attack is in 'target' attribute\
--  - target - names a target cfxZone, used for orders. Troops will immediately\
--    start moving towards that zone if defined and such a zone exists\
--  - maxSpawns - limit number of spawn cycles. omit or -1 is unlimited\
--  - requestable - used with heloTroops to determine if spawning can be ordered by \
--    comms when in range\
-- respawn currently happens after theSpawn is deleted and cooldown seconds have passed \
cfxSpawnZones.allSpawners = {}\
cfxSpawnZones.callbacks = {} -- signature: cb(reason, group, spawner)\
 \
\
--\
-- C A L L B A C K S \
-- \
function cfxSpawnZones.addCallback(theCallback)\
    table.insert(cfxSpawnZones.callbacks, theCallback)\
end\
\
function cfxSpawnZones.invokeCallbacksFor(reason, theGroup, theSpawner)\
    for idx, theCB in pairs (cfxSpawnZones.callbacks) do \
        theCB(reason, theGroup, theSpawner)\
    end\
end\
\
\
--\
-- creating a spawner\
--\
function cfxSpawnZones.createSpawner(inZone)\
    local theSpawner = {}\
    theSpawner.zone = inZone\
    theSpawner.name = inZone.name \
    theSpawner.types = cfxZones.getZoneProperty(inZone, \"types\")\
    --theSpawner.owner = cfxZones.getCoalitionFromZoneProperty(inZone, \"owner\", 0)\
    -- synthesize types * typeMult\
    local n = cfxZones.getNumberFromZoneProperty(inZone, \"typeMult\", 1)\
    local repeater = \"\"\
    if n < 1 then n = 1 end \
    while n > 1 do \
        repeater = repeater .. \",\" .. theSpawner.types\
        n = n - 1\
    end\
    theSpawner.types = theSpawner.types .. repeater \
    \
    theSpawner.country = cfxZones.getNumberFromZoneProperty(inZone, \"country\", 0) -- coalition2county(theSpawner.owner)\
    theSpawner.masterZoneName = cfxZones.getStringFromZoneProperty(inZone, \"masterOwner\", \"\")\
    if theSpawner.masterZoneName == \"\" then theSpawner.masterZoneName = nil end \
    \
    theSpawner.rawOwner = coalition.getCountryCoalition(theSpawner.country)\
    theSpawner.baseName = cfxZones.getZoneProperty(inZone, \"baseName\")\
    theSpawner.cooldown = cfxZones.getNumberFromZoneProperty(inZone, \"cooldown\", 60)\
    theSpawner.autoRemove = cfxZones.getBoolFromZoneProperty(inZone, \"autoRemove\", false)\
    theSpawner.lastSpawnTimeStamp = -10000 -- just init so it will always work\
    theSpawner.heading = cfxZones.getNumberFromZoneProperty(inZone, \"heading\", 0)\
    --trigger.action.outText(\"+++spwn: zone \" .. inZone.name .. \" owner \" .. theSpawner.owner \" --> ctry \" .. theSpawner.country, 30)\
    \
    theSpawner.cdTimer = 0 -- used for cooldown. if timer.getTime < this value, don't spawn\
    theSpawner.cdStarted = false -- used to initiate cooldown when theSpawn disappears\
    theSpawner.count = 1 -- used to create names, and count how many groups created\
    theSpawner.theSpawn = nil -- link to last spawned group\
    theSpawner.formation = \"circle_out\"\
    theSpawner.formation = cfxZones.getStringFromZoneProperty(inZone, \"formation\", \"circle_out\")\
    theSpawner.paused = cfxZones.getBoolFromZoneProperty(inZone, \"paused\", false)\
    theSpawner.orders = cfxZones.getStringFromZoneProperty(inZone, \"orders\", \"guard\")\
    --theSpawner.orders = cfxZones.getZoneProperty(inZone, \"orders\")\
    -- used to assign special orders, default is 'guard', use \"laze\" to make them laze targets. can be 'wait-' which may auto-convert to 'guard' after pick-up by helo, to be handled outside.\
    -- use \"train\" to tell them to HOLD WEAPONS, don't move and don't participate in loop, so we have in effect target dummies\
    -- can also use order 'dummy' or 'dummies' to switch to train\
    if theSpawner.orders:lower() == \"dummy\" or theSpawner.orders:lower() == \"dummies\" then theSpawner.orders = \"train\" end \
    \
    theSpawner.range = cfxZones.getNumberFromZoneProperty(inZone, \"range\", 300) -- if we have a range, for example enemy detection for Lasing or engage range\
    theSpawner.maxSpawns = cfxZones.getNumberFromZoneProperty(inZone, \"maxSpawns\", -1) -- if there is a limit on how many troops can spawn. -1 = endless spawns\
    theSpawner.requestable = cfxZones.getBoolFromZoneProperty(inZone, \"requestable\", false)\
    if theSpawner.requestable then \
        theSpawner.paused = true \
    end\
    theSpawner.target = cfxZones.getStringFromZoneProperty(inZone, \"target\", \"\")\
    if theSpawner.target == \"\" then -- this is the defaut case \
        theSpawner.target = nil \
    end\
    \
    return theSpawner\
end\
\
function cfxSpawnZones.addSpawner(aSpawner)\
    cfxSpawnZones.allSpawners[aSpawner.zone] = aSpawner\
end\
\
function cfxSpawnZones.removeSpawner(aSpawner)\
    cfxSpawnZones.allSpawners[aSpawner.zone] = nil\
end\
\
function cfxSpawnZones.getSpawnerForZone(aZone)\
    return cfxSpawnZones.allSpawners[aZone]\
end\
\
function cfxSpawnZones.getSpawnerForZoneNamed(aName)\
    local aZone = cfxZones.getZoneByName(aName) \
    return cfxSpawnZones.getSpawnerForZone(aZone)\
end\
\
\
function cfxSpawnZones.getRequestableSpawnersInRange(aPoint, aRange, aSide)\
    -- trigger.action.outText(\"enter requestable spawners for side \" .. aSide , 30)\
    if not aSide then aSide = 0 end  \
    if not aRange then aRange = 200 end \
    if not aPoint then return {} end \
\
    local theSpawners = {}\
    for aZone, aSpawner in pairs(cfxSpawnZones.allSpawners) do \
        -- iterate all zones and collect those that match \
        local hasMatch = true \
        local delta = dcsCommon.dist(aPoint, aZone.point)\
        if delta>aRange then hasMatch = false end \
        if aSide ~= 0 then \
            -- check if side is correct for owned zone \
            if not cfxSpawnZones.verifySpawnOwnership(aSpawner) then \
                -- failed ownership test. owner of master \
                -- is not my own zone \
                hasMatch = false \
            end\
        end\
        \
        if aSide ~= aSpawner.rawOwner then \
            -- only return spawners with this side\
            -- note: this will NOT work with neutral players \
            hasMatch = false \
        end\
        \
        if not aSpawner.requestable then \
            hasMatch = false \
        end\
        \
        if hasMatch then \
            table.insert(theSpawners, aSpawner)\
        end\
    end\
    \
    return theSpawners\
end\
--\
-- spawn troops \
-- \
function cfxSpawnZones.verifySpawnOwnership(spawner)\
    -- returns false ONLY if masterSpawn disagrees\
    if not spawner.masterZoneName then \
        --trigger.action.outText(\"spawner \" .. spawner.name .. \" no master, go!\", 30)\
        return true \
    end -- no master owner, all ok\
    local myCoalition = spawner.rawOwner\
    local masterZone = cfxZones.getZoneByName(spawner.masterZoneName)\
    if not masterZone then \
        trigger.action.outText(\"spawner \" .. spawner.name .. \" DID NOT FIND MASTER ZONE <\" .. spawner.masterZoneName .. \">\", 30)\
    end\
    \
    if not masterZone.owner then \
        --trigger.action.outText(\"spawner \" .. spawner.name .. \" - masterZone \" .. masterZone.name .. \" HAS NO OWNER????\", 30)\
        return true \
    end\
    \
    if (myCoalition ~= masterZone.owner) then \
        -- can't spawn, surrounding area owned by enemy\
        --trigger.action.outText(\"spawner \" .. spawner.name .. \" - spawn suppressed: area not owned: \" .. \" master owner is \" .. masterZone.owner .. \", we are \" .. myCoalition, 30)\
        return false \
    end\
    --trigger.action.outText(\"spawner \" .. spawner.name .. \" good to go: \", 30)\
    return true\
end\
\
function cfxSpawnZones.spawnWithSpawner(aSpawner)\
    -- will NOT check if conditions are met. This forces a spawn\
    local unitTypes = {} -- build type names\
    local p = aSpawner.zone.point  \
        \
    -- split the conf.troopsOnBoardTypes into an array of types\
    unitTypes = dcsCommon.splitString(aSpawner.types, \",\")\
    if #unitTypes < 1 then \
        table.insert(unitTypes, \"Soldier M4\") -- make it one m4 trooper as fallback\
    end\
    \
    local theCountry = aSpawner.country  \
    local theCoalition = coalition.getCountryCoalition(theCountry)\
--    trigger.action.outText(\"+++ spawn: coal <\" .. theCoalition .. \"> from country <\" .. theCountry .. \">\", 30)\
    \
    local theGroup = cfxZones.createGroundUnitsInZoneForCoalition (\
                theCoalition, \
                aSpawner.baseName .. \"-\" .. aSpawner.count, -- must be unique \
                aSpawner.zone,                                             \
                unitTypes,                                                     \
                aSpawner.formation,\
                aSpawner.heading)\
    aSpawner.theSpawn = theGroup\
    aSpawner.count = aSpawner.count + 1 \
    -- we may also want to add this to auto ground troops pool \
    -- we not only want to, we absolutely need to in order \
    -- to make this work. \
    \
    if aSpawner.orders and (\
       aSpawner.orders:lower() == \"training\" or \
       aSpawner.orders:lower() == \"train\" )\
    then \
        -- make them ROE \"HOLD\"\
        cfxCommander.scheduleOptionForGroup(\
            theGroup, \
            AI.Option.Ground.id.ROE, \
            AI.Option.Ground.val.ROE.WEAPON_HOLD, \
            1.0)\
    else \
        local newTroops = cfxGroundTroops.createGroundTroops(theGroup, aSpawner.range, aSpawner.orders) \
        cfxGroundTroops.addGroundTroopsToPool(newTroops)\
        \
        -- see if we have defined a target zone as destination\
        if aSpawner.target then \
            local destZone = cfxZones.getZoneByName(aSpawner.target)\
            if destZone then\
                newTroops.destination = destZone\
                cfxGroundTroops.makeTroopsEngageZone(newTroops)\
            else \
                trigger.action.outText(\"+++ spawner \" .. aSpawner.name .. \" has illegal target \" .. aSpawner.target .. \". Pausing.\", 30)\
                aSpawner.paused = true \
            end\
        elseif aSpawner.orders == \"attackZone\" then \
            trigger.action.outText(\"+++ spawner \" .. aSpawner.name .. \" has no target but attackZone command. Pausing.\", 30)\
                aSpawner.paused = true         \
        end \
        \
    end\
    \
    -- callback to all who want to know \
    cfxSpawnZones.invokeCallbacksFor(\"spawned\", theGroup, aSpawner)\
    \
    -- timestamp so we can check against cooldown on manual spawn\
    aSpawner.lastSpawnTimeStamp = timer.getTime()\
    -- make sure a requestable spawner is always paused \
    if aSpawner.requestable then \
        aSpawner.paused = true \
    end\
    \
    if aSpawner.autoRemove then \
        -- simply remove the group \
        aSpawner.theSpawn = nil\
    end\
end\
\
\
--\
-- U P D A T E \
--\
\
function cfxSpawnZones.update()\
    cfxSpawnZones.updateSchedule = timer.scheduleFunction(cfxSpawnZones.update, {}, timer.getTime() + 1/cfxSpawnZones.ups)\
    \
    for key, spawner in pairs (cfxSpawnZones.allSpawners) do \
        -- see if the spawn is dead or was removed\
        local needsSpawn = true \
        if spawner.theSpawn then \
            local group = spawner.theSpawn\
            if group:isExist() then \
                -- see how many members of this group are still alive\
                local liveUnits = dcsCommon.getLiveGroupUnits(group)\
                -- spawn is still alive, will not spawn\
                if #liveUnits > 1 then \
                    -- we may want to check if this member is still inside\
                    -- of spawn location. currently we don't do that\
                    needsSpawn = false \
                end\
            end\
        end\
    \
        if spawner.paused then needsSpawn = false end \
        \
        -- see if we spawned maximum number of times already\
        -- or have -1 as maxspawn, indicating endless\
        if needsSpawn and spawner.maxSpawns > -1 then \
            needsSpawn = spawner.maxSpawns > 0\
        end\
        \
        if needsSpawn then \
            -- is this the first time? \
            if not spawner.cdStarted then \
                -- no, start cooldown\
                spawner.cdStarted = true \
                spawner.cdTimer = timer.getTime() + spawner.cooldown\
            end\
        end\
\
        -- still on cooldown?\
        if timer.getTime() < spawner.cdTimer then needsSpawn = false end \
        \
        -- is master zone still alinged with me?\
        needsSpawn = needsSpawn and cfxSpawnZones.verifySpawnOwnership(spawner)\
                \
        -- if we get here, and needsSpawn is still set, we go ahead and spawn\
        if needsSpawn then \
---            trigger.action.outText(\"+++ spawning for zone \" .. spawner.zone.name, 30)\
            cfxSpawnZones.spawnWithSpawner(spawner)\
            spawner.cdStarted = false -- reset spawner cd signal \
            if spawner.maxSpawns > 0 then \
                spawner.maxSpawns = spawner.maxSpawns - 1\
            end\
            if spawner.maxSpawns == 0 then \
                spawner.paused = true \
                trigger.action.outText(\"+++ maxspawn -- turning off  zone \" .. spawner.zone.name, 30)\
            end\
        else \
            -- trigger.action.outText(\"+++ NOSPAWN for zone \" .. spawner.zone.name, 30)\
        end\
    end\
end\
\
function cfxSpawnZones.start()\
    if not dcsCommon.libCheck(\"cfx Spawn Zones\", \
        cfxSpawnZones.requiredLibs) then\
        return false \
    end\
    \
    -- collect all spawn zones \
    local attrZones = cfxZones.getZonesWithAttributeNamed(\"spawner\")\
    \
    -- now create a spawner for all, add them to the spawner updater, and spawn for all zones that are not\
    -- paused \
    for k, aZone in pairs(attrZones) do \
        local aSpawner = cfxSpawnZones.createSpawner(aZone)\
        cfxSpawnZones.addSpawner(aSpawner)\
        if not aSpawner.paused and cfxSpawnZones.verifySpawnOwnership(aSpawner) and aSpawner.maxSpawns ~= 0 then \
            cfxSpawnZones.spawnWithSpawner(aSpawner)\
        end\
    end\
    \
    -- and start the regular update calls\
    cfxSpawnZones.update()\
    \
    trigger.action.outText(\"cfx Spawn Zones v\" .. cfxSpawnZones.version .. \" started.\", 30)\
    return true\
end\
\
if not cfxSpawnZones.start() then \
    trigger.action.outText(\"cf/x Spawn Zones aborted: missing libraries\", 30)\
    cfxSpawnZones = nil \
end\
\
--[[--\
IMPROVEMENTS\
 'notMasterOwner' a flag to invert ownership, so we can spawn blue if masterOwner is red\
  \
  take apart owned zone and spawner, so we have a more canonical behaviour\
  \
  'repair' flag - have repair logic for units that are spawned just like now the owned zones do\
--]]--",
                    ["predicate"] = "a_do_script",
                }, -- end of [6]
                [7] = 
                {
                    ["text"] = "jtacGrpUI = {}\
jtacGrpUI.version = \"1.0.2\"\
--[[-- VERSION HISTORY\
 - 1.0.2 - also include idling JTACS\
         - add positional info when using owned zones \
         \
--]]--\
-- find & command cfxGroundTroops-based jtacs\
-- UI installed via OTHER for all groups with players\
-- module based on xxxGrpUI\
 \
jtacGrpUI.groupConfig = {} -- all inited group private config data \
jtacGrpUI.simpleCommands = true -- if true, f10 other invokes directly\
\
--\
-- C O N F I G   H A N D L I N G \
-- =============================\
--\
-- Each group has their own config block that can be used to \
-- store group-private data and configuration items.\
--\
\
function jtacGrpUI.resetConfig(conf)\
end\
\
function jtacGrpUI.createDefaultConfig(theGroup)\
    local conf = {}\
    conf.theGroup = theGroup\
    conf.name = theGroup:getName()\
    conf.id = theGroup:getID()\
    conf.coalition = theGroup:getCoalition() \
    \
    jtacGrpUI.resetConfig(conf)\
\
    conf.mainMenu = nil; -- this is where we store the main menu if we branch\
    conf.myCommands = nil; -- this is where we store the commands if we branch \
    \
    return conf\
end\
\
-- getConfigFor group will allocate if doesn't exist in DB\
-- and add to it\
function jtacGrpUI.getConfigForGroup(theGroup)\
    if not theGroup then \
        trigger.action.outText(\"+++WARNING: jtacGrpUI nil group in getConfigForGroup!\", 30)\
        return nil \
    end\
    local theName = theGroup:getName()\
    local c = jtacGrpUI.getConfigByGroupName(theName) -- we use central accessor\
    if not c then \
        c = jtacGrpUI.createDefaultConfig(theGroup)\
        jtacGrpUI.groupConfig[theName] = c -- should use central accessor...\
    end\
    return c \
end\
\
function jtacGrpUI.getConfigByGroupName(theName) -- DOES NOT allocate when not exist\
    if not theName then return nil end \
    return jtacGrpUI.groupConfig[theName]\
end\
\
\
function jtacGrpUI.getConfigForUnit(theUnit)\
    -- simple one-off step by accessing the group \
    if not theUnit then \
        trigger.action.outText(\"+++WARNING: jtacGrpUI nil unit in getConfigForUnit!\", 30)\
        return nil \
    end\
    \
    local theGroup = theUnit:getGroup()\
    return getConfigForGroup(theGroup)\
end\
\
--\
--\
-- M E N U   H A N D L I N G \
-- =========================\
--\
--\
 function jtacGrpUI.clearCommsSubmenus(conf)\
    if conf.myCommands then \
        for i=1, #conf.myCommands do\
            missionCommands.removeItemForGroup(conf.id, conf.myCommands[i])\
        end\
    end\
    conf.myCommands = {}\
end\
\
function jtacGrpUI.removeCommsFromConfig(conf)\
    jtacGrpUI.clearCommsSubmenus(conf)\
    \
    if conf.myMainMenu then \
        missionCommands.removeItemForGroup(conf.id, conf.myMainMenu) \
        conf.myMainMenu = nil\
    end\
end\
\
-- this only works in single-unit groups. may want to check if group \
-- has disappeared\
function jtacGrpUI.removeCommsForUnit(theUnit)\
    if not theUnit then return end\
    if not theUnit:isExist() then return end     \
    -- perhaps add code: check if group is empty\
    local conf = jtacGrpUI.getConfigForUnit(theUnit)\
    jtacGrpUI.removeCommsFromConfig(conf)\
end\
\
function jtacGrpUI.removeCommsForGroup(theGroup)\
    if not theGroup then return end\
    if not theGroup:isExist() then return end     \
    local conf = jtacGrpUI.getConfigForGroup(theGroup)\
    jtacGrpUI.removeCommsFromConfig(conf)\
end\
\
--\
-- set main root in F10 Other. All sub menus click into this \
--\
function jtacGrpUI.isEligibleForMenu(theGroup)\
    return true\
end\
\
function jtacGrpUI.setCommsMenuForUnit(theUnit)\
    if not theUnit then \
        trigger.action.outText(\"+++WARNING: jtacGrpUI nil UNIT in setCommsMenuForUnit!\", 30)\
        return\
    end\
    if not theUnit:isExist() then return end \
    \
    local theGroup = theUnit:getGroup()\
    jtacGrpUI.setCommsMenu(theGroup)\
end\
\
function jtacGrpUI.setCommsMenu(theGroup)\
    -- depending on own load state, we set the command structure\
    -- it begins at 10-other, and has 'jtac' as main menu with submenus\
    -- as required \
    if not theGroup then return end\
    if not theGroup:isExist() then return end \
    \
    -- we test here if this group qualifies for \
    -- the menu. if not, exit \
    if not jtacGrpUI.isEligibleForMenu(theGroup) then return end\
    \
    local conf = jtacGrpUI.getConfigForGroup(theGroup) \
    conf.id = theGroup:getID(); -- we do this ALWAYS so it is current even after a crash \
--    trigger.action.outText(\"+++ setting group <\".. conf.theGroup:getName() .. \"> jtac command\", 30)\
    \
    if jtacGrpUI.simpleCommands then \
        -- we install directly in F-10 other \
        if not conf.myMainMenu then \
            local commandTxt = \"jtac Lasing Report\"\
            local theCommand =  missionCommands.addCommandForGroup(\
                conf.id, \
                commandTxt,\
                nil,\
                jtacGrpUI.redirectCommandX, \
                {conf, \"lasing report\"}\
                )\
            conf.myMainMenu = theCommand\
        end\
        \
        return \
    end\
    \
    \
    -- ok, first, if we don't have an F-10 menu, create one \
    if not (conf.myMainMenu) then \
        conf.myMainMenu = missionCommands.addSubMenuForGroup(conf.id, 'jtac') \
    end\
    \
    -- clear out existing commands\
    jtacGrpUI.clearCommsSubmenus(conf)\
    \
    -- now we have a menu without submenus. \
    -- add our own submenus\
    jtacGrpUI.addSubMenus(conf)\
    \
end\
\
function jtacGrpUI.addSubMenus(conf)\
    -- add menu items to choose from after \
    -- user clickedf on MAIN MENU. In this implementation\
    -- they all result invoked methods\
    \
    \
    \
    local commandTxt = \"jtac Lasing Report\"\
    local theCommand =  missionCommands.addCommandForGroup(\
                conf.id, \
                commandTxt,\
                conf.myMainMenu,\
                jtacGrpUI.redirectCommandX, \
                {conf, \"lasing report\"}\
                )\
    table.insert(conf.myCommands, theCommand)\
--[[--\
    commandTxt = \"This is another important command\"\
    theCommand =  missionCommands.addCommandForGroup(\
                conf.id, \
                commandTxt,\
                conf.myMainMenu,\
                jtacGrpUI.redirectCommandX, \
                {conf, \"Sub2\"}\
                )\
    table.insert(conf.myCommands, theCommand)\
--]]--\
end\
\
--\
-- each menu item has a redirect and timed invoke to divorce from the\
-- no-debug zone in the menu invocation. Delay is .1 seconds\
--\
\
function jtacGrpUI.redirectCommandX(args)\
    timer.scheduleFunction(jtacGrpUI.doCommandX, args, timer.getTime() + 0.1)\
end\
\
function jtacGrpUI.doCommandX(args)\
    local conf = args[1] -- < conf in here\
    local what = args[2] -- < second argument in here\
    local theGroup = conf.theGroup\
--    trigger.action.outTextForGroup(conf.id, \"+++ groupUI: processing comms menu for <\" .. what .. \">\", 30)\
    local targetList = jtacGrpUI.collectJTACtargets(conf, true)\
    -- iterate the list\
    if #targetList < 1 then \
        trigger.action.outTextForGroup(conf.id, \"No targets are currently being lased\", 30)\
        return \
    end\
    \
    local desc = \"JTAC Target Report:\\n\"\
--    trigger.action.outTextForGroup(conf.id, \"Target Report:\", 30)\
    for i=1, #targetList do \
        local aTarget = targetList[i]\
        if aTarget.idle then \
            desc = desc .. \"\\n\" .. aTarget.jtacName .. aTarget.posInfo ..\": no target\"\
        else \
            desc = desc .. \"\\n\" .. aTarget.jtacName .. aTarget.posInfo ..\" lasing \" .. aTarget.lazeTargetType .. \" [\" .. aTarget.range .. \"nm at \" .. aTarget.bearing .. \"°]\"\
        end \
    end\
    trigger.action.outTextForGroup(conf.id, desc .. \"\\n\", 30)\
end\
\
function jtacGrpUI.collectJTACtargets(conf, includeIdle)\
    -- iterate cfxGroundTroops.deployedTroops to retrieve all \
    -- troops that are lazing. 'Lazing' are all groups that \
    -- have an active (non-nil) lazeTarget and 'laze' orders\
    if not includeIdle then includeIdle = false end \
    \
    local theJTACS = {}\
    for idx, troop in pairs(cfxGroundTroops.deployedTroops) do \
        if troop.coalition == conf.coalition\
         and troop.orders == \"laze\" \
         and troop.lazeTarget \
         and troop.lazeTarget:isExist() \
        then \
            table.insert(theJTACS, troop)\
        elseif troop.coalition == conf.coalition \
         and troop.orders == \"laze\"\
         and includeIdle\
        then \
            -- we also include idlers\
            table.insert(theJTACS, troop)\
        end\
    end\
    \
    -- we now have a list of all ground troops that are lazing.\
    -- get bearing and range to targets, and sort them accordingly\
    local targetList = {}\
    local here = dcsCommon.getGroupLocation(conf.theGroup) -- this is me\
    \
    for idx, troop in pairs (theJTACS) do\
        local aTarget = {}\
        -- establish our location \
        aTarget.jtacName = troop.name \
        aTarget.posInfo = \"\"\
        if cfxOwnedZones and cfxOwnedZones.hasOwnedZones() then \
            local jtacLoc = dcsCommon.getGroupLocation(troop.group)\
            local nearestZone = cfxOwnedZones.getNearestOwnedZoneToPoint(jtacLoc)\
            if nearestZone then \
                local ozRange = dcsCommon.dist(jtacLoc, nearestZone.point) * 0.000621371\
                ozRange = math.floor(ozRange * 10) / 10\
                local relPos = dcsCommon.compassPositionOfARelativeToB(jtacLoc, nearestZone.point)\
                aTarget.posInfo = \" (\" .. ozRange .. \"nm \" .. relPos .. \" of \" .. nearestZone.name .. \")\"\
            end\
        end\
        -- we may get idlers, catch them now \
        if not troop.lazeTarget then \
            aTarget.idle = true\
            aTarget.range = math.huge\
        else \
            -- get the target we are lazing \
            local there = troop.lazeTarget:getPoint()\
            aTarget.idle = false\
            aTarget.range = dcsCommon.dist(here, there)\
            aTarget.range = aTarget.range * 0.000621371 -- meter to miles \
            aTarget.range = math.floor(aTarget.range * 10) / 10\
            aTarget.bearing = dcsCommon.bearingInDegreesFromAtoB(here, there)\
            --aTarget.jtacName = troop.name \
            aTarget.lazeTargetType = troop.lazeTargetType\
        end\
        table.insert(targetList, aTarget)\
    end\
    \
    -- now sort by range \
    table.sort(targetList, function (left, right) return left.range < right.range end )\
    \
    -- return list sorted by distance\
    return targetList\
end\
\
--\
-- G R O U P   M A N A G E M E N T \
--\
-- Group Management is required to make sure all groups\
-- receive a comms menu and that they receive a clean-up \
-- when required \
--\
-- Callbacks are provided by cfxPlayer module to which we\
-- subscribe during init \
--\
function jtacGrpUI.playerChangeEvent(evType, description, player, data)\
    --trigger.action.outText(\"+++ groupUI: received <\".. evType .. \"> Event\", 30)\
    if evType == \"newGroup\" then \
        -- initialized attributes are in data as follows\
        --   .group - new group \
        --   .name - new group's name \
        --   .primeUnit - the unit that trigggered new group appearing \
        --   .primeUnitName - name of prime unit \
        --   .id group ID \
        --theUnit = data.primeUnit\
        jtacGrpUI.setCommsMenu(data.group)\
--        trigger.action.outText(\"+++ groupUI: added \" .. theUnit:getName() .. \" to comms menu\", 30)\
        return \
    end\
    \
    if evType == \"removeGroup\" then \
        -- data is the player record that no longer exists. it consists of\
        --  .name \
        -- we must remove the comms menu for this group else we try to add another one to this group later\
        local conf = jtacGrpUI.getConfigByGroupName(data.name)\
        \
        if conf then \
            jtacGrpUI.removeCommsFromConfig(conf) -- remove menus \
            jtacGrpUI.resetConfig(conf) -- re-init this group for when it re-appears\
        else \
            trigger.action.outText(\"+++ jtacUI: can't retrieve group <\" .. data.name .. \"> config: not found!\", 30)\
        end\
        \
        return\
    end\
    \
    if evType == \"leave\" then\
        -- player unit left. we don't care since we only work on group level\
        -- if they were the only, this is followed up by group disappeared \
        \
    end\
    \
    if evType == \"unit\" then \
        -- player changed units. almost never in MP, but possible in solo\
        -- because of 1 seconds timing loop \
        -- will result in a new group appearing and a group disappearing, so we are good\
        -- may need some logic to clean up old configs and/or menu items \
\
    end\
    \
end\
\
--\
-- Start \
--\
function jtacGrpUI.start()\
\
    -- iterate existing groups so we have a start situation\
    -- now iterate through all player groups and install the Assault Troop Menu\
    allPlayerGroups = cfxPlayerGroups -- cfxPlayerGroups is a global, don't fuck with it! \
    -- contains per group player record. Does not resolve on unit level!\
    for gname, pgroup in pairs(allPlayerGroups) do \
        local theUnit = pgroup.primeUnit -- get any unit of that group\
        jtacGrpUI.setCommsMenuForUnit(theUnit) -- set up\
    end\
    -- now install the new group notifier to install Assault Troops menu\
    \
    cfxPlayer.addMonitor(jtacGrpUI.playerChangeEvent)\
    trigger.action.outText(\"cf/x jtacGrpUI v\" .. jtacGrpUI.version .. \" started\", 30)\
    \
end\
\
--\
-- GO GO GO \
--\
if not cfxGroundTroops then \
    trigger.action.outText(\"cf/x jtacGrpUI REQUIRES cfxGroundTroops to work.\", 30)\
else \
    jtacGrpUI.start()\
end",
                    ["predicate"] = "a_do_script",
                }, -- end of [7]
            }, -- end of ["actions"]
            ["predicate"] = "triggerStart",
            ["comment"] = "Load DML",
        }, -- end of [1]
    }, -- end of ["trigrules"]
    ["currentKey"] = 939,
    ["start_time"] = 28800,
    ["forcedOptions"] = 
    {
        ["weapons"] = true,
        ["optionsView"] = "optview_all",
        ["labels"] = 3,
    }, -- end of ["forcedOptions"]
    ["failures"] = 
    {
        ["pp_damage_EmergMaxTempr"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pp_damage_EmergMaxTempr",
            ["mm"] = 0,
        }, -- end of ["pp_damage_EmergMaxTempr"]
        ["CTRL_RUDDER_ROD_MAJOR_DAMAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_RUDDER_ROD_MAJOR_DAMAGE",
            ["mm"] = 0,
        }, -- end of ["CTRL_RUDDER_ROD_MAJOR_DAMAGE"]
        ["AN_ALR69V_FAILURE_SENSOR_TAIL_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AN_ALR69V_FAILURE_SENSOR_TAIL_RIGHT",
            ["mm"] = 0,
        }, -- end of ["AN_ALR69V_FAILURE_SENSOR_TAIL_RIGHT"]
        ["CTRL_ELEVATOR_ROD_DESTROYED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_ELEVATOR_ROD_DESTROYED",
            ["mm"] = 0,
        }, -- end of ["CTRL_ELEVATOR_ROD_DESTROYED"]
        ["ELEC_STARTER_BURNOUT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_STARTER_BURNOUT",
            ["mm"] = 0,
        }, -- end of ["ELEC_STARTER_BURNOUT"]
        ["ADI_UNIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ADI_UNIT",
            ["mm"] = 0,
        }, -- end of ["ADI_UNIT"]
        ["CTRL_RUDDER_TRIM_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_RUDDER_TRIM_FAILURE",
            ["mm"] = 0,
        }, -- end of ["CTRL_RUDDER_TRIM_FAILURE"]
        ["tail_reductor_chip"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "tail_reductor_chip",
            ["mm"] = 0,
        }, -- end of ["tail_reductor_chip"]
        ["UNCR_C_STRUT_DOWN_LOCK_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UNCR_C_STRUT_DOWN_LOCK_FAILURE",
            ["mm"] = 0,
        }, -- end of ["UNCR_C_STRUT_DOWN_LOCK_FAILURE"]
        ["MWMMC_FAILURE_CPU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_CPU",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_CPU"]
        ["AN_ALE_40V_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AN_ALE_40V_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["AN_ALE_40V_FAILURE_TOTAL"]
        ["FR24RADIO"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FR24RADIO",
            ["mm"] = 0,
        }, -- end of ["FR24RADIO"]
        ["SWMMC_FAILURE_CPU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_CPU",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_CPU"]
        ["FLEX_S_BKP_LAMP_DEFECTIVE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FLEX_S_BKP_LAMP_DEFECTIVE",
            ["mm"] = 0,
        }, -- end of ["FLEX_S_BKP_LAMP_DEFECTIVE"]
        ["FCS_FAILURE_P_SENSOR_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_P_SENSOR_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_P_SENSOR_1"]
        ["oil_press_drop"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "oil_press_drop",
            ["mm"] = 0,
        }, -- end of ["oil_press_drop"]
        ["Failure_Fuel_RightBoostPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Fuel_RightBoostPump",
            ["mm"] = 0,
        }, -- end of ["Failure_Fuel_RightBoostPump"]
        ["Failure_ECS_Valve"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_ECS_Valve",
            ["mm"] = 0,
        }, -- end of ["Failure_ECS_Valve"]
        ["CNI_FAILURE_COM2_SECOS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CNI_FAILURE_COM2_SECOS",
            ["mm"] = 0,
        }, -- end of ["CNI_FAILURE_COM2_SECOS"]
        ["MWMMC_FAILURE_1553B_RWR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_1553B_RWR",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_1553B_RWR"]
        ["hydr_leak"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hydr_leak",
            ["mm"] = 0,
        }, -- end of ["hydr_leak"]
        ["FCS_FAILURE_NY_SENSOR_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_NY_SENSOR_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_NY_SENSOR_1"]
        ["EXT_TANK_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EXT_TANK_LEAK",
            ["mm"] = 0,
        }, -- end of ["EXT_TANK_LEAK"]
        ["EMMC_FAILURE_BATTERY_FCS1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_BATTERY_FCS1",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_BATTERY_FCS1"]
        ["CADC_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["CADC_FAILURE_TOTAL"]
        ["es_damage_MainGenerator"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_MainGenerator",
            ["mm"] = 0,
        }, -- end of ["es_damage_MainGenerator"]
        ["WEAPONS_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "WEAPONS_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["WEAPONS_FAILURE_TOTAL"]
        ["FAILURE_SMS_PYLON_7"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_SMS_PYLON_7",
            ["mm"] = 0,
        }, -- end of ["FAILURE_SMS_PYLON_7"]
        ["RWR_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_TOTAL"]
        ["CNI_FAILURE_IFF_TX"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CNI_FAILURE_IFF_TX",
            ["mm"] = 0,
        }, -- end of ["CNI_FAILURE_IFF_TX"]
        ["FAILURE_EXT_LIGHT_LAND"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_EXT_LIGHT_LAND",
            ["mm"] = 0,
        }, -- end of ["FAILURE_EXT_LIGHT_LAND"]
        ["es_damage_RadarInverter"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_RadarInverter",
            ["mm"] = 0,
        }, -- end of ["es_damage_RadarInverter"]
        ["REAR_TANK_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "REAR_TANK_LEAK",
            ["mm"] = 0,
        }, -- end of ["REAR_TANK_LEAK"]
        ["GUN_LEFT_MG131_OPEN_CIRCUIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_LEFT_MG131_OPEN_CIRCUIT",
            ["mm"] = 0,
        }, -- end of ["GUN_LEFT_MG131_OPEN_CIRCUIT"]
        ["CTRL_ELEVATOR_ROD_MAJOR_DAMAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_ELEVATOR_ROD_MAJOR_DAMAGE",
            ["mm"] = 0,
        }, -- end of ["CTRL_ELEVATOR_ROD_MAJOR_DAMAGE"]
        ["ELEC_STARTER_RELAY_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_STARTER_RELAY_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_STARTER_RELAY_FAILURE"]
        ["fsf_RightBoostPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fsf_RightBoostPump",
            ["mm"] = 0,
        }, -- end of ["fsf_RightBoostPump"]
        ["asc_r"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "asc_r",
            ["mm"] = 0,
        }, -- end of ["asc_r"]
        ["BOMBS_SOLENOID_FAULT_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_SOLENOID_FAULT_LEFT",
            ["mm"] = 0,
        }, -- end of ["BOMBS_SOLENOID_FAULT_LEFT"]
        ["BOMBS_ARMING_NO_VOLATAGE_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_ARMING_NO_VOLATAGE_LEFT",
            ["mm"] = 0,
        }, -- end of ["BOMBS_ARMING_NO_VOLATAGE_LEFT"]
        ["ELEC_BOOSTER_FUEL_PUMP_0_COIL_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_BOOSTER_FUEL_PUMP_0_COIL_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_BOOSTER_FUEL_PUMP_0_COIL_FAILURE"]
        ["FUEL_BOOSTER_FUEL_PUMP_0_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_BOOSTER_FUEL_PUMP_0_FAILURE",
            ["mm"] = 0,
        }, -- end of ["FUEL_BOOSTER_FUEL_PUMP_0_FAILURE"]
        ["ELEC_UC_LAMP_LHD_BULB_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_UC_LAMP_LHD_BULB_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_UC_LAMP_LHD_BULB_FAILURE"]
        ["FUEL_VALVE_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_VALVE_LEAK",
            ["mm"] = 0,
        }, -- end of ["FUEL_VALVE_LEAK"]
        ["AN_ALE_40V_FAILURE_CONTAINER_LEFT_GEAR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AN_ALE_40V_FAILURE_CONTAINER_LEFT_GEAR",
            ["mm"] = 0,
        }, -- end of ["AN_ALE_40V_FAILURE_CONTAINER_LEFT_GEAR"]
        ["INST_MASTER_COMPASS_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_MASTER_COMPASS_FAILURE",
            ["mm"] = 0,
        }, -- end of ["INST_MASTER_COMPASS_FAILURE"]
        ["CARBAIR_SHORT_CIRCUIT_BLB"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CARBAIR_SHORT_CIRCUIT_BLB",
            ["mm"] = 0,
        }, -- end of ["CARBAIR_SHORT_CIRCUIT_BLB"]
        ["FUEL_LH_WING_TANK_MINOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_LH_WING_TANK_MINOR_LEAK",
            ["mm"] = 0,
        }, -- end of ["FUEL_LH_WING_TANK_MINOR_LEAK"]
        ["LEFT_TANK_PUMP_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LEFT_TANK_PUMP_FAULT",
            ["mm"] = 0,
        }, -- end of ["LEFT_TANK_PUMP_FAULT"]
        ["Failure_Ctrl_LEF"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Ctrl_LEF",
            ["mm"] = 0,
        }, -- end of ["Failure_Ctrl_LEF"]
        ["GUN_FAIL_LEFT_IN_GUN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_FAIL_LEFT_IN_GUN",
            ["mm"] = 0,
        }, -- end of ["GUN_FAIL_LEFT_IN_GUN"]
        ["EMMC_FAILURE_BATTERY_DC2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_BATTERY_DC2",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_BATTERY_DC2"]
        ["ELEC_UC_LAMP_CD_BULB_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_UC_LAMP_CD_BULB_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_UC_LAMP_CD_BULB_FAILURE"]
        ["COOLANT_SHORT_CIRCUIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COOLANT_SHORT_CIRCUIT",
            ["mm"] = 0,
        }, -- end of ["COOLANT_SHORT_CIRCUIT"]
        ["abris_hardware"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "abris_hardware",
            ["mm"] = 0,
        }, -- end of ["abris_hardware"]
        ["EEC_Failure_LeftEngine"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EEC_Failure_LeftEngine",
            ["mm"] = 0,
        }, -- end of ["EEC_Failure_LeftEngine"]
        ["RWR_FAILURE_CONTROL_BOX"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_CONTROL_BOX",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_CONTROL_BOX"]
        ["MSC_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MSC_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["MSC_FAILURE_TOTAL"]
        ["ecm"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ecm",
            ["mm"] = 0,
        }, -- end of ["ecm"]
        ["CADC_RUDDER_AUTHORITY_COMMAND"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_RUDDER_AUTHORITY_COMMAND",
            ["mm"] = 0,
        }, -- end of ["CADC_RUDDER_AUTHORITY_COMMAND"]
        ["hs_damage_AltHydro"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hs_damage_AltHydro",
            ["mm"] = 0,
        }, -- end of ["hs_damage_AltHydro"]
        ["ELEC_BOOSTER_FUEL_PUMP_0_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_BOOSTER_FUEL_PUMP_0_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_BOOSTER_FUEL_PUMP_0_FAILURE"]
        ["UNCR_LH_STRUT_UP_LOCK_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UNCR_LH_STRUT_UP_LOCK_FAILURE",
            ["mm"] = 0,
        }, -- end of ["UNCR_LH_STRUT_UP_LOCK_FAILURE"]
        ["asc_a"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "asc_a",
            ["mm"] = 0,
        }, -- end of ["asc_a"]
        ["TURNIND_POINTER_VIBRATES"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TURNIND_POINTER_VIBRATES",
            ["mm"] = 0,
        }, -- end of ["TURNIND_POINTER_VIBRATES"]
        ["GUN_RIGHT_OUT_AMMUN_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_RIGHT_OUT_AMMUN_FAULT",
            ["mm"] = 0,
        }, -- end of ["GUN_RIGHT_OUT_AMMUN_FAULT"]
        ["GUN_RIGHT_IN_AMMUN_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_RIGHT_IN_AMMUN_FAULT",
            ["mm"] = 0,
        }, -- end of ["GUN_RIGHT_IN_AMMUN_FAULT"]
        ["engine_seized"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "engine_seized",
            ["mm"] = 0,
        }, -- end of ["engine_seized"]
        ["ELEC_GENERATOR_REGULATOR_MALFUNCTION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_GENERATOR_REGULATOR_MALFUNCTION",
            ["mm"] = 0,
        }, -- end of ["ELEC_GENERATOR_REGULATOR_MALFUNCTION"]
        ["R_GEAR_BRAKE_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_GEAR_BRAKE_FAULT",
            ["mm"] = 0,
        }, -- end of ["R_GEAR_BRAKE_FAULT"]
        ["FUEL_TANK_01_MINOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_01_MINOR_LEAK",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_01_MINOR_LEAK"]
        ["COMPASS_NO_TORQUE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COMPASS_NO_TORQUE",
            ["mm"] = 0,
        }, -- end of ["COMPASS_NO_TORQUE"]
        ["esf_LeftGenerator"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "esf_LeftGenerator",
            ["mm"] = 0,
        }, -- end of ["esf_LeftGenerator"]
        ["L_GEAR_BRAKE_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_GEAR_BRAKE_FAULT",
            ["mm"] = 0,
        }, -- end of ["L_GEAR_BRAKE_FAULT"]
        ["MAINPOWER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MAINPOWER",
            ["mm"] = 0,
        }, -- end of ["MAINPOWER"]
        ["ef_vibration"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ef_vibration",
            ["mm"] = 0,
        }, -- end of ["ef_vibration"]
        ["STARTER_BURNOUT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STARTER_BURNOUT",
            ["mm"] = 0,
        }, -- end of ["STARTER_BURNOUT"]
        ["SWMMC_FAILURE_CMFCD"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_CMFCD",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_CMFCD"]
        ["OXYN_PRIMARY_CONTAINER_PERFORATED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OXYN_PRIMARY_CONTAINER_PERFORATED",
            ["mm"] = 0,
        }, -- end of ["OXYN_PRIMARY_CONTAINER_PERFORATED"]
        ["FAILURE_HYDRAULICS_1_ACCU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_HYDRAULICS_1_ACCU",
            ["mm"] = 0,
        }, -- end of ["FAILURE_HYDRAULICS_1_ACCU"]
        ["OIL_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OIL_LEAK",
            ["mm"] = 0,
        }, -- end of ["OIL_LEAK"]
        ["FCS_FAILURE_LG_3"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_LG_3",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_LG_3"]
        ["OIL_SYSTEM_FAIL_050"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OIL_SYSTEM_FAIL_050",
            ["mm"] = 0,
        }, -- end of ["OIL_SYSTEM_FAIL_050"]
        ["ENGINE_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENGINE_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["ENGINE_FAILURE_TOTAL"]
        ["ELEC_MASTER_COMPASS_HARNESS_CUT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_MASTER_COMPASS_HARNESS_CUT",
            ["mm"] = 0,
        }, -- end of ["ELEC_MASTER_COMPASS_HARNESS_CUT"]
        ["CTRL_RUDDER_ROD_DESTROYED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_RUDDER_ROD_DESTROYED",
            ["mm"] = 0,
        }, -- end of ["CTRL_RUDDER_ROD_DESTROYED"]
        ["HYDR1PUMP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYDR1PUMP",
            ["mm"] = 0,
        }, -- end of ["HYDR1PUMP"]
        ["GUN_RIGHT_IN_BARREL_WORN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_RIGHT_IN_BARREL_WORN",
            ["mm"] = 0,
        }, -- end of ["GUN_RIGHT_IN_BARREL_WORN"]
        ["FUEL_FUEL_PUMP_P1_DEGRADED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_FUEL_PUMP_P1_DEGRADED",
            ["mm"] = 0,
        }, -- end of ["FUEL_FUEL_PUMP_P1_DEGRADED"]
        ["FUEL_NITRO_TANK_MAJOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "FUEL_NITRO_TANK_MAJOR_LEAK",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_NITRO_TANK_MAJOR_LEAK"]
        ["FCS_FAILURE_ROLL_AUGD_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_ROLL_AUGD_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_ROLL_AUGD_2"]
        ["INS_PART_FAIL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_PART_FAIL",
            ["mm"] = 0,
        }, -- end of ["INS_PART_FAIL"]
        ["GUN_RIGHT_OUT_BARREL_WORN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_RIGHT_OUT_BARREL_WORN",
            ["mm"] = 0,
        }, -- end of ["GUN_RIGHT_OUT_BARREL_WORN"]
        ["FUEL_TANK_00_EXPLODED"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_00_EXPLODED",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_00_EXPLODED"]
        ["MD1_GYRO_TOTAL_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MD1_GYRO_TOTAL_FAILURE",
            ["mm"] = 0,
        }, -- end of ["MD1_GYRO_TOTAL_FAILURE"]
        ["SWMMC_AAP_NO_RS422_COMM"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_AAP_NO_RS422_COMM",
            ["mm"] = 0,
        }, -- end of ["SWMMC_AAP_NO_RS422_COMM"]
        ["ENG0_WATERRADIATOR0_PIERCED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_WATERRADIATOR0_PIERCED",
            ["mm"] = 0,
        }, -- end of ["ENG0_WATERRADIATOR0_PIERCED"]
        ["FUEL_TANK_00_MAJOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_00_MAJOR_LEAK",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_00_MAJOR_LEAK"]
        ["IMU_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "IMU_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["IMU_FAILURE_TOTAL"]
        ["FLEX_S_NO_GUN_SIGN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FLEX_S_NO_GUN_SIGN",
            ["mm"] = 0,
        }, -- end of ["FLEX_S_NO_GUN_SIGN"]
        ["GUN_LEFT_IN_OPEN_CIRCUIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_LEFT_IN_OPEN_CIRCUIT",
            ["mm"] = 0,
        }, -- end of ["GUN_LEFT_IN_OPEN_CIRCUIT"]
        ["HYD_PUMP_1_FAIL_100"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYD_PUMP_1_FAIL_100",
            ["mm"] = 0,
        }, -- end of ["HYD_PUMP_1_FAIL_100"]
        ["engine_surge_failure"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "engine_surge_failure",
            ["mm"] = 0,
        }, -- end of ["engine_surge_failure"]
        ["hs_damage_GainPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hs_damage_GainPump",
            ["mm"] = 0,
        }, -- end of ["hs_damage_GainPump"]
        ["FCS_FAILURE_PITCH_RATE_GYRO_3"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_PITCH_RATE_GYRO_3",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_PITCH_RATE_GYRO_3"]
        ["CTRL_AILERON_ROD_MAJOR_DAMAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_AILERON_ROD_MAJOR_DAMAGE",
            ["mm"] = 0,
        }, -- end of ["CTRL_AILERON_ROD_MAJOR_DAMAGE"]
        ["CK_UNIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CK_UNIT",
            ["mm"] = 0,
        }, -- end of ["CK_UNIT"]
        ["FUEL_ENGINE0_FUEL_PUMP_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_ENGINE0_FUEL_PUMP_FAILURE",
            ["mm"] = 0,
        }, -- end of ["FUEL_ENGINE0_FUEL_PUMP_FAILURE"]
        ["RWR_FAILURE_ANTENNA_REAR_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_ANTENNA_REAR_RIGHT",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_ANTENNA_REAR_RIGHT"]
        ["RADARALTUNIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RADARALTUNIT",
            ["mm"] = 0,
        }, -- end of ["RADARALTUNIT"]
        ["EMMC_FAILURE_DC_GENERATOR_VOLTAGE_LOW"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_DC_GENERATOR_VOLTAGE_LOW",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_DC_GENERATOR_VOLTAGE_LOW"]
        ["CARBAIR_OPEN_CIRCUIT_BLB"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CARBAIR_OPEN_CIRCUIT_BLB",
            ["mm"] = 0,
        }, -- end of ["CARBAIR_OPEN_CIRCUIT_BLB"]
        ["Failure_Comp_ADC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Comp_ADC",
            ["mm"] = 0,
        }, -- end of ["Failure_Comp_ADC"]
        ["ENG0_OIL_HOSE_1_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_OIL_HOSE_1_LEAK",
            ["mm"] = 0,
        }, -- end of ["ENG0_OIL_HOSE_1_LEAK"]
        ["HYDRO_LOW_AIR_PRESSURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYDRO_LOW_AIR_PRESSURE",
            ["mm"] = 0,
        }, -- end of ["HYDRO_LOW_AIR_PRESSURE"]
        ["ELEC_GREEN_SIGNAL_LIGHT_BROKEN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_GREEN_SIGNAL_LIGHT_BROKEN",
            ["mm"] = 0,
        }, -- end of ["ELEC_GREEN_SIGNAL_LIGHT_BROKEN"]
        ["FUEL_MAIN_FUEL_PUMP_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_MAIN_FUEL_PUMP_FAILURE",
            ["mm"] = 0,
        }, -- end of ["FUEL_MAIN_FUEL_PUMP_FAILURE"]
        ["ELEC_GENERATOR_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_GENERATOR_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_GENERATOR_FAILURE"]
        ["FR24ANTENNA"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FR24ANTENNA",
            ["mm"] = 0,
        }, -- end of ["FR24ANTENNA"]
        ["FCS_FAILURE_L_ELEVATOR_HYD_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_L_ELEVATOR_HYD_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_L_ELEVATOR_HYD_2"]
        ["GENERATOR_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GENERATOR_FAULT",
            ["mm"] = 0,
        }, -- end of ["GENERATOR_FAULT"]
        ["ssf_static_pressure_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ssf_static_pressure_fail",
            ["mm"] = 0,
        }, -- end of ["ssf_static_pressure_fail"]
        ["FUEL_PUMP_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_PUMP_FAILURE",
            ["mm"] = 0,
        }, -- end of ["FUEL_PUMP_FAILURE"]
        ["ppf_RightNozzleControl"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ppf_RightNozzleControl",
            ["mm"] = 0,
        }, -- end of ["ppf_RightNozzleControl"]
        ["ELEC_NAVLIGHT_RED_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_NAVLIGHT_RED_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_NAVLIGHT_RED_FAILURE"]
        ["RWR_FAILURE_QUAD45"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_QUAD45",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_QUAD45"]
        ["JAMMER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "JAMMER",
            ["mm"] = 0,
        }, -- end of ["JAMMER"]
        ["INS_FAILURE_ALT_INVALID"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_FAILURE_ALT_INVALID",
            ["mm"] = 0,
        }, -- end of ["INS_FAILURE_ALT_INVALID"]
        ["INS_FAILURE_VELOCITY"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_FAILURE_VELOCITY",
            ["mm"] = 0,
        }, -- end of ["INS_FAILURE_VELOCITY"]
        ["ARBS_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ARBS_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["ARBS_FAILURE_TOTAL"]
        ["OXY_FAILURE_R_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OXY_FAILURE_R_LEAK",
            ["mm"] = 0,
        }, -- end of ["OXY_FAILURE_R_LEAK"]
        ["fs_damage_right_cell_boost_pump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fs_damage_right_cell_boost_pump",
            ["mm"] = 0,
        }, -- end of ["fs_damage_right_cell_boost_pump"]
        ["GUN_RIGHT_OUT_MOUNT_LOOSE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_RIGHT_OUT_MOUNT_LOOSE",
            ["mm"] = 0,
        }, -- end of ["GUN_RIGHT_OUT_MOUNT_LOOSE"]
        ["ef_fuel_reg"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ef_fuel_reg",
            ["mm"] = 0,
        }, -- end of ["ef_fuel_reg"]
        ["ENG0_WATER_RADIATOR_1_PIERCED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_WATER_RADIATOR_1_PIERCED",
            ["mm"] = 0,
        }, -- end of ["ENG0_WATER_RADIATOR_1_PIERCED"]
        ["GSH23_CHARGED_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GSH23_CHARGED_FAILURE",
            ["mm"] = 0,
        }, -- end of ["GSH23_CHARGED_FAILURE"]
        ["TACH_POOR_CONNECTION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TACH_POOR_CONNECTION",
            ["mm"] = 0,
        }, -- end of ["TACH_POOR_CONNECTION"]
        ["CTRL_RH_SLAT_JAMMED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_RH_SLAT_JAMMED",
            ["mm"] = 0,
        }, -- end of ["CTRL_RH_SLAT_JAMMED"]
        ["PNEM_ENGINE_HOSE_PERFORATED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PNEM_ENGINE_HOSE_PERFORATED",
            ["mm"] = 0,
        }, -- end of ["PNEM_ENGINE_HOSE_PERFORATED"]
        ["sas_yaw_right"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "sas_yaw_right",
            ["mm"] = 0,
        }, -- end of ["sas_yaw_right"]
        ["ENG0_OIL_RADIATOR_1_PIERCED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_OIL_RADIATOR_1_PIERCED",
            ["mm"] = 0,
        }, -- end of ["ENG0_OIL_RADIATOR_1_PIERCED"]
        ["R_GEAR_UPL_JAMMED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_GEAR_UPL_JAMMED",
            ["mm"] = 0,
        }, -- end of ["R_GEAR_UPL_JAMMED"]
        ["hydro_left"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hydro_left",
            ["mm"] = 0,
        }, -- end of ["hydro_left"]
        ["FCS_FAILURE_YAW_LVDT_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_YAW_LVDT_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_YAW_LVDT_2"]
        ["L_GEAR_UPL_JAMMED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_GEAR_UPL_JAMMED",
            ["mm"] = 0,
        }, -- end of ["L_GEAR_UPL_JAMMED"]
        ["fs_damage_BoosterPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fs_damage_BoosterPump",
            ["mm"] = 0,
        }, -- end of ["fs_damage_BoosterPump"]
        ["UHF_ARC_159_FAILURE_REMOTE_DISPLAY_RIO"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UHF_ARC_159_FAILURE_REMOTE_DISPLAY_RIO",
            ["mm"] = 0,
        }, -- end of ["UHF_ARC_159_FAILURE_REMOTE_DISPLAY_RIO"]
        ["RWR_FAILURE_DISPLAY_PILOT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_DISPLAY_PILOT",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_DISPLAY_PILOT"]
        ["STATION_3_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STATION_3_FAILURE",
            ["mm"] = 0,
        }, -- end of ["STATION_3_FAILURE"]
        ["RIGHT_FLAP_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RIGHT_FLAP_FAULT",
            ["mm"] = 0,
        }, -- end of ["RIGHT_FLAP_FAULT"]
        ["INT_HYDRO_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INT_HYDRO_LEAK",
            ["mm"] = 0,
        }, -- end of ["INT_HYDRO_LEAK"]
        ["FAILURE_EXT_LIGHT_FORMATION_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_EXT_LIGHT_FORMATION_LEFT",
            ["mm"] = 0,
        }, -- end of ["FAILURE_EXT_LIGHT_FORMATION_LEFT"]
        ["STARTER_WIRING"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STARTER_WIRING",
            ["mm"] = 0,
        }, -- end of ["STARTER_WIRING"]
        ["pitch_trim_runaway_up"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pitch_trim_runaway_up",
            ["mm"] = 0,
        }, -- end of ["pitch_trim_runaway_up"]
        ["ELEVONSERVINNERRIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEVONSERVINNERRIGHT",
            ["mm"] = 0,
        }, -- end of ["ELEVONSERVINNERRIGHT"]
        ["es_damage_GeneratorLeft"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_GeneratorLeft",
            ["mm"] = 0,
        }, -- end of ["es_damage_GeneratorLeft"]
        ["engine_chip"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "engine_chip",
            ["mm"] = 0,
        }, -- end of ["engine_chip"]
        ["GMC_TOTAL_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GMC_TOTAL_FAILURE",
            ["mm"] = 0,
        }, -- end of ["GMC_TOTAL_FAILURE"]
        ["CADC_FAILURE_MACH"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_FAILURE_MACH",
            ["mm"] = 0,
        }, -- end of ["CADC_FAILURE_MACH"]
        ["fs_damage_TransferPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fs_damage_TransferPump",
            ["mm"] = 0,
        }, -- end of ["fs_damage_TransferPump"]
        ["RightEngine_ShaveInOil"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RightEngine_ShaveInOil",
            ["mm"] = 0,
        }, -- end of ["RightEngine_ShaveInOil"]
        ["es_damage_EmergGen"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_EmergGen",
            ["mm"] = 0,
        }, -- end of ["es_damage_EmergGen"]
        ["rudder_loss"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "rudder_loss",
            ["mm"] = 0,
        }, -- end of ["rudder_loss"]
        ["FR22ANTENNA"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FR22ANTENNA",
            ["mm"] = 0,
        }, -- end of ["FR22ANTENNA"]
        ["laser_failure"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "laser_failure",
            ["mm"] = 0,
        }, -- end of ["laser_failure"]
        ["tacan_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["mm"] = 0,
        }, -- end of ["tacan_fail"]
        ["BOMBS_NO_VOLATAGE_BOTH"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_NO_VOLATAGE_BOTH",
            ["mm"] = 0,
        }, -- end of ["BOMBS_NO_VOLATAGE_BOTH"]
        ["FUEL_FUSELAGE_TANK_MINOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_FUSELAGE_TANK_MINOR_LEAK",
            ["mm"] = 0,
        }, -- end of ["FUEL_FUSELAGE_TANK_MINOR_LEAK"]
        ["EZ42_FIXED_LAMP_DEFECTIVE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EZ42_FIXED_LAMP_DEFECTIVE",
            ["mm"] = 0,
        }, -- end of ["EZ42_FIXED_LAMP_DEFECTIVE"]
        ["PITOT_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PITOT_FAILURE",
            ["mm"] = 0,
        }, -- end of ["PITOT_FAILURE"]
        ["ELEC_BOOSTER_FUEL_PUMP_2_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_BOOSTER_FUEL_PUMP_2_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_BOOSTER_FUEL_PUMP_2_FAILURE"]
        ["SNS_FAILURE_COMPUTER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SNS_FAILURE_COMPUTER",
            ["mm"] = 0,
        }, -- end of ["SNS_FAILURE_COMPUTER"]
        ["csf_PitchTrim"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "csf_PitchTrim",
            ["mm"] = 0,
        }, -- end of ["csf_PitchTrim"]
        ["CANARDSERVOLEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CANARDSERVOLEFT",
            ["mm"] = 0,
        }, -- end of ["CANARDSERVOLEFT"]
        ["COOLANT_DEFECTIVE_IND"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COOLANT_DEFECTIVE_IND",
            ["mm"] = 0,
        }, -- end of ["COOLANT_DEFECTIVE_IND"]
        ["CNI_FAILURE_COM1_SECOS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CNI_FAILURE_COM1_SECOS",
            ["mm"] = 0,
        }, -- end of ["CNI_FAILURE_COM1_SECOS"]
        ["INS_DATA_DEGRADED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_DATA_DEGRADED",
            ["mm"] = 0,
        }, -- end of ["INS_DATA_DEGRADED"]
        ["Failure_PP_EngR_OilLeak"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_PP_EngR_OilLeak",
            ["mm"] = 0,
        }, -- end of ["Failure_PP_EngR_OilLeak"]
        ["RKL_41_TOTAL_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RKL_41_TOTAL_FAILURE",
            ["mm"] = 0,
        }, -- end of ["RKL_41_TOTAL_FAILURE"]
        ["EMMC_FAILURE_DADS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_DADS",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_DADS"]
        ["hs_damage_UtilityHydro"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hs_damage_UtilityHydro",
            ["mm"] = 0,
        }, -- end of ["hs_damage_UtilityHydro"]
        ["pp_damage_Ignition"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pp_damage_Ignition",
            ["mm"] = 0,
        }, -- end of ["pp_damage_Ignition"]
        ["FCS_FAILURE_PITCH_RATE_GYRO_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_PITCH_RATE_GYRO_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_PITCH_RATE_GYRO_1"]
        ["MWMMC_FAILURE_1553B_TACAN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_1553B_TACAN",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_1553B_TACAN"]
        ["HYDR_UNLOAD_VALVE_NOT_UNLOAD"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYDR_UNLOAD_VALVE_NOT_UNLOAD",
            ["mm"] = 0,
        }, -- end of ["HYDR_UNLOAD_VALVE_NOT_UNLOAD"]
        ["FCS_FAILURE_L_ELEVATOR_ELEC_D"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_L_ELEVATOR_ELEC_D",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_L_ELEVATOR_ELEC_D"]
        ["FUEL_TANK_01_MEDIUM_LEAK"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "FUEL_TANK_01_MEDIUM_LEAK",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_01_MEDIUM_LEAK"]
        ["EPRSENSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EPRSENSOR",
            ["mm"] = 0,
        }, -- end of ["EPRSENSOR"]
        ["MWMMC_FAILURE_1553B_IFF"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_1553B_IFF",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_1553B_IFF"]
        ["RWRUNIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWRUNIT",
            ["mm"] = 0,
        }, -- end of ["RWRUNIT"]
        ["ENG_ALT_2_FAIL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG_ALT_2_FAIL",
            ["mm"] = 0,
        }, -- end of ["ENG_ALT_2_FAIL"]
        ["ZCP_FAILURE_MALFUNC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ZCP_FAILURE_MALFUNC",
            ["mm"] = 0,
        }, -- end of ["ZCP_FAILURE_MALFUNC"]
        ["CADC_FAILURE_BARO_ALT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_FAILURE_BARO_ALT",
            ["mm"] = 0,
        }, -- end of ["CADC_FAILURE_BARO_ALT"]
        ["oxy_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "oxy_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["oxy_FAILURE_TOTAL"]
        ["ICS_FAILURE_AMPLIFIER_RIO_NORM"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ICS_FAILURE_AMPLIFIER_RIO_NORM",
            ["mm"] = 0,
        }, -- end of ["ICS_FAILURE_AMPLIFIER_RIO_NORM"]
        ["ENGINE_FAILURE_N2_TURBINE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENGINE_FAILURE_N2_TURBINE",
            ["mm"] = 0,
        }, -- end of ["ENGINE_FAILURE_N2_TURBINE"]
        ["BOMBS_ARMING_BROKEN_SOLENOID_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_ARMING_BROKEN_SOLENOID_RIGHT",
            ["mm"] = 0,
        }, -- end of ["BOMBS_ARMING_BROKEN_SOLENOID_RIGHT"]
        ["fuel_sys_right_transfer_pump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fuel_sys_right_transfer_pump",
            ["mm"] = 0,
        }, -- end of ["fuel_sys_right_transfer_pump"]
        ["STARTER_LOSE_CON"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STARTER_LOSE_CON",
            ["mm"] = 0,
        }, -- end of ["STARTER_LOSE_CON"]
        ["Failure_PP_EngL_Nozzle_CS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_PP_EngL_Nozzle_CS",
            ["mm"] = 0,
        }, -- end of ["Failure_PP_EngL_Nozzle_CS"]
        ["FCS_FAILURE_COMP_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_COMP_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_COMP_2"]
        ["FCS_FAILURE_PITCH_LVDT_3"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_PITCH_LVDT_3",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_PITCH_LVDT_3"]
        ["W_S_R"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "W_S_R",
            ["mm"] = 0,
        }, -- end of ["W_S_R"]
        ["SAR_2_95"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "SAR_2_95",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["SAR_2_95"]
        ["SWMMC_FAILURE_AVI"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_AVI",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_AVI"]
        ["EZ42_NO_POWER_SUPPLY"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EZ42_NO_POWER_SUPPLY",
            ["mm"] = 0,
        }, -- end of ["EZ42_NO_POWER_SUPPLY"]
        ["MWMMC_FAILURE_AVI"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_AVI",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_AVI"]
        ["pp_damage_MainMaxTempr"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pp_damage_MainMaxTempr",
            ["mm"] = 0,
        }, -- end of ["pp_damage_MainMaxTempr"]
        ["PUMP_SEPARATOR_CLOGGED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PUMP_SEPARATOR_CLOGGED",
            ["mm"] = 0,
        }, -- end of ["PUMP_SEPARATOR_CLOGGED"]
        ["Vibration_LeftEngine"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "Vibration_LeftEngine",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["Vibration_LeftEngine"]
        ["explosive_depressurization"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "explosive_depressurization",
            ["mm"] = 0,
        }, -- end of ["explosive_depressurization"]
        ["UNCR_LH_WHEEL_BRAKE_DAMAGED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UNCR_LH_WHEEL_BRAKE_DAMAGED",
            ["mm"] = 0,
        }, -- end of ["UNCR_LH_WHEEL_BRAKE_DAMAGED"]
        ["DOORS_TV_JAMMED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DOORS_TV_JAMMED",
            ["mm"] = 0,
        }, -- end of ["DOORS_TV_JAMMED"]
        ["UHF_ARC_159_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UHF_ARC_159_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["UHF_ARC_159_FAILURE_TOTAL"]
        ["AN_ALR69V_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AN_ALR69V_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["AN_ALR69V_FAILURE_TOTAL"]
        ["Failure_Hyd_HYD1A_Leak"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Hyd_HYD1A_Leak",
            ["mm"] = 0,
        }, -- end of ["Failure_Hyd_HYD1A_Leak"]
        ["R_GEAR_MOTOR_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_GEAR_MOTOR_FAULT",
            ["mm"] = 0,
        }, -- end of ["R_GEAR_MOTOR_FAULT"]
        ["es_damage_Inverter115_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_Inverter115_1",
            ["mm"] = 0,
        }, -- end of ["es_damage_Inverter115_1"]
        ["PNEM_MACHINE_GUNS_HOSE_PERFORATED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PNEM_MACHINE_GUNS_HOSE_PERFORATED",
            ["mm"] = 0,
        }, -- end of ["PNEM_MACHINE_GUNS_HOSE_PERFORATED"]
        ["FCS_FAILURE_ROLL_ELEC_SERVO_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_ROLL_ELEC_SERVO_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_ROLL_ELEC_SERVO_1"]
        ["ENGINE_FAILURE_AB_IGNITION_UNIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENGINE_FAILURE_AB_IGNITION_UNIT",
            ["mm"] = 0,
        }, -- end of ["ENGINE_FAILURE_AB_IGNITION_UNIT"]
        ["L_GEAR_MOTOR_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_GEAR_MOTOR_FAULT",
            ["mm"] = 0,
        }, -- end of ["L_GEAR_MOTOR_FAULT"]
        ["ELEVONINNERRIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEVONINNERRIGHT",
            ["mm"] = 0,
        }, -- end of ["ELEVONINNERRIGHT"]
        ["helmet"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "helmet",
            ["mm"] = 0,
        }, -- end of ["helmet"]
        ["batteries_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "batteries_fail",
            ["mm"] = 0,
        }, -- end of ["batteries_fail"]
        ["hs_damage_MainPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hs_damage_MainPump",
            ["mm"] = 0,
        }, -- end of ["hs_damage_MainPump"]
        ["MainReductor_ShaveInOil"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MainReductor_ShaveInOil",
            ["mm"] = 0,
        }, -- end of ["MainReductor_ShaveInOil"]
        ["FCS_FAILURE_ROLL_AUGD_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_ROLL_AUGD_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_ROLL_AUGD_1"]
        ["FUEL_FUEL_PUMP_P2_DEGRADED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_FUEL_PUMP_P2_DEGRADED",
            ["mm"] = 0,
        }, -- end of ["FUEL_FUEL_PUMP_P2_DEGRADED"]
        ["PNEM_SECONDARY_CONTAINER_PERFORATED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PNEM_SECONDARY_CONTAINER_PERFORATED",
            ["mm"] = 0,
        }, -- end of ["PNEM_SECONDARY_CONTAINER_PERFORATED"]
        ["PNEM_RH_FLAP_JACK_BUSTED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PNEM_RH_FLAP_JACK_BUSTED",
            ["mm"] = 0,
        }, -- end of ["PNEM_RH_FLAP_JACK_BUSTED"]
        ["WEAP_GUN_02_AMMO_BELT_SEVERED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "WEAP_GUN_02_AMMO_BELT_SEVERED",
            ["mm"] = 0,
        }, -- end of ["WEAP_GUN_02_AMMO_BELT_SEVERED"]
        ["AAR_47_FAILURE_SENSOR_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AAR_47_FAILURE_SENSOR_LEFT",
            ["mm"] = 0,
        }, -- end of ["AAR_47_FAILURE_SENSOR_LEFT"]
        ["VHF_ARC_182_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VHF_ARC_182_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["VHF_ARC_182_FAILURE_TOTAL"]
        ["GUN_LEFT_MG131_BARREL_WORN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_LEFT_MG131_BARREL_WORN",
            ["mm"] = 0,
        }, -- end of ["GUN_LEFT_MG131_BARREL_WORN"]
        ["OXYN_PRIMARY_CONTAINER_MINOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OXYN_PRIMARY_CONTAINER_MINOR_LEAK",
            ["mm"] = 0,
        }, -- end of ["OXYN_PRIMARY_CONTAINER_MINOR_LEAK"]
        ["PPF_RE_TEMPER_LIM_OFF"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "PPF_RE_TEMPER_LIM_OFF",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["PPF_RE_TEMPER_LIM_OFF"]
        ["FCS_FAILURE_R_ELEVATOR_ELEC_A"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_R_ELEVATOR_ELEC_A",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_R_ELEVATOR_ELEC_A"]
        ["DC_BUS_GENERATOR_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DC_BUS_GENERATOR_FAILURE",
            ["mm"] = 0,
        }, -- end of ["DC_BUS_GENERATOR_FAILURE"]
        ["ELEC_BATTERY_DESTROYED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_BATTERY_DESTROYED",
            ["mm"] = 0,
        }, -- end of ["ELEC_BATTERY_DESTROYED"]
        ["Failure_Sens_LeftPitotHeater"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Sens_LeftPitotHeater",
            ["mm"] = 0,
        }, -- end of ["Failure_Sens_LeftPitotHeater"]
        ["HYD_ALT_2_FAIL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYD_ALT_2_FAIL",
            ["mm"] = 0,
        }, -- end of ["HYD_ALT_2_FAIL"]
        ["TAIL_GEAR_FAIL_GO_DOWN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TAIL_GEAR_FAIL_GO_DOWN",
            ["mm"] = 0,
        }, -- end of ["TAIL_GEAR_FAIL_GO_DOWN"]
        ["GUN_FAIL_RIGHT_CENTER_GUN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_FAIL_RIGHT_CENTER_GUN",
            ["mm"] = 0,
        }, -- end of ["GUN_FAIL_RIGHT_CENTER_GUN"]
        ["LeftEngine_ShaveInOil"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LeftEngine_ShaveInOil",
            ["mm"] = 0,
        }, -- end of ["LeftEngine_ShaveInOil"]
        ["BACKUPGENERATOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BACKUPGENERATOR",
            ["mm"] = 0,
        }, -- end of ["BACKUPGENERATOR"]
        ["MAIN_R_GEAR_D_LOCK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MAIN_R_GEAR_D_LOCK",
            ["mm"] = 0,
        }, -- end of ["MAIN_R_GEAR_D_LOCK"]
        ["FAILURE_HYDRAULICS_2_EXTERNAL_LEAKAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_HYDRAULICS_2_EXTERNAL_LEAKAGE",
            ["mm"] = 0,
        }, -- end of ["FAILURE_HYDRAULICS_2_EXTERNAL_LEAKAGE"]
        ["ENGINE_FAILURE_N2_COMPRESSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENGINE_FAILURE_N2_COMPRESSOR",
            ["mm"] = 0,
        }, -- end of ["ENGINE_FAILURE_N2_COMPRESSOR"]
        ["fs_damage_MainPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fs_damage_MainPump",
            ["mm"] = 0,
        }, -- end of ["fs_damage_MainPump"]
        ["ELEC_FUEL_PUMP_P1_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_FUEL_PUMP_P1_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_FUEL_PUMP_P1_FAILURE"]
        ["K14_FIXED_LAMP_DEFECTIVE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "K14_FIXED_LAMP_DEFECTIVE",
            ["mm"] = 0,
        }, -- end of ["K14_FIXED_LAMP_DEFECTIVE"]
        ["RDR_FAILURE_RX_FRONT_END_DEGRATION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RDR_FAILURE_RX_FRONT_END_DEGRATION",
            ["mm"] = 0,
        }, -- end of ["RDR_FAILURE_RX_FRONT_END_DEGRATION"]
        ["EMMC_FAILURE_ELECT_EQUIP_HOT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_ELECT_EQUIP_HOT",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_ELECT_EQUIP_HOT"]
        ["TGP_FAILURE_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TGP_FAILURE_LEFT",
            ["mm"] = 0,
        }, -- end of ["TGP_FAILURE_LEFT"]
        ["Failure_Elec_LeftGenerator"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Elec_LeftGenerator",
            ["mm"] = 0,
        }, -- end of ["Failure_Elec_LeftGenerator"]
        ["SNS_FAILURE_ANTENNA"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SNS_FAILURE_ANTENNA",
            ["mm"] = 0,
        }, -- end of ["SNS_FAILURE_ANTENNA"]
        ["RWR_FAILURE_SENSOR_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_SENSOR_LEFT",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_SENSOR_LEFT"]
        ["MWMMC_FAILURE_1553B_ILS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_1553B_ILS",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_1553B_ILS"]
        ["ELEC_LH_FLAPS_DRIVE_WIRE_SEVERED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_LH_FLAPS_DRIVE_WIRE_SEVERED",
            ["mm"] = 0,
        }, -- end of ["ELEC_LH_FLAPS_DRIVE_WIRE_SEVERED"]
        ["TOP_CYLINDER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TOP_CYLINDER",
            ["mm"] = 0,
        }, -- end of ["TOP_CYLINDER"]
        ["RADAR_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RADAR_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["RADAR_FAILURE_TOTAL"]
        ["PNEM_FLAPS_HOSE_PERFORATED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PNEM_FLAPS_HOSE_PERFORATED",
            ["mm"] = 0,
        }, -- end of ["PNEM_FLAPS_HOSE_PERFORATED"]
        ["ELEC_LH_GEAR_DRIVE_WIRE_SEVERED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_LH_GEAR_DRIVE_WIRE_SEVERED",
            ["mm"] = 0,
        }, -- end of ["ELEC_LH_GEAR_DRIVE_WIRE_SEVERED"]
        ["L_GEAR_UPL_NOT_LOCK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_GEAR_UPL_NOT_LOCK",
            ["mm"] = 0,
        }, -- end of ["L_GEAR_UPL_NOT_LOCK"]
        ["FUEL_MAIN_FUEL_PUMP_DEGRADED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_MAIN_FUEL_PUMP_DEGRADED",
            ["mm"] = 0,
        }, -- end of ["FUEL_MAIN_FUEL_PUMP_DEGRADED"]
        ["sas_yaw_left"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "sas_yaw_left",
            ["mm"] = 0,
        }, -- end of ["sas_yaw_left"]
        ["AC_BUS_PO7501_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AC_BUS_PO7501_FAILURE",
            ["mm"] = 0,
        }, -- end of ["AC_BUS_PO7501_FAILURE"]
        ["FAILURE_EXT_LIGHT_TAXI"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_EXT_LIGHT_TAXI",
            ["mm"] = 0,
        }, -- end of ["FAILURE_EXT_LIGHT_TAXI"]
        ["Failure_PP_RightAMAD_OilLeak"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_PP_RightAMAD_OilLeak",
            ["mm"] = 0,
        }, -- end of ["Failure_PP_RightAMAD_OilLeak"]
        ["ELEC_RH_FLAPS_DRIVE_WIRE_SEVERED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_RH_FLAPS_DRIVE_WIRE_SEVERED",
            ["mm"] = 0,
        }, -- end of ["ELEC_RH_FLAPS_DRIVE_WIRE_SEVERED"]
        ["starter_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "starter_fail",
            ["mm"] = 0,
        }, -- end of ["starter_fail"]
        ["MWMMC_FAILURE_1553B_SPJ"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_1553B_SPJ",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_1553B_SPJ"]
        ["CNI_FAILURE_TACAN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CNI_FAILURE_TACAN",
            ["mm"] = 0,
        }, -- end of ["CNI_FAILURE_TACAN"]
        ["RightEngine_Fire"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RightEngine_Fire",
            ["mm"] = 0,
        }, -- end of ["RightEngine_Fire"]
        ["Failure_Fuel_LeftBoostPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Fuel_LeftBoostPump",
            ["mm"] = 0,
        }, -- end of ["Failure_Fuel_LeftBoostPump"]
        ["UNCR_LH_STRUT_UP_LOCK_JAMMED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UNCR_LH_STRUT_UP_LOCK_JAMMED",
            ["mm"] = 0,
        }, -- end of ["UNCR_LH_STRUT_UP_LOCK_JAMMED"]
        ["LIGHTS_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LIGHTS_FAILURE",
            ["mm"] = 0,
        }, -- end of ["LIGHTS_FAILURE"]
        ["asc_p"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "asc_p",
            ["mm"] = 0,
        }, -- end of ["asc_p"]
        ["BOMBS_ARMING_BROKEN_SOLENOID_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_ARMING_BROKEN_SOLENOID_LEFT",
            ["mm"] = 0,
        }, -- end of ["BOMBS_ARMING_BROKEN_SOLENOID_LEFT"]
        ["Failure_PP_EngR_Main_FFCS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_PP_EngR_Main_FFCS",
            ["mm"] = 0,
        }, -- end of ["Failure_PP_EngR_Main_FFCS"]
        ["FUEL_NITRO_TANK_LEAK_STOPPED"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "FUEL_NITRO_TANK_LEAK_STOPPED",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_NITRO_TANK_LEAK_STOPPED"]
        ["FCS_FAILURE_EFCS_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_EFCS_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_EFCS_2"]
        ["Failure_Hyd_IsolatedHYD2BSystem_Leak"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Hyd_IsolatedHYD2BSystem_Leak",
            ["mm"] = 0,
        }, -- end of ["Failure_Hyd_IsolatedHYD2BSystem_Leak"]
        ["COMPASS_POINTER_PULLS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COMPASS_POINTER_PULLS",
            ["mm"] = 0,
        }, -- end of ["COMPASS_POINTER_PULLS"]
        ["GUN_RIGHT_OUT_OPEN_CIRCUIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_RIGHT_OUT_OPEN_CIRCUIT",
            ["mm"] = 0,
        }, -- end of ["GUN_RIGHT_OUT_OPEN_CIRCUIT"]
        ["ELEC_NAVLIGHT_WHITE_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_NAVLIGHT_WHITE_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_NAVLIGHT_WHITE_FAILURE"]
        ["AIRBRAKE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AIRBRAKE",
            ["mm"] = 0,
        }, -- end of ["AIRBRAKE"]
        ["Failure_Gear_WOW"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Gear_WOW",
            ["mm"] = 0,
        }, -- end of ["Failure_Gear_WOW"]
        ["TURNIND_INCORRECT_SENS_VAC_HIGH"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TURNIND_INCORRECT_SENS_VAC_HIGH",
            ["mm"] = 0,
        }, -- end of ["TURNIND_INCORRECT_SENS_VAC_HIGH"]
        ["IGNITION_NO_OUTPUT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "IGNITION_NO_OUTPUT",
            ["mm"] = 0,
        }, -- end of ["IGNITION_NO_OUTPUT"]
        ["GUN_LEFT_CENTER_MOUNT_LOOSE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_LEFT_CENTER_MOUNT_LOOSE",
            ["mm"] = 0,
        }, -- end of ["GUN_LEFT_CENTER_MOUNT_LOOSE"]
        ["chip_in_oil"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "chip_in_oil",
            ["mm"] = 0,
        }, -- end of ["chip_in_oil"]
        ["ELEC_BOOSTER_FUEL_PUMP_1_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_BOOSTER_FUEL_PUMP_1_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_BOOSTER_FUEL_PUMP_1_FAILURE"]
        ["COMPASS_ERRATIC_OPERATION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COMPASS_ERRATIC_OPERATION",
            ["mm"] = 0,
        }, -- end of ["COMPASS_ERRATIC_OPERATION"]
        ["TID_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TID_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["TID_FAILURE_TOTAL"]
        ["ELEVONSERVOUTERRIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEVONSERVOUTERRIGHT",
            ["mm"] = 0,
        }, -- end of ["ELEVONSERVOUTERRIGHT"]
        ["ELEC_UC_LAMP_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_UC_LAMP_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_UC_LAMP_FAILURE"]
        ["STATION_5_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STATION_5_FAILURE",
            ["mm"] = 0,
        }, -- end of ["STATION_5_FAILURE"]
        ["EMMC_FAILURE_SHARS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_SHARS",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_SHARS"]
        ["D2_LEFT_CYLINDER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "D2_LEFT_CYLINDER",
            ["mm"] = 0,
        }, -- end of ["D2_LEFT_CYLINDER"]
        ["Surge_LeftEngine"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Surge_LeftEngine",
            ["mm"] = 0,
        }, -- end of ["Surge_LeftEngine"]
        ["BOMBS_RUST_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_RUST_LEFT",
            ["mm"] = 0,
        }, -- end of ["BOMBS_RUST_LEFT"]
        ["STATION_7_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STATION_7_FAILURE",
            ["mm"] = 0,
        }, -- end of ["STATION_7_FAILURE"]
        ["ARN_83_ADF_DAMAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ARN_83_ADF_DAMAGE",
            ["mm"] = 0,
        }, -- end of ["ARN_83_ADF_DAMAGE"]
        ["csf_PitchDamper"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "csf_PitchDamper",
            ["mm"] = 0,
        }, -- end of ["csf_PitchDamper"]
        ["RIGHT_WING_TANK_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RIGHT_WING_TANK_LEAK",
            ["mm"] = 0,
        }, -- end of ["RIGHT_WING_TANK_LEAK"]
        ["FAILURE_HYDRAULICS_EMERGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_HYDRAULICS_EMERGE",
            ["mm"] = 0,
        }, -- end of ["FAILURE_HYDRAULICS_EMERGE"]
        ["ENG0_OILRADIATOR0_PIERCED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_OILRADIATOR0_PIERCED",
            ["mm"] = 0,
        }, -- end of ["ENG0_OILRADIATOR0_PIERCED"]
        ["DTC_FAILURE_DATA_DECIPHER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DTC_FAILURE_DATA_DECIPHER",
            ["mm"] = 0,
        }, -- end of ["DTC_FAILURE_DATA_DECIPHER"]
        ["ENG0_CARBURETTOR_OIL_FEED_CLOGGED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_CARBURETTOR_OIL_FEED_CLOGGED",
            ["mm"] = 0,
        }, -- end of ["ENG0_CARBURETTOR_OIL_FEED_CLOGGED"]
        ["Failure_Ctrl_Aileron"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Ctrl_Aileron",
            ["mm"] = 0,
        }, -- end of ["Failure_Ctrl_Aileron"]
        ["UNLOAD_VALVE_NOT_UNLOAD"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UNLOAD_VALVE_NOT_UNLOAD",
            ["mm"] = 0,
        }, -- end of ["UNLOAD_VALVE_NOT_UNLOAD"]
        ["EMMC_FAILURE_SCU_AC2AC36V"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_SCU_AC2AC36V",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_SCU_AC2AC36V"]
        ["UNLOAD_VALVE_NOT_LOAD"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UNLOAD_VALVE_NOT_LOAD",
            ["mm"] = 0,
        }, -- end of ["UNLOAD_VALVE_NOT_LOAD"]
        ["TURNIND_INCORRECT_SENS_VAC_LOW"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TURNIND_INCORRECT_SENS_VAC_LOW",
            ["mm"] = 0,
        }, -- end of ["TURNIND_INCORRECT_SENS_VAC_LOW"]
        ["ELEC_RH_CABIN_LIGHT_POOR_CONTACT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_RH_CABIN_LIGHT_POOR_CONTACT",
            ["mm"] = 0,
        }, -- end of ["ELEC_RH_CABIN_LIGHT_POOR_CONTACT"]
        ["RDR_FAILURE_DEGRATED_PERFORMANCE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RDR_FAILURE_DEGRATED_PERFORMANCE",
            ["mm"] = 0,
        }, -- end of ["RDR_FAILURE_DEGRATED_PERFORMANCE"]
        ["Failure_LeftEngine"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_LeftEngine",
            ["mm"] = 0,
        }, -- end of ["Failure_LeftEngine"]
        ["EMMC_FAILURE_TRU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_TRU",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_TRU"]
        ["OESP_FAILURE_CH_DISP_L"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OESP_FAILURE_CH_DISP_L",
            ["mm"] = 0,
        }, -- end of ["OESP_FAILURE_CH_DISP_L"]
        ["UHF_ARC_159_FAILURE_DISPLAY"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UHF_ARC_159_FAILURE_DISPLAY",
            ["mm"] = 0,
        }, -- end of ["UHF_ARC_159_FAILURE_DISPLAY"]
        ["ILS_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ILS_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["ILS_FAILURE_TOTAL"]
        ["INS_FAILURE_HEADING"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_FAILURE_HEADING",
            ["mm"] = 0,
        }, -- end of ["INS_FAILURE_HEADING"]
        ["Vibration_RightEngine"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "Vibration_RightEngine",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["Vibration_RightEngine"]
        ["as_damage_Depressurization"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "as_damage_Depressurization",
            ["mm"] = 0,
        }, -- end of ["as_damage_Depressurization"]
        ["ELEVONINNERLEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEVONINNERLEFT",
            ["mm"] = 0,
        }, -- end of ["ELEVONINNERLEFT"]
        ["TURNIND_POINTER_NOT_SET_ZERO"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TURNIND_POINTER_NOT_SET_ZERO",
            ["mm"] = 0,
        }, -- end of ["TURNIND_POINTER_NOT_SET_ZERO"]
        ["FAILURE_HYDRAULICS_2_PUMP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_HYDRAULICS_2_PUMP",
            ["mm"] = 0,
        }, -- end of ["FAILURE_HYDRAULICS_2_PUMP"]
        ["EMMC_FAILURE_BATTERY_FCS2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_BATTERY_FCS2",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_BATTERY_FCS2"]
        ["SWMMC_FAILURE_RMFCD"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_RMFCD",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_RMFCD"]
        ["RIGHT_MFCD_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RIGHT_MFCD_FAILURE",
            ["mm"] = 0,
        }, -- end of ["RIGHT_MFCD_FAILURE"]
        ["SMS_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SMS_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["SMS_FAILURE_TOTAL"]
        ["CARBAIR_BREAK_LEADS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CARBAIR_BREAK_LEADS",
            ["mm"] = 0,
        }, -- end of ["CARBAIR_BREAK_LEADS"]
        ["INST_PITOT_DAMAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_PITOT_DAMAGE",
            ["mm"] = 0,
        }, -- end of ["INST_PITOT_DAMAGE"]
        ["SWMMC_FAILURE_LMFCD"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_LMFCD",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_LMFCD"]
        ["UHF_RADIO_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UHF_RADIO_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["UHF_RADIO_FAILURE_TOTAL"]
        ["MWMMC_FAILURE_1553B_RMFCD"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_1553B_RMFCD",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_1553B_RMFCD"]
        ["FAILURE_SMS_PYLON_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_SMS_PYLON_1",
            ["mm"] = 0,
        }, -- end of ["FAILURE_SMS_PYLON_1"]
        ["APU_Fire"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "APU_Fire",
            ["mm"] = 0,
        }, -- end of ["APU_Fire"]
        ["ENG0_WATERRADIATOR1_PIERCED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_WATERRADIATOR1_PIERCED",
            ["mm"] = 0,
        }, -- end of ["ENG0_WATERRADIATOR1_PIERCED"]
        ["es_damage_InverterPT500C"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_InverterPT500C",
            ["mm"] = 0,
        }, -- end of ["es_damage_InverterPT500C"]
        ["LANDING_LIGHTS_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LANDING_LIGHTS_FAILURE",
            ["mm"] = 0,
        }, -- end of ["LANDING_LIGHTS_FAILURE"]
        ["GUN_LEFT_MG131_AMMUN_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_LEFT_MG131_AMMUN_FAULT",
            ["mm"] = 0,
        }, -- end of ["GUN_LEFT_MG131_AMMUN_FAULT"]
        ["RWR_FAILURE_RECEIVER_XX1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_RECEIVER_XX1",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_RECEIVER_XX1"]
        ["SWMMC_FAILURE_PS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_PS",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_PS"]
        ["GUN_LEFT_OUT_OPEN_CIRCUIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_LEFT_OUT_OPEN_CIRCUIT",
            ["mm"] = 0,
        }, -- end of ["GUN_LEFT_OUT_OPEN_CIRCUIT"]
        ["TRN_FAIL_AUX"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TRN_FAIL_AUX",
            ["mm"] = 0,
        }, -- end of ["TRN_FAIL_AUX"]
        ["FLEX_S_NO_POWER_SUPPLY"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FLEX_S_NO_POWER_SUPPLY",
            ["mm"] = 0,
        }, -- end of ["FLEX_S_NO_POWER_SUPPLY"]
        ["BAT_SOLENOID_WIRING"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BAT_SOLENOID_WIRING",
            ["mm"] = 0,
        }, -- end of ["BAT_SOLENOID_WIRING"]
        ["EMMC_FAILURE_FUEL_START_PUMP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_FUEL_START_PUMP",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_FUEL_START_PUMP"]
        ["FUEL_FORWARD_TANK_MINOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_FORWARD_TANK_MINOR_LEAK",
            ["mm"] = 0,
        }, -- end of ["FUEL_FORWARD_TANK_MINOR_LEAK"]
        ["INS_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["INS_FAILURE_TOTAL"]
        ["sensf_CADC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "sensf_CADC",
            ["mm"] = 0,
        }, -- end of ["sensf_CADC"]
        ["WEAP_GUN_02_DAMAGED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "WEAP_GUN_02_DAMAGED",
            ["mm"] = 0,
        }, -- end of ["WEAP_GUN_02_DAMAGED"]
        ["hydro"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hydro",
            ["mm"] = 0,
        }, -- end of ["hydro"]
        ["FUEL_TANK_02_MINOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_TANK_02_MINOR_LEAK",
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_02_MINOR_LEAK"]
        ["HUD_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HUD_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["HUD_FAILURE_TOTAL"]
        ["ELEC_BATTERY_OVERHEAT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_BATTERY_OVERHEAT",
            ["mm"] = 0,
        }, -- end of ["ELEC_BATTERY_OVERHEAT"]
        ["TACH_RESISTANCE_ADJ"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TACH_RESISTANCE_ADJ",
            ["mm"] = 0,
        }, -- end of ["TACH_RESISTANCE_ADJ"]
        ["Failure_ECS_OBOGS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_ECS_OBOGS",
            ["mm"] = 0,
        }, -- end of ["Failure_ECS_OBOGS"]
        ["EMMC_FAILURE_CANOPY_UNLOCK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_CANOPY_UNLOCK",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_CANOPY_UNLOCK"]
        ["fire_sys_fireko50"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fire_sys_fireko50",
            ["mm"] = 0,
        }, -- end of ["fire_sys_fireko50"]
        ["FUEL_TANK_01_EXPLODED"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_01_EXPLODED",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_01_EXPLODED"]
        ["AHRS_FAILURE_GYRO"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AHRS_FAILURE_GYRO",
            ["mm"] = 0,
        }, -- end of ["AHRS_FAILURE_GYRO"]
        ["es_damage_VU2"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "es_damage_VU2",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["es_damage_VU2"]
        ["ENG0_OIL_HOSE_1_BURST"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_OIL_HOSE_1_BURST",
            ["mm"] = 0,
        }, -- end of ["ENG0_OIL_HOSE_1_BURST"]
        ["GUN_LEFT_OUT_BARREL_WORN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_LEFT_OUT_BARREL_WORN",
            ["mm"] = 0,
        }, -- end of ["GUN_LEFT_OUT_BARREL_WORN"]
        ["TailReductor_LowOilPressure"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "TailReductor_LowOilPressure",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["TailReductor_LowOilPressure"]
        ["INS_FAILURE_DATA_INVALID"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_FAILURE_DATA_INVALID",
            ["mm"] = 0,
        }, -- end of ["INS_FAILURE_DATA_INVALID"]
        ["OXY_FAILURE_AUTO_100_O2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OXY_FAILURE_AUTO_100_O2",
            ["mm"] = 0,
        }, -- end of ["OXY_FAILURE_AUTO_100_O2"]
        ["EMMC_FAILURE_AC_GROUND"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_AC_GROUND",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_AC_GROUND"]
        ["pp_damage_MainStabFactor"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pp_damage_MainStabFactor",
            ["mm"] = 0,
        }, -- end of ["pp_damage_MainStabFactor"]
        ["hydro_right"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hydro_right",
            ["mm"] = 0,
        }, -- end of ["hydro_right"]
        ["FAILURE_HYDRAULICS_1_EXTERNAL_LEAKAGE_SEVERE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_HYDRAULICS_1_EXTERNAL_LEAKAGE_SEVERE",
            ["mm"] = 0,
        }, -- end of ["FAILURE_HYDRAULICS_1_EXTERNAL_LEAKAGE_SEVERE"]
        ["INST_TACH1_POOR_CONNECTION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_TACH1_POOR_CONNECTION",
            ["mm"] = 0,
        }, -- end of ["INST_TACH1_POOR_CONNECTION"]
        ["TRIMMER_DRIVE_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TRIMMER_DRIVE_FAULT",
            ["mm"] = 0,
        }, -- end of ["TRIMMER_DRIVE_FAULT"]
        ["SADL_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SADL_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["SADL_FAILURE_TOTAL"]
        ["EMMC_FAILURE_STATIC_INVERTER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_STATIC_INVERTER",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_STATIC_INVERTER"]
        ["Failure_Elec_RightGenerator"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Elec_RightGenerator",
            ["mm"] = 0,
        }, -- end of ["Failure_Elec_RightGenerator"]
        ["ELEVONOUTERLEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEVONOUTERLEFT",
            ["mm"] = 0,
        }, -- end of ["ELEVONOUTERLEFT"]
        ["SAR_1_95"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "SAR_1_95",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["SAR_1_95"]
        ["DOPPLER_UNIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DOPPLER_UNIT",
            ["mm"] = 0,
        }, -- end of ["DOPPLER_UNIT"]
        ["flaps_fault"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "flaps_fault",
            ["mm"] = 0,
        }, -- end of ["flaps_fault"]
        ["TAIL_GEAR_C_CABLE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TAIL_GEAR_C_CABLE",
            ["mm"] = 0,
        }, -- end of ["TAIL_GEAR_C_CABLE"]
        ["damper"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "damper",
            ["mm"] = 0,
        }, -- end of ["damper"]
        ["BCKGYRO"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BCKGYRO",
            ["mm"] = 0,
        }, -- end of ["BCKGYRO"]
        ["CANARDFLAPRIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CANARDFLAPRIGHT",
            ["mm"] = 0,
        }, -- end of ["CANARDFLAPRIGHT"]
        ["STARTER_RELAY_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STARTER_RELAY_FAULT",
            ["mm"] = 0,
        }, -- end of ["STARTER_RELAY_FAULT"]
        ["GMC_MAGN_COMP_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GMC_MAGN_COMP_FAILURE",
            ["mm"] = 0,
        }, -- end of ["GMC_MAGN_COMP_FAILURE"]
        ["fire_sys_fire_RE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fire_sys_fire_RE",
            ["mm"] = 0,
        }, -- end of ["fire_sys_fire_RE"]
        ["SWMMC_FAILURE_HUD"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_HUD",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_HUD"]
        ["ENG0_GOVERNOR_REGULATOR_MALFUNCTION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_GOVERNOR_REGULATOR_MALFUNCTION",
            ["mm"] = 0,
        }, -- end of ["ENG0_GOVERNOR_REGULATOR_MALFUNCTION"]
        ["ENG0_STARTER_CLUTCH_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_STARTER_CLUTCH_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ENG0_STARTER_CLUTCH_FAILURE"]
        ["ELEC_PITOT_HEAT_ELEMENT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_PITOT_HEAT_ELEMENT",
            ["mm"] = 0,
        }, -- end of ["ELEC_PITOT_HEAT_ELEMENT"]
        ["pp_damage_MainMaxNormFreq"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pp_damage_MainMaxNormFreq",
            ["mm"] = 0,
        }, -- end of ["pp_damage_MainMaxNormFreq"]
        ["ARN_83_TOTAL_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ARN_83_TOTAL_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ARN_83_TOTAL_FAILURE"]
        ["CTRL_LANDING_FLAPS_MECHANICAL_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_LANDING_FLAPS_MECHANICAL_FAILURE",
            ["mm"] = 0,
        }, -- end of ["CTRL_LANDING_FLAPS_MECHANICAL_FAILURE"]
        ["SWMMC_CSU_NO_RS422_COMM"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_CSU_NO_RS422_COMM",
            ["mm"] = 0,
        }, -- end of ["SWMMC_CSU_NO_RS422_COMM"]
        ["Failure_Hyd_HYD2A_Leak"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Hyd_HYD2A_Leak",
            ["mm"] = 0,
        }, -- end of ["Failure_Hyd_HYD2A_Leak"]
        ["CADC_WING_SWEEP_INDICATOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_WING_SWEEP_INDICATOR",
            ["mm"] = 0,
        }, -- end of ["CADC_WING_SWEEP_INDICATOR"]
        ["sight_lamps_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "sight_lamps_fail",
            ["mm"] = 0,
        }, -- end of ["sight_lamps_fail"]
        ["EMMC_FAILURE_AC_GENERATOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_AC_GENERATOR",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_AC_GENERATOR"]
        ["RADARASS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RADARASS",
            ["mm"] = 0,
        }, -- end of ["RADARASS"]
        ["fs_aft_LH_leakage"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fs_aft_LH_leakage",
            ["mm"] = 0,
        }, -- end of ["fs_aft_LH_leakage"]
        ["aileron_trim_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "aileron_trim_fail",
            ["mm"] = 0,
        }, -- end of ["aileron_trim_fail"]
        ["CADC_WING_SWEEP_COMMAND_CHANNEL_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_WING_SWEEP_COMMAND_CHANNEL_1",
            ["mm"] = 0,
        }, -- end of ["CADC_WING_SWEEP_COMMAND_CHANNEL_1"]
        ["FCS_FAILURE_ROLL_LVDT_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_ROLL_LVDT_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_ROLL_LVDT_1"]
        ["FUEL_TANK_00_FIRE"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_00_FIRE",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_00_FIRE"]
        ["UNCR_RH_STRUT_UP_LOCK_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UNCR_RH_STRUT_UP_LOCK_FAILURE",
            ["mm"] = 0,
        }, -- end of ["UNCR_RH_STRUT_UP_LOCK_FAILURE"]
        ["CADC_FAILURE_DYNAMIC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_FAILURE_DYNAMIC",
            ["mm"] = 0,
        }, -- end of ["CADC_FAILURE_DYNAMIC"]
        ["Failure_Fuel_QuantityGaging"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Fuel_QuantityGaging",
            ["mm"] = 0,
        }, -- end of ["Failure_Fuel_QuantityGaging"]
        ["MWMMC_FAILURE_1553B_CMFCD"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_1553B_CMFCD",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_1553B_CMFCD"]
        ["fuel_sys_left_transfer_pump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fuel_sys_left_transfer_pump",
            ["mm"] = 0,
        }, -- end of ["fuel_sys_left_transfer_pump"]
        ["rudder_trim_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "rudder_trim_fail",
            ["mm"] = 0,
        }, -- end of ["rudder_trim_fail"]
        ["HYD_Transf"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYD_Transf",
            ["mm"] = 0,
        }, -- end of ["HYD_Transf"]
        ["FCS_FAILURE_L_ELEVATOR_ELEC_C"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_L_ELEVATOR_ELEC_C",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_L_ELEVATOR_ELEC_C"]
        ["es_damage_StarterGenerator"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_StarterGenerator",
            ["mm"] = 0,
        }, -- end of ["es_damage_StarterGenerator"]
        ["es_damage_Battery"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_Battery",
            ["mm"] = 0,
        }, -- end of ["es_damage_Battery"]
        ["ppf_FireLeft"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ppf_FireLeft",
            ["mm"] = 0,
        }, -- end of ["ppf_FireLeft"]
        ["EMMC_FAILURE_DC_GENERATOR_VOLTAGE_HIGH"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_DC_GENERATOR_VOLTAGE_HIGH",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_DC_GENERATOR_VOLTAGE_HIGH"]
        ["VHF_AM_RADIO_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VHF_AM_RADIO_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["VHF_AM_RADIO_FAILURE_TOTAL"]
        ["VHF_SQUELCH_RELAY"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VHF_SQUELCH_RELAY",
            ["mm"] = 0,
        }, -- end of ["VHF_SQUELCH_RELAY"]
        ["RPMFault_LeftEngine"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "RPMFault_LeftEngine",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["RPMFault_LeftEngine"]
        ["F2_TOP_CYLINDER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "F2_TOP_CYLINDER",
            ["mm"] = 0,
        }, -- end of ["F2_TOP_CYLINDER"]
        ["FUEL_BOOSTER_FUEL_PUMP_DEGRADED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_BOOSTER_FUEL_PUMP_DEGRADED",
            ["mm"] = 0,
        }, -- end of ["FUEL_BOOSTER_FUEL_PUMP_DEGRADED"]
        ["INST_SPEEDOMETER_DEPRESSURIZATION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_SPEEDOMETER_DEPRESSURIZATION",
            ["mm"] = 0,
        }, -- end of ["INST_SPEEDOMETER_DEPRESSURIZATION"]
        ["Failure_PP_EngL_Main_FFCS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_PP_EngL_Main_FFCS",
            ["mm"] = 0,
        }, -- end of ["Failure_PP_EngL_Main_FFCS"]
        ["K14_NO_POWER_SUPPLY"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "K14_NO_POWER_SUPPLY",
            ["mm"] = 0,
        }, -- end of ["K14_NO_POWER_SUPPLY"]
        ["INS_FAILURE_ATTITUDE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_FAILURE_ATTITUDE",
            ["mm"] = 0,
        }, -- end of ["INS_FAILURE_ATTITUDE"]
        ["INST_TACH0_POOR_CONNECTION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_TACH0_POOR_CONNECTION",
            ["mm"] = 0,
        }, -- end of ["INST_TACH0_POOR_CONNECTION"]
        ["fs_damage_engine_pump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fs_damage_engine_pump",
            ["mm"] = 0,
        }, -- end of ["fs_damage_engine_pump"]
        ["MANIFOLD_LINE_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MANIFOLD_LINE_LEAK",
            ["mm"] = 0,
        }, -- end of ["MANIFOLD_LINE_LEAK"]
        ["INS_FAILURE_ACC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_FAILURE_ACC",
            ["mm"] = 0,
        }, -- end of ["INS_FAILURE_ACC"]
        ["IFFCC_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "IFFCC_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["IFFCC_FAILURE_TOTAL"]
        ["RWR_FAILURE_QUAD225"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_QUAD225",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_QUAD225"]
        ["FCS_FAILURE_ROLL_ELEC_SERVO_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_ROLL_ELEC_SERVO_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_ROLL_ELEC_SERVO_2"]
        ["RDR_FAILURE_PREESURIZATION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RDR_FAILURE_PREESURIZATION",
            ["mm"] = 0,
        }, -- end of ["RDR_FAILURE_PREESURIZATION"]
        ["ENGINE_FAILURE_APD88_STARTER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENGINE_FAILURE_APD88_STARTER",
            ["mm"] = 0,
        }, -- end of ["ENGINE_FAILURE_APD88_STARTER"]
        ["AN_ALR69V_FAILURE_SENSOR_NOSE_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AN_ALR69V_FAILURE_SENSOR_NOSE_LEFT",
            ["mm"] = 0,
        }, -- end of ["AN_ALR69V_FAILURE_SENSOR_NOSE_LEFT"]
        ["Failure_PP_RightPTS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_PP_RightPTS",
            ["mm"] = 0,
        }, -- end of ["Failure_PP_RightPTS"]
        ["GUN_RIGHT_MG131_OPEN_CIRCUIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_RIGHT_MG131_OPEN_CIRCUIT",
            ["mm"] = 0,
        }, -- end of ["GUN_RIGHT_MG131_OPEN_CIRCUIT"]
        ["RUDDERSERV"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RUDDERSERV",
            ["mm"] = 0,
        }, -- end of ["RUDDERSERV"]
        ["TACAN_FAILURE_TRANSMITTER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TACAN_FAILURE_TRANSMITTER",
            ["mm"] = 0,
        }, -- end of ["TACAN_FAILURE_TRANSMITTER"]
        ["GUN_RIGHT_MG151_BARREL_WORN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_RIGHT_MG151_BARREL_WORN",
            ["mm"] = 0,
        }, -- end of ["GUN_RIGHT_MG151_BARREL_WORN"]
        ["GUN_LEFT_IN_BARREL_WORN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_LEFT_IN_BARREL_WORN",
            ["mm"] = 0,
        }, -- end of ["GUN_LEFT_IN_BARREL_WORN"]
        ["CADC_PRESSURE_SENSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_PRESSURE_SENSOR",
            ["mm"] = 0,
        }, -- end of ["CADC_PRESSURE_SENSOR"]
        ["CTRL_TAIL_ROTOR_CONTROL_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_TAIL_ROTOR_CONTROL_FAILURE",
            ["mm"] = 0,
        }, -- end of ["CTRL_TAIL_ROTOR_CONTROL_FAILURE"]
        ["W_S_L"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "W_S_L",
            ["mm"] = 0,
        }, -- end of ["W_S_L"]
        ["FCS_FAILURE_Q_SENSOR_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_Q_SENSOR_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_Q_SENSOR_2"]
        ["fsf_LeftBoostPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fsf_LeftBoostPump",
            ["mm"] = 0,
        }, -- end of ["fsf_LeftBoostPump"]
        ["OIL_DILUTION_SOLENOID"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OIL_DILUTION_SOLENOID",
            ["mm"] = 0,
        }, -- end of ["OIL_DILUTION_SOLENOID"]
        ["OXYN_RIGHT_CONTAINER_PERFORATED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OXYN_RIGHT_CONTAINER_PERFORATED",
            ["mm"] = 0,
        }, -- end of ["OXYN_RIGHT_CONTAINER_PERFORATED"]
        ["FCS_FAILURE_L_ELEVATOR_HYD_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_L_ELEVATOR_HYD_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_L_ELEVATOR_HYD_1"]
        ["AOASENSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AOASENSOR",
            ["mm"] = 0,
        }, -- end of ["AOASENSOR"]
        ["hydro_main_irreversible_valve"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hydro_main_irreversible_valve",
            ["mm"] = 0,
        }, -- end of ["hydro_main_irreversible_valve"]
        ["fuel_sys_feed_tank_pump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fuel_sys_feed_tank_pump",
            ["mm"] = 0,
        }, -- end of ["fuel_sys_feed_tank_pump"]
        ["HYDR2ACC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYDR2ACC",
            ["mm"] = 0,
        }, -- end of ["HYDR2ACC"]
        ["RDR_FAILURE_RECEIVER_DEGRATION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RDR_FAILURE_RECEIVER_DEGRATION",
            ["mm"] = 0,
        }, -- end of ["RDR_FAILURE_RECEIVER_DEGRATION"]
        ["ef_shutdown"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ef_shutdown",
            ["mm"] = 0,
        }, -- end of ["ef_shutdown"]
        ["hsf_ControlHydraulic"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hsf_ControlHydraulic",
            ["mm"] = 0,
        }, -- end of ["hsf_ControlHydraulic"]
        ["JADRO_1A_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "JADRO_1A_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["JADRO_1A_FAILURE_TOTAL"]
        ["KPP_FAILURE_PARTIAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "KPP_FAILURE_PARTIAL",
            ["mm"] = 0,
        }, -- end of ["KPP_FAILURE_PARTIAL"]
        ["OIL_RADIATOR_SENSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OIL_RADIATOR_SENSOR",
            ["mm"] = 0,
        }, -- end of ["OIL_RADIATOR_SENSOR"]
        ["SWMMC_FAILURE_DVR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_DVR",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_DVR"]
        ["hs_damage_GainAccumulator"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hs_damage_GainAccumulator",
            ["mm"] = 0,
        }, -- end of ["hs_damage_GainAccumulator"]
        ["FWD_TANK_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FWD_TANK_LEAK",
            ["mm"] = 0,
        }, -- end of ["FWD_TANK_LEAK"]
        ["radioalt_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "radioalt_fail",
            ["mm"] = 0,
        }, -- end of ["radioalt_fail"]
        ["INST_VARIOMETER_CLOGGED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_VARIOMETER_CLOGGED",
            ["mm"] = 0,
        }, -- end of ["INST_VARIOMETER_CLOGGED"]
        ["GUN_LEFT_IN_MOUNT_LOOSE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_LEFT_IN_MOUNT_LOOSE",
            ["mm"] = 0,
        }, -- end of ["GUN_LEFT_IN_MOUNT_LOOSE"]
        ["Failure_Gear_NWS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Gear_NWS",
            ["mm"] = 0,
        }, -- end of ["Failure_Gear_NWS"]
        ["rws"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "rws",
            ["mm"] = 0,
        }, -- end of ["rws"]
        ["HUDDISPLAY"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HUDDISPLAY",
            ["mm"] = 0,
        }, -- end of ["HUDDISPLAY"]
        ["l_gen"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "l_gen",
            ["mm"] = 0,
        }, -- end of ["l_gen"]
        ["OIL_RADIATOR_MOTOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OIL_RADIATOR_MOTOR",
            ["mm"] = 0,
        }, -- end of ["OIL_RADIATOR_MOTOR"]
        ["hs_damage_GainAutoUnload"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hs_damage_GainAutoUnload",
            ["mm"] = 0,
        }, -- end of ["hs_damage_GainAutoUnload"]
        ["FUSELAGE_TANK_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUSELAGE_TANK_LEAK",
            ["mm"] = 0,
        }, -- end of ["FUSELAGE_TANK_LEAK"]
        ["MWMMC_FAILURE_IOC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_IOC",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_IOC"]
        ["INS_WIND_INVALID"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_WIND_INVALID",
            ["mm"] = 0,
        }, -- end of ["INS_WIND_INVALID"]
        ["HORIZON_BAR_NOT_SETTLE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HORIZON_BAR_NOT_SETTLE",
            ["mm"] = 0,
        }, -- end of ["HORIZON_BAR_NOT_SETTLE"]
        ["r_gen"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "r_gen",
            ["mm"] = 0,
        }, -- end of ["r_gen"]
        ["OIL_DILUTION_WIRE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OIL_DILUTION_WIRE",
            ["mm"] = 0,
        }, -- end of ["OIL_DILUTION_WIRE"]
        ["GUN_RIGHT_MG151_OPEN_CIRCUIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_RIGHT_MG151_OPEN_CIRCUIT",
            ["mm"] = 0,
        }, -- end of ["GUN_RIGHT_MG151_OPEN_CIRCUIT"]
        ["FCS_FAILURE_YAW_ELEC_SERVO_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_YAW_ELEC_SERVO_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_YAW_ELEC_SERVO_2"]
        ["ELEC_SIGNAL_LIGHTS_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_SIGNAL_LIGHTS_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_SIGNAL_LIGHTS_FAILURE"]
        ["OXYGEN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OXYGEN",
            ["mm"] = 0,
        }, -- end of ["OXYGEN"]
        ["FAILURE_HYDRAULICS_1_PUMP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_HYDRAULICS_1_PUMP",
            ["mm"] = 0,
        }, -- end of ["FAILURE_HYDRAULICS_1_PUMP"]
        ["R_GEAR_DLK_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_GEAR_DLK_FAULT",
            ["mm"] = 0,
        }, -- end of ["R_GEAR_DLK_FAULT"]
        ["fuel_sys_300left"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "fuel_sys_300left",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["fuel_sys_300left"]
        ["FUEL_NITRO_TANK_MINOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "FUEL_NITRO_TANK_MINOR_LEAK",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_NITRO_TANK_MINOR_LEAK"]
        ["FUEL_DROPTANK_MINOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_DROPTANK_MINOR_LEAK",
            ["mm"] = 0,
        }, -- end of ["FUEL_DROPTANK_MINOR_LEAK"]
        ["ELEC_RH_GEAR_DRIVE_WIRE_SEVERED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_RH_GEAR_DRIVE_WIRE_SEVERED",
            ["mm"] = 0,
        }, -- end of ["ELEC_RH_GEAR_DRIVE_WIRE_SEVERED"]
        ["ppf_LeftGearbox"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ppf_LeftGearbox",
            ["mm"] = 0,
        }, -- end of ["ppf_LeftGearbox"]
        ["ELEC_SUPERCHARGER_SOLENOID_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_SUPERCHARGER_SOLENOID_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_SUPERCHARGER_SOLENOID_FAILURE"]
        ["INST_TACH0_RESISTANCE_MISMATCH"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_TACH0_RESISTANCE_MISMATCH",
            ["mm"] = 0,
        }, -- end of ["INST_TACH0_RESISTANCE_MISMATCH"]
        ["IGNITION_TERM_CONNECT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "IGNITION_TERM_CONNECT",
            ["mm"] = 0,
        }, -- end of ["IGNITION_TERM_CONNECT"]
        ["ELEVONSERVOUTERLEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEVONSERVOUTERLEFT",
            ["mm"] = 0,
        }, -- end of ["ELEVONSERVOUTERLEFT"]
        ["NGear_ret_fault"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "NGear_ret_fault",
            ["mm"] = 0,
        }, -- end of ["NGear_ret_fault"]
        ["FUELTANK3R"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUELTANK3R",
            ["mm"] = 0,
        }, -- end of ["FUELTANK3R"]
        ["FAULTY_ROCKET_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAULTY_ROCKET_LEFT",
            ["mm"] = 0,
        }, -- end of ["FAULTY_ROCKET_LEFT"]
        ["aileron_loss"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "aileron_loss",
            ["mm"] = 0,
        }, -- end of ["aileron_loss"]
        ["FCS_FAILURE_ROLL_RATE_GYRO_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_ROLL_RATE_GYRO_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_ROLL_RATE_GYRO_1"]
        ["BOMBS_DAMAGE_LINKAGE_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_DAMAGE_LINKAGE_LEFT",
            ["mm"] = 0,
        }, -- end of ["BOMBS_DAMAGE_LINKAGE_LEFT"]
        ["Failure_PP_LeftAMAD_OilLeak"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_PP_LeftAMAD_OilLeak",
            ["mm"] = 0,
        }, -- end of ["Failure_PP_LeftAMAD_OilLeak"]
        ["Failure_PP_EngR_Nozzle_CS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_PP_EngR_Nozzle_CS",
            ["mm"] = 0,
        }, -- end of ["Failure_PP_EngR_Nozzle_CS"]
        ["hydro_main"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hydro_main",
            ["mm"] = 0,
        }, -- end of ["hydro_main"]
        ["RGear_ret_fault"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RGear_ret_fault",
            ["mm"] = 0,
        }, -- end of ["RGear_ret_fault"]
        ["LeftEngine_LowOilPressure"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LeftEngine_LowOilPressure",
            ["mm"] = 0,
        }, -- end of ["LeftEngine_LowOilPressure"]
        ["FCS_FAILURE_L_ELEVATOR_ELEC_B"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_L_ELEVATOR_ELEC_B",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_L_ELEVATOR_ELEC_B"]
        ["RADAR_ALT_TOTAL_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RADAR_ALT_TOTAL_FAILURE",
            ["mm"] = 0,
        }, -- end of ["RADAR_ALT_TOTAL_FAILURE"]
        ["INST_VARIOMETER_DEPRESSURIZATION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_VARIOMETER_DEPRESSURIZATION",
            ["mm"] = 0,
        }, -- end of ["INST_VARIOMETER_DEPRESSURIZATION"]
        ["RDR_FAILURE_SERVO_OVERHEAT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RDR_FAILURE_SERVO_OVERHEAT",
            ["mm"] = 0,
        }, -- end of ["RDR_FAILURE_SERVO_OVERHEAT"]
        ["FUEL_TANK_01_MAJOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_01_MAJOR_LEAK",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_01_MAJOR_LEAK"]
        ["MWMMC_FAILURE_1553B_FCS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_1553B_FCS",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_1553B_FCS"]
        ["CTRL_LH_SLAT_JAMMED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_LH_SLAT_JAMMED",
            ["mm"] = 0,
        }, -- end of ["CTRL_LH_SLAT_JAMMED"]
        ["ELEVONSERVINNERLEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEVONSERVINNERLEFT",
            ["mm"] = 0,
        }, -- end of ["ELEVONSERVINNERLEFT"]
        ["TAPEREC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TAPEREC",
            ["mm"] = 0,
        }, -- end of ["TAPEREC"]
        ["ILS_FAILURE_ANT_LOCALIZER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ILS_FAILURE_ANT_LOCALIZER",
            ["mm"] = 0,
        }, -- end of ["ILS_FAILURE_ANT_LOCALIZER"]
        ["csf_AutoFlap"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "csf_AutoFlap",
            ["mm"] = 0,
        }, -- end of ["csf_AutoFlap"]
        ["TVDISPLAY"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TVDISPLAY",
            ["mm"] = 0,
        }, -- end of ["TVDISPLAY"]
        ["RDR_FAILURE_PEDESTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RDR_FAILURE_PEDESTAL",
            ["mm"] = 0,
        }, -- end of ["RDR_FAILURE_PEDESTAL"]
        ["RDR_FAILURE_SERVOLOOP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RDR_FAILURE_SERVOLOOP",
            ["mm"] = 0,
        }, -- end of ["RDR_FAILURE_SERVOLOOP"]
        ["UNCR_RH_STRUT_UP_LOCK_JAMMED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UNCR_RH_STRUT_UP_LOCK_JAMMED",
            ["mm"] = 0,
        }, -- end of ["UNCR_RH_STRUT_UP_LOCK_JAMMED"]
        ["ELEC_EMERGENCY_GENERATOR_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_EMERGENCY_GENERATOR_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_EMERGENCY_GENERATOR_FAILURE"]
        ["ICS_FAILURE_AMPLIFIER_RIO_BU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ICS_FAILURE_AMPLIFIER_RIO_BU",
            ["mm"] = 0,
        }, -- end of ["ICS_FAILURE_AMPLIFIER_RIO_BU"]
        ["STARTER_SOL_SHORT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STARTER_SOL_SHORT",
            ["mm"] = 0,
        }, -- end of ["STARTER_SOL_SHORT"]
        ["FCS_FAILURE_NZ_SENSOR_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_NZ_SENSOR_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_NZ_SENSOR_2"]
        ["FCS_FAILURE_COMP_3"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_COMP_3",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_COMP_3"]
        ["FUELTANK5L"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUELTANK5L",
            ["mm"] = 0,
        }, -- end of ["FUELTANK5L"]
        ["FCS_FAILURE_YAW_RATE_GYRO_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_YAW_RATE_GYRO_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_YAW_RATE_GYRO_2"]
        ["OESP_FAILURE_MAWS_R"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OESP_FAILURE_MAWS_R",
            ["mm"] = 0,
        }, -- end of ["OESP_FAILURE_MAWS_R"]
        ["RWR_FAILURE_COMPUTER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_COMPUTER",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_COMPUTER"]
        ["esf_LeftRectifier"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "esf_LeftRectifier",
            ["mm"] = 0,
        }, -- end of ["esf_LeftRectifier"]
        ["ROOF_AIRSPEED_INDICATOR_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ROOF_AIRSPEED_INDICATOR_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ROOF_AIRSPEED_INDICATOR_FAILURE"]
        ["AAR_47_FAILURE_SENSOR_BOTTOM"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AAR_47_FAILURE_SENSOR_BOTTOM",
            ["mm"] = 0,
        }, -- end of ["AAR_47_FAILURE_SENSOR_BOTTOM"]
        ["BOMBS_ARMING_BROKEN_WIRING_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_ARMING_BROKEN_WIRING_LEFT",
            ["mm"] = 0,
        }, -- end of ["BOMBS_ARMING_BROKEN_WIRING_LEFT"]
        ["MAINPITOT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MAINPITOT",
            ["mm"] = 0,
        }, -- end of ["MAINPITOT"]
        ["FCS_FAILURE_R_ELEVATOR_ELEC_D"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_R_ELEVATOR_ELEC_D",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_R_ELEVATOR_ELEC_D"]
        ["AAR_47_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AAR_47_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["AAR_47_FAILURE_TOTAL"]
        ["CTRL_AILERON_ROD_MINOR_DAMAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_AILERON_ROD_MINOR_DAMAGE",
            ["mm"] = 0,
        }, -- end of ["CTRL_AILERON_ROD_MINOR_DAMAGE"]
        ["FCS_FAILURE_COMP_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_COMP_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_COMP_1"]
        ["COOLANT_RADIATOR_WIRING"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COOLANT_RADIATOR_WIRING",
            ["mm"] = 0,
        }, -- end of ["COOLANT_RADIATOR_WIRING"]
        ["FUEL_MW50_TANK_DRAIN_VALVE_SEVERED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_MW50_TANK_DRAIN_VALVE_SEVERED",
            ["mm"] = 0,
        }, -- end of ["FUEL_MW50_TANK_DRAIN_VALVE_SEVERED"]
        ["AIRSPEED_INDICATOR_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AIRSPEED_INDICATOR_FAILURE",
            ["mm"] = 0,
        }, -- end of ["AIRSPEED_INDICATOR_FAILURE"]
        ["ELEC_RH_JUNCTION_BOX_DESTROYED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_RH_JUNCTION_BOX_DESTROYED",
            ["mm"] = 0,
        }, -- end of ["ELEC_RH_JUNCTION_BOX_DESTROYED"]
        ["abris_software"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "abris_software",
            ["mm"] = 0,
        }, -- end of ["abris_software"]
        ["ef_surge"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ef_surge",
            ["mm"] = 0,
        }, -- end of ["ef_surge"]
        ["ROCKETS_INTERVALOMETER_WIRING"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ROCKETS_INTERVALOMETER_WIRING",
            ["mm"] = 0,
        }, -- end of ["ROCKETS_INTERVALOMETER_WIRING"]
        ["pitot_blocked"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pitot_blocked",
            ["mm"] = 0,
        }, -- end of ["pitot_blocked"]
        ["CANARDFLAPLEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CANARDFLAPLEFT",
            ["mm"] = 0,
        }, -- end of ["CANARDFLAPLEFT"]
        ["fs_forward_LH_leakage"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fs_forward_LH_leakage",
            ["mm"] = 0,
        }, -- end of ["fs_forward_LH_leakage"]
        ["GYROS_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GYROS_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["GYROS_FAILURE_TOTAL"]
        ["RB05ANT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RB05ANT",
            ["mm"] = 0,
        }, -- end of ["RB05ANT"]
        ["GUN_RIGHT_CENTER_BARREL_WORN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_RIGHT_CENTER_BARREL_WORN",
            ["mm"] = 0,
        }, -- end of ["GUN_RIGHT_CENTER_BARREL_WORN"]
        ["MWMMC_FAILURE_1553B_OESP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_1553B_OESP",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_1553B_OESP"]
        ["CTRL_ELEVATOR_TRIM_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_ELEVATOR_TRIM_FAILURE",
            ["mm"] = 0,
        }, -- end of ["CTRL_ELEVATOR_TRIM_FAILURE"]
        ["FUELTANK4R"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUELTANK4R",
            ["mm"] = 0,
        }, -- end of ["FUELTANK4R"]
        ["static_blocked"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "static_blocked",
            ["mm"] = 0,
        }, -- end of ["static_blocked"]
        ["RADAR_ALTIMETR_RIGHT_ANT_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RADAR_ALTIMETR_RIGHT_ANT_FAILURE",
            ["mm"] = 0,
        }, -- end of ["RADAR_ALTIMETR_RIGHT_ANT_FAILURE"]
        ["CTRL_ELEVATOR_ROD_MINOR_DAMAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_ELEVATOR_ROD_MINOR_DAMAGE",
            ["mm"] = 0,
        }, -- end of ["CTRL_ELEVATOR_ROD_MINOR_DAMAGE"]
        ["FAILURE_HYDRAULICS_1_INTERNAL_LEAKAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_HYDRAULICS_1_INTERNAL_LEAKAGE",
            ["mm"] = 0,
        }, -- end of ["FAILURE_HYDRAULICS_1_INTERNAL_LEAKAGE"]
        ["MWMMC_FAILURE_1553B_HUD"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_1553B_HUD",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_1553B_HUD"]
        ["HORIZON_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HORIZON_FAULT",
            ["mm"] = 0,
        }, -- end of ["HORIZON_FAULT"]
        ["fire_sys_fire_LE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fire_sys_fire_LE",
            ["mm"] = 0,
        }, -- end of ["fire_sys_fire_LE"]
        ["fuel_sys_swapping_pumps"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "fuel_sys_swapping_pumps",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["fuel_sys_swapping_pumps"]
        ["PNEM_SUPERCHARGER_JACK_JAMMED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PNEM_SUPERCHARGER_JACK_JAMMED",
            ["mm"] = 0,
        }, -- end of ["PNEM_SUPERCHARGER_JACK_JAMMED"]
        ["HYD_PUMP_3_FAIL_100"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYD_PUMP_3_FAIL_100",
            ["mm"] = 0,
        }, -- end of ["HYD_PUMP_3_FAIL_100"]
        ["FCS_FAILURE_ROLL_RATE_GYRO_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_ROLL_RATE_GYRO_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_ROLL_RATE_GYRO_2"]
        ["ELEC_FUEL_PUMP_P2_COIL_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_FUEL_PUMP_P2_COIL_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_FUEL_PUMP_P2_COIL_FAILURE"]
        ["CANARDSERVORIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CANARDSERVORIGHT",
            ["mm"] = 0,
        }, -- end of ["CANARDSERVORIGHT"]
        ["DVMS_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DVMS_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["DVMS_FAILURE_TOTAL"]
        ["VHF_FM_RADIO_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VHF_FM_RADIO_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["VHF_FM_RADIO_FAILURE_TOTAL"]
        ["BOMBS_DAMAGE_ELINKAGE_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_DAMAGE_ELINKAGE_RIGHT",
            ["mm"] = 0,
        }, -- end of ["BOMBS_DAMAGE_ELINKAGE_RIGHT"]
        ["FUELTANK1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUELTANK1",
            ["mm"] = 0,
        }, -- end of ["FUELTANK1"]
        ["EMMC_FAILURE_BATTERY_DC1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_BATTERY_DC1",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_BATTERY_DC1"]
        ["ecf"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["mm"] = 0,
        }, -- end of ["ecf"]
        ["ELEC_GOVERNOR_BOX_DAMAGED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_GOVERNOR_BOX_DAMAGED",
            ["mm"] = 0,
        }, -- end of ["ELEC_GOVERNOR_BOX_DAMAGED"]
        ["DTC_FAILURE_CARD_BROKEN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DTC_FAILURE_CARD_BROKEN",
            ["mm"] = 0,
        }, -- end of ["DTC_FAILURE_CARD_BROKEN"]
        ["REVERSER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "REVERSER",
            ["mm"] = 0,
        }, -- end of ["REVERSER"]
        ["OXY_FAILURE_HIGH_PRESS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OXY_FAILURE_HIGH_PRESS",
            ["mm"] = 0,
        }, -- end of ["OXY_FAILURE_HIGH_PRESS"]
        ["RDR_FAILURE_TRANSMITTER_DEGRATION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RDR_FAILURE_TRANSMITTER_DEGRATION",
            ["mm"] = 0,
        }, -- end of ["RDR_FAILURE_TRANSMITTER_DEGRATION"]
        ["TransitionalReductor_ShaveInOil"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TransitionalReductor_ShaveInOil",
            ["mm"] = 0,
        }, -- end of ["TransitionalReductor_ShaveInOil"]
        ["TURBINE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TURBINE",
            ["mm"] = 0,
        }, -- end of ["TURBINE"]
        ["AUTOPILOT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AUTOPILOT",
            ["mm"] = 0,
        }, -- end of ["AUTOPILOT"]
        ["RIGHT_TANK_PUMP_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RIGHT_TANK_PUMP_FAULT",
            ["mm"] = 0,
        }, -- end of ["RIGHT_TANK_PUMP_FAULT"]
        ["UHF_ARC_159_FAILURE_REMOTE_DISPLAY"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UHF_ARC_159_FAILURE_REMOTE_DISPLAY",
            ["mm"] = 0,
        }, -- end of ["UHF_ARC_159_FAILURE_REMOTE_DISPLAY"]
        ["Failure_Ctrl_FCS_Ch1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Ctrl_FCS_Ch1",
            ["mm"] = 0,
        }, -- end of ["Failure_Ctrl_FCS_Ch1"]
        ["RDR_FAILURE_PROCESSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RDR_FAILURE_PROCESSOR",
            ["mm"] = 0,
        }, -- end of ["RDR_FAILURE_PROCESSOR"]
        ["OXYN_LEFT_CONTAINER_PERFORATED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OXYN_LEFT_CONTAINER_PERFORATED",
            ["mm"] = 0,
        }, -- end of ["OXYN_LEFT_CONTAINER_PERFORATED"]
        ["RDR_FAILURE_PROCESSOR_DEGRATION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RDR_FAILURE_PROCESSOR_DEGRATION",
            ["mm"] = 0,
        }, -- end of ["RDR_FAILURE_PROCESSOR_DEGRATION"]
        ["ELEC_SIGNAL_LIGHTS_MALFUNCTION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_SIGNAL_LIGHTS_MALFUNCTION",
            ["mm"] = 0,
        }, -- end of ["ELEC_SIGNAL_LIGHTS_MALFUNCTION"]
        ["ef_rt12"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ef_rt12",
            ["mm"] = 0,
        }, -- end of ["ef_rt12"]
        ["es_damage_DMR"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "es_damage_DMR",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["es_damage_DMR"]
        ["CTRL_LANDING_FLAPS_LH_MECHANICAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_LANDING_FLAPS_LH_MECHANICAL",
            ["mm"] = 0,
        }, -- end of ["CTRL_LANDING_FLAPS_LH_MECHANICAL"]
        ["RDR_FAILURE_RECEIVER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RDR_FAILURE_RECEIVER",
            ["mm"] = 0,
        }, -- end of ["RDR_FAILURE_RECEIVER"]
        ["EMMC_FAILURE_COCKPIT_PRESSURE_LOW"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_COCKPIT_PRESSURE_LOW",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_COCKPIT_PRESSURE_LOW"]
        ["EMMC_FAILURE_BAU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_BAU",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_BAU"]
        ["MAGNETO_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MAGNETO_1",
            ["mm"] = 0,
        }, -- end of ["MAGNETO_1"]
        ["COOLANT_RADIATOR_SENSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COOLANT_RADIATOR_SENSOR",
            ["mm"] = 0,
        }, -- end of ["COOLANT_RADIATOR_SENSOR"]
        ["FCS_FAILURE_WOW_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_WOW_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_WOW_2"]
        ["autopilot"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "autopilot",
            ["mm"] = 0,
        }, -- end of ["autopilot"]
        ["EMMC_FAILURE_DADS_RPTU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_DADS_RPTU",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_DADS_RPTU"]
        ["BOMBS_TRAIN_DEFECTIVE_SWITCH"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_TRAIN_DEFECTIVE_SWITCH",
            ["mm"] = 0,
        }, -- end of ["BOMBS_TRAIN_DEFECTIVE_SWITCH"]
        ["OIL_SYSTEM_FAIL_100"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OIL_SYSTEM_FAIL_100",
            ["mm"] = 0,
        }, -- end of ["OIL_SYSTEM_FAIL_100"]
        ["fs_aft_RH_leakage"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fs_aft_RH_leakage",
            ["mm"] = 0,
        }, -- end of ["fs_aft_RH_leakage"]
        ["GUN_LEFT_CENTER_OPEN_CIRCUIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_LEFT_CENTER_OPEN_CIRCUIT",
            ["mm"] = 0,
        }, -- end of ["GUN_LEFT_CENTER_OPEN_CIRCUIT"]
        ["EMMC_FAILURE_TRU_AC2DC28V"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_TRU_AC2DC28V",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_TRU_AC2DC28V"]
        ["TAIL_GEAR_D_LOCK_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TAIL_GEAR_D_LOCK_FAULT",
            ["mm"] = 0,
        }, -- end of ["TAIL_GEAR_D_LOCK_FAULT"]
        ["ELEVONOUTERRIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEVONOUTERRIGHT",
            ["mm"] = 0,
        }, -- end of ["ELEVONOUTERRIGHT"]
        ["fsf_CrossfeedValve"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fsf_CrossfeedValve",
            ["mm"] = 0,
        }, -- end of ["fsf_CrossfeedValve"]
        ["ELEC_MAIN_FUEL_PUMP_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_MAIN_FUEL_PUMP_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_MAIN_FUEL_PUMP_FAILURE"]
        ["ENG0_WASTEGATE_OIL_FEED_CLOGGED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_WASTEGATE_OIL_FEED_CLOGGED",
            ["mm"] = 0,
        }, -- end of ["ENG0_WASTEGATE_OIL_FEED_CLOGGED"]
        ["BOOST_REG"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOOST_REG",
            ["mm"] = 0,
        }, -- end of ["BOOST_REG"]
        ["r_conv"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "r_conv",
            ["mm"] = 0,
        }, -- end of ["r_conv"]
        ["DDD_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DDD_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["DDD_FAILURE_TOTAL"]
        ["FUELTANK2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUELTANK2",
            ["mm"] = 0,
        }, -- end of ["FUELTANK2"]
        ["BOMBS_SOLENOID_FAULT_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_SOLENOID_FAULT_RIGHT",
            ["mm"] = 0,
        }, -- end of ["BOMBS_SOLENOID_FAULT_RIGHT"]
        ["FLIR_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FLIR_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["FLIR_FAILURE_TOTAL"]
        ["inverters_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "inverters_fail",
            ["mm"] = 0,
        }, -- end of ["inverters_fail"]
        ["l_conv"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "l_conv",
            ["mm"] = 0,
        }, -- end of ["l_conv"]
        ["STRAKE_LEFT_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STRAKE_LEFT_FAILURE",
            ["mm"] = 0,
        }, -- end of ["STRAKE_LEFT_FAILURE"]
        ["CMS_FAILURE_PROGRAMMER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CMS_FAILURE_PROGRAMMER",
            ["mm"] = 0,
        }, -- end of ["CMS_FAILURE_PROGRAMMER"]
        ["ELEC_RED_SIGNAL_LIGHT_BROKEN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_RED_SIGNAL_LIGHT_BROKEN",
            ["mm"] = 0,
        }, -- end of ["ELEC_RED_SIGNAL_LIGHT_BROKEN"]
        ["ef_fire"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ef_fire",
            ["mm"] = 0,
        }, -- end of ["ef_fire"]
        ["mfd"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "mfd",
            ["mm"] = 0,
        }, -- end of ["mfd"]
        ["CARBAIR_GND_LEAD"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CARBAIR_GND_LEAD",
            ["mm"] = 0,
        }, -- end of ["CARBAIR_GND_LEAD"]
        ["FUELTANK5R"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUELTANK5R",
            ["mm"] = 0,
        }, -- end of ["FUELTANK5R"]
        ["hs_damage_MainAccumulator"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hs_damage_MainAccumulator",
            ["mm"] = 0,
        }, -- end of ["hs_damage_MainAccumulator"]
        ["PNEM_LH_BRAKE_HOSE_PERFORATED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PNEM_LH_BRAKE_HOSE_PERFORATED",
            ["mm"] = 0,
        }, -- end of ["PNEM_LH_BRAKE_HOSE_PERFORATED"]
        ["AFK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AFK",
            ["mm"] = 0,
        }, -- end of ["AFK"]
        ["UHF_ARC_159_FAILURE_INTERNAL_MODULE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UHF_ARC_159_FAILURE_INTERNAL_MODULE",
            ["mm"] = 0,
        }, -- end of ["UHF_ARC_159_FAILURE_INTERNAL_MODULE"]
        ["INST_CLOCK_MALFUNCTION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_CLOCK_MALFUNCTION",
            ["mm"] = 0,
        }, -- end of ["INST_CLOCK_MALFUNCTION"]
        ["FUEL_ENGINE0_FUEL_PUMP_DEGRADED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_ENGINE0_FUEL_PUMP_DEGRADED",
            ["mm"] = 0,
        }, -- end of ["FUEL_ENGINE0_FUEL_PUMP_DEGRADED"]
        ["ILS_FAILURE_ANT_GLIDESLOPE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ILS_FAILURE_ANT_GLIDESLOPE",
            ["mm"] = 0,
        }, -- end of ["ILS_FAILURE_ANT_GLIDESLOPE"]
        ["EEC_Failure_RightEngine"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EEC_Failure_RightEngine",
            ["mm"] = 0,
        }, -- end of ["EEC_Failure_RightEngine"]
        ["hydro_auxiliary"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "hydro_auxiliary",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["hydro_auxiliary"]
        ["GUN_LEFT_MG151_OPEN_CIRCUIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_LEFT_MG151_OPEN_CIRCUIT",
            ["mm"] = 0,
        }, -- end of ["GUN_LEFT_MG151_OPEN_CIRCUIT"]
        ["slats"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "slats",
            ["mm"] = 0,
        }, -- end of ["slats"]
        ["ROCKETS_DEFECTIVE_WIRING"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ROCKETS_DEFECTIVE_WIRING",
            ["mm"] = 0,
        }, -- end of ["ROCKETS_DEFECTIVE_WIRING"]
        ["ICS_FAILURE_AMPLIFIER_PILOT_BU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ICS_FAILURE_AMPLIFIER_PILOT_BU",
            ["mm"] = 0,
        }, -- end of ["ICS_FAILURE_AMPLIFIER_PILOT_BU"]
        ["hydro_diaphragm"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "hydro_diaphragm",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["hydro_diaphragm"]
        ["MWMMC_FAILURE_DMP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_DMP",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_DMP"]
        ["fsf_AutoBalance"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fsf_AutoBalance",
            ["mm"] = 0,
        }, -- end of ["fsf_AutoBalance"]
        ["FCS_FAILURE_PITCH_LVDT_4"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_PITCH_LVDT_4",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_PITCH_LVDT_4"]
        ["Failure_Comp_MC2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Comp_MC2",
            ["mm"] = 0,
        }, -- end of ["Failure_Comp_MC2"]
        ["SWMMC_FAILURE_DMP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_DMP",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_DMP"]
        ["EMMC_FAILURE_EMMC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_EMMC",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_EMMC"]
        ["ELEC_BOMBABWGERAT_RELEASE_MALFUNCTION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_BOMBABWGERAT_RELEASE_MALFUNCTION",
            ["mm"] = 0,
        }, -- end of ["ELEC_BOMBABWGERAT_RELEASE_MALFUNCTION"]
        ["FCS_FAILURE_YAW_RATE_GYRO_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_YAW_RATE_GYRO_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_YAW_RATE_GYRO_1"]
        ["acs"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["mm"] = 0,
        }, -- end of ["acs"]
        ["VHF_CRFUEL_MAIN_TANK_MINOR_LEAKYSTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VHF_CRFUEL_MAIN_TANK_MINOR_LEAKYSTAL",
            ["mm"] = 0,
        }, -- end of ["VHF_CRFUEL_MAIN_TANK_MINOR_LEAKYSTAL"]
        ["AN_ALE_40V_FAILURE_CONTAINER_RIGHT_GEAR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AN_ALE_40V_FAILURE_CONTAINER_RIGHT_GEAR",
            ["mm"] = 0,
        }, -- end of ["AN_ALE_40V_FAILURE_CONTAINER_RIGHT_GEAR"]
        ["os_damage_BalloonLeakage"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "os_damage_BalloonLeakage",
            ["mm"] = 0,
        }, -- end of ["os_damage_BalloonLeakage"]
        ["RWR_FAILURE_ANTENNA_FRONT_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_ANTENNA_FRONT_RIGHT",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_ANTENNA_FRONT_RIGHT"]
        ["SAR_1_2_95"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SAR_1_2_95",
            ["mm"] = 0,
        }, -- end of ["SAR_1_2_95"]
        ["RWR_FAILURE_SENSOR_TAIL_R"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_SENSOR_TAIL_R",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_SENSOR_TAIL_R"]
        ["STRAKE_RIGHT_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STRAKE_RIGHT_FAILURE",
            ["mm"] = 0,
        }, -- end of ["STRAKE_RIGHT_FAILURE"]
        ["FCS_FAILURE_WOW_4"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_WOW_4",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_WOW_4"]
        ["FCS_FAILURE_NZ_SENSOR_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_NZ_SENSOR_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_NZ_SENSOR_1"]
        ["ENG0_GOVERNOR_MALFUNCTION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_GOVERNOR_MALFUNCTION",
            ["mm"] = 0,
        }, -- end of ["ENG0_GOVERNOR_MALFUNCTION"]
        ["ENG0_GOVERNOR_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_GOVERNOR_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ENG0_GOVERNOR_FAILURE"]
        ["main_reductor_chip"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "main_reductor_chip",
            ["mm"] = 0,
        }, -- end of ["main_reductor_chip"]
        ["AIRBRAKESERVO"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AIRBRAKESERVO",
            ["mm"] = 0,
        }, -- end of ["AIRBRAKESERVO"]
        ["FAILURE_SMS_PYLON_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_SMS_PYLON_2",
            ["mm"] = 0,
        }, -- end of ["FAILURE_SMS_PYLON_2"]
        ["FUEL_TANK_00_LEAK_STOPPED"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_00_LEAK_STOPPED",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_00_LEAK_STOPPED"]
        ["INST_COMPASS_MALFUNCTION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_COMPASS_MALFUNCTION",
            ["mm"] = 0,
        }, -- end of ["INST_COMPASS_MALFUNCTION"]
        ["ELEC_REAR_FUEL_PUMP_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_REAR_FUEL_PUMP_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_REAR_FUEL_PUMP_FAILURE"]
        ["fs_forward_RH_leakage"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fs_forward_RH_leakage",
            ["mm"] = 0,
        }, -- end of ["fs_forward_RH_leakage"]
        ["CADC_FAILURE_PRESSURE_ALT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_FAILURE_PRESSURE_ALT",
            ["mm"] = 0,
        }, -- end of ["CADC_FAILURE_PRESSURE_ALT"]
        ["elevator_loss"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "elevator_loss",
            ["mm"] = 0,
        }, -- end of ["elevator_loss"]
        ["STATION_2_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STATION_2_FAILURE",
            ["mm"] = 0,
        }, -- end of ["STATION_2_FAILURE"]
        ["DEFECTIVE_INSTRUMENT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DEFECTIVE_INSTRUMENT",
            ["mm"] = 0,
        }, -- end of ["DEFECTIVE_INSTRUMENT"]
        ["gs_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "gs_fail",
            ["mm"] = 0,
        }, -- end of ["gs_fail"]
        ["FCS_FAILURE_P_SENSOR_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_P_SENSOR_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_P_SENSOR_2"]
        ["pp_damage_EmergMaxNormFreq"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pp_damage_EmergMaxNormFreq",
            ["mm"] = 0,
        }, -- end of ["pp_damage_EmergMaxNormFreq"]
        ["ELEC_FORWARD_FUEL_PUMP_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_FORWARD_FUEL_PUMP_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_FORWARD_FUEL_PUMP_FAILURE"]
        ["VHF_ARC_182_FAILURE_INTERNAL_MODULE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VHF_ARC_182_FAILURE_INTERNAL_MODULE",
            ["mm"] = 0,
        }, -- end of ["VHF_ARC_182_FAILURE_INTERNAL_MODULE"]
        ["engine_flameout_irrecoverable"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "engine_flameout_irrecoverable",
            ["mm"] = 0,
        }, -- end of ["engine_flameout_irrecoverable"]
        ["CTRL_COMPASS_DESTROYED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_COMPASS_DESTROYED",
            ["mm"] = 0,
        }, -- end of ["CTRL_COMPASS_DESTROYED"]
        ["GUN_RIGHT_IN_OPEN_CIRCUIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_RIGHT_IN_OPEN_CIRCUIT",
            ["mm"] = 0,
        }, -- end of ["GUN_RIGHT_IN_OPEN_CIRCUIT"]
        ["RWR_FAILURE_QUAD315"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_QUAD315",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_QUAD315"]
        ["FCS_FAILURE_COMP_4"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_COMP_4",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_COMP_4"]
        ["FUEL_TANK_00_MEDIUM_LEAK"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "FUEL_TANK_00_MEDIUM_LEAK",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_00_MEDIUM_LEAK"]
        ["INST_HUD_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_HUD_FAILURE",
            ["mm"] = 0,
        }, -- end of ["INST_HUD_FAILURE"]
        ["SUPERCHARGER_LIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SUPERCHARGER_LIGHT",
            ["mm"] = 0,
        }, -- end of ["SUPERCHARGER_LIGHT"]
        ["r_engine"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "r_engine",
            ["mm"] = 0,
        }, -- end of ["r_engine"]
        ["TRN_FAIL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TRN_FAIL",
            ["mm"] = 0,
        }, -- end of ["TRN_FAIL"]
        ["BOMBS_NO_VOLATAGE_AT_RACK_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_NO_VOLATAGE_AT_RACK_LEFT",
            ["mm"] = 0,
        }, -- end of ["BOMBS_NO_VOLATAGE_AT_RACK_LEFT"]
        ["FCS_FAILURE_YAW_AUGD_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_YAW_AUGD_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_YAW_AUGD_1"]
        ["BCKPITOT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BCKPITOT",
            ["mm"] = 0,
        }, -- end of ["BCKPITOT"]
        ["ELEC_DASHBOARD_HARNESS_CUT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_DASHBOARD_HARNESS_CUT",
            ["mm"] = 0,
        }, -- end of ["ELEC_DASHBOARD_HARNESS_CUT"]
        ["es_damage_Generator"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_Generator",
            ["mm"] = 0,
        }, -- end of ["es_damage_Generator"]
        ["ELEC_C5_LAMP_POOR_CONTACT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_C5_LAMP_POOR_CONTACT",
            ["mm"] = 0,
        }, -- end of ["ELEC_C5_LAMP_POOR_CONTACT"]
        ["CICU_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CICU_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["CICU_FAILURE_TOTAL"]
        ["INS_PU_REJECTED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_PU_REJECTED",
            ["mm"] = 0,
        }, -- end of ["INS_PU_REJECTED"]
        ["l_engine"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "l_engine",
            ["mm"] = 0,
        }, -- end of ["l_engine"]
        ["EGTSENSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EGTSENSOR",
            ["mm"] = 0,
        }, -- end of ["EGTSENSOR"]
        ["FCS_FAILURE_PITCH_LVDT_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_PITCH_LVDT_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_PITCH_LVDT_2"]
        ["ELEC_FUEL_PUMP_P1_COIL_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_FUEL_PUMP_P1_COIL_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_FUEL_PUMP_P1_COIL_FAILURE"]
        ["FUEL_MAIN_TANK_MAJOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_MAIN_TANK_MAJOR_LEAK",
            ["mm"] = 0,
        }, -- end of ["FUEL_MAIN_TANK_MAJOR_LEAK"]
        ["LEFT_GUNNER_KILLED_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LEFT_GUNNER_KILLED_FAILURE",
            ["mm"] = 0,
        }, -- end of ["LEFT_GUNNER_KILLED_FAILURE"]
        ["ELEC_BOOSTER_FUEL_PUMP_COIL_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_BOOSTER_FUEL_PUMP_COIL_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_BOOSTER_FUEL_PUMP_COIL_FAILURE"]
        ["SOPLO_FAILURE_PARTIAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SOPLO_FAILURE_PARTIAL",
            ["mm"] = 0,
        }, -- end of ["SOPLO_FAILURE_PARTIAL"]
        ["FCS_FAILURE_PITCH_RATE_GYRO_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_PITCH_RATE_GYRO_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_PITCH_RATE_GYRO_2"]
        ["EMMC_FAILURE_FUEL_LOWER_PUMP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_FUEL_LOWER_PUMP",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_FUEL_LOWER_PUMP"]
        ["CMS_FAILURE_RIGHT_DISPENSER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CMS_FAILURE_RIGHT_DISPENSER",
            ["mm"] = 0,
        }, -- end of ["CMS_FAILURE_RIGHT_DISPENSER"]
        ["EMMC_FAILURE_DADS_LPTU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_DADS_LPTU",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_DADS_LPTU"]
        ["FAILURE_EXT_LIGHT_FORMATION_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_EXT_LIGHT_FORMATION_RIGHT",
            ["mm"] = 0,
        }, -- end of ["FAILURE_EXT_LIGHT_FORMATION_RIGHT"]
        ["TURNIND_POINTER_FAILS_NO_VACUUM"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TURNIND_POINTER_FAILS_NO_VACUUM",
            ["mm"] = 0,
        }, -- end of ["TURNIND_POINTER_FAILS_NO_VACUUM"]
        ["RWRANTREAR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWRANTREAR",
            ["mm"] = 0,
        }, -- end of ["RWRANTREAR"]
        ["AHRS_FAILURE_MAD"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AHRS_FAILURE_MAD",
            ["mm"] = 0,
        }, -- end of ["AHRS_FAILURE_MAD"]
        ["VHF_ARC_182_FAILURE_DISPLAY"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VHF_ARC_182_FAILURE_DISPLAY",
            ["mm"] = 0,
        }, -- end of ["VHF_ARC_182_FAILURE_DISPLAY"]
        ["FCS_FAILURE_PITCH_RATE_GYRO_4"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_PITCH_RATE_GYRO_4",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_PITCH_RATE_GYRO_4"]
        ["COOLANT_POOR_CONNTECT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COOLANT_POOR_CONNTECT",
            ["mm"] = 0,
        }, -- end of ["COOLANT_POOR_CONNTECT"]
        ["HYD_ALT_1_FAIL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYD_ALT_1_FAIL",
            ["mm"] = 0,
        }, -- end of ["HYD_ALT_1_FAIL"]
        ["es_damage_MainInverter"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_MainInverter",
            ["mm"] = 0,
        }, -- end of ["es_damage_MainInverter"]
        ["AUX_TANK_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AUX_TANK_LEAK",
            ["mm"] = 0,
        }, -- end of ["AUX_TANK_LEAK"]
        ["FUEL_BOOSTER_FUEL_PUMP_2_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_BOOSTER_FUEL_PUMP_2_FAILURE",
            ["mm"] = 0,
        }, -- end of ["FUEL_BOOSTER_FUEL_PUMP_2_FAILURE"]
        ["KPP_1273_GYRO_TOTAL_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "KPP_1273_GYRO_TOTAL_FAILURE",
            ["mm"] = 0,
        }, -- end of ["KPP_1273_GYRO_TOTAL_FAILURE"]
        ["ENGINE_FAILURE_COMBUSTOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENGINE_FAILURE_COMBUSTOR",
            ["mm"] = 0,
        }, -- end of ["ENGINE_FAILURE_COMBUSTOR"]
        ["asc_y"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "asc_y",
            ["mm"] = 0,
        }, -- end of ["asc_y"]
        ["Surge_RightEngine"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Surge_RightEngine",
            ["mm"] = 0,
        }, -- end of ["Surge_RightEngine"]
        ["MAIN_L_GEAR_D_LOCK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MAIN_L_GEAR_D_LOCK",
            ["mm"] = 0,
        }, -- end of ["MAIN_L_GEAR_D_LOCK"]
        ["FAILURE_SMS_PYLON_4"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_SMS_PYLON_4",
            ["mm"] = 0,
        }, -- end of ["FAILURE_SMS_PYLON_4"]
        ["adf_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "adf_fail",
            ["mm"] = 0,
        }, -- end of ["adf_fail"]
        ["FUEL_RH_WING_TANK_MINOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_RH_WING_TANK_MINOR_LEAK",
            ["mm"] = 0,
        }, -- end of ["FUEL_RH_WING_TANK_MINOR_LEAK"]
        ["BOMBS_ARMING_BROKEN_WIRING"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_ARMING_BROKEN_WIRING",
            ["mm"] = 0,
        }, -- end of ["BOMBS_ARMING_BROKEN_WIRING"]
        ["FUSELAGE_TANK_PUMP_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUSELAGE_TANK_PUMP_FAULT",
            ["mm"] = 0,
        }, -- end of ["FUSELAGE_TANK_PUMP_FAULT"]
        ["EMMC_FAILURE_LWC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_LWC",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_LWC"]
        ["FUEL_GAUGE_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_GAUGE_FAULT",
            ["mm"] = 0,
        }, -- end of ["FUEL_GAUGE_FAULT"]
        ["GUN_LEFT_IN_AMMUN_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_LEFT_IN_AMMUN_FAULT",
            ["mm"] = 0,
        }, -- end of ["GUN_LEFT_IN_AMMUN_FAULT"]
        ["SUPERCHARGER_WIRE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SUPERCHARGER_WIRE",
            ["mm"] = 0,
        }, -- end of ["SUPERCHARGER_WIRE"]
        ["FAILURE_HYDRAULICS_1_EXTERNAL_LEAKAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_HYDRAULICS_1_EXTERNAL_LEAKAGE",
            ["mm"] = 0,
        }, -- end of ["FAILURE_HYDRAULICS_1_EXTERNAL_LEAKAGE"]
        ["CADC_FAILURE_TEMPERATURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_FAILURE_TEMPERATURE",
            ["mm"] = 0,
        }, -- end of ["CADC_FAILURE_TEMPERATURE"]
        ["es_damage_AltInverter"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_AltInverter",
            ["mm"] = 0,
        }, -- end of ["es_damage_AltInverter"]
        ["FCS_FAILURE_L_ELEVATOR_ELEC_A"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_L_ELEVATOR_ELEC_A",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_L_ELEVATOR_ELEC_A"]
        ["sensf_PITOT_DAMAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "sensf_PITOT_DAMAGE",
            ["mm"] = 0,
        }, -- end of ["sensf_PITOT_DAMAGE"]
        ["ELEC_STARTER_SOLENOID_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_STARTER_SOLENOID_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_STARTER_SOLENOID_FAILURE"]
        ["FAILURE_SMS_PYLON_5"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_SMS_PYLON_5",
            ["mm"] = 0,
        }, -- end of ["FAILURE_SMS_PYLON_5"]
        ["fs_damage_transfer_pumps"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fs_damage_transfer_pumps",
            ["mm"] = 0,
        }, -- end of ["fs_damage_transfer_pumps"]
        ["HYDR1ACC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYDR1ACC",
            ["mm"] = 0,
        }, -- end of ["HYDR1ACC"]
        ["fire_sys_fireAPU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fire_sys_fireAPU",
            ["mm"] = 0,
        }, -- end of ["fire_sys_fireAPU"]
        ["AC_BUS_PO7502_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AC_BUS_PO7502_FAILURE",
            ["mm"] = 0,
        }, -- end of ["AC_BUS_PO7502_FAILURE"]
        ["FUEL_TANK_03_MINOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_TANK_03_MINOR_LEAK",
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_03_MINOR_LEAK"]
        ["RWRANTLEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWRANTLEFT",
            ["mm"] = 0,
        }, -- end of ["RWRANTLEFT"]
        ["CMDISP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CMDISP",
            ["mm"] = 0,
        }, -- end of ["CMDISP"]
        ["fs_damage_swapping_pumps"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fs_damage_swapping_pumps",
            ["mm"] = 0,
        }, -- end of ["fs_damage_swapping_pumps"]
        ["ELECTRIC_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELECTRIC_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELECTRIC_FAILURE"]
        ["GUN_LEFT_MG151_AMMUN_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_LEFT_MG151_AMMUN_FAULT",
            ["mm"] = 0,
        }, -- end of ["GUN_LEFT_MG151_AMMUN_FAULT"]
        ["MWMMC_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE"]
        ["D2_RIGHT_CYLINDER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "D2_RIGHT_CYLINDER",
            ["mm"] = 0,
        }, -- end of ["D2_RIGHT_CYLINDER"]
        ["ELEC_PITOT_HEAT_WIRING"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_PITOT_HEAT_WIRING",
            ["mm"] = 0,
        }, -- end of ["ELEC_PITOT_HEAT_WIRING"]
        ["FUEL_AUX_TANK_MINOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_AUX_TANK_MINOR_LEAK",
            ["mm"] = 0,
        }, -- end of ["FUEL_AUX_TANK_MINOR_LEAK"]
        ["engine_flameout_recoverable"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "engine_flameout_recoverable",
            ["mm"] = 0,
        }, -- end of ["engine_flameout_recoverable"]
        ["FCS_FAILURE_NZ_SENSOR_3"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_NZ_SENSOR_3",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_NZ_SENSOR_3"]
        ["RKL_41_ADF_DAMAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RKL_41_ADF_DAMAGE",
            ["mm"] = 0,
        }, -- end of ["RKL_41_ADF_DAMAGE"]
        ["JESTER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "JESTER",
            ["mm"] = 0,
        }, -- end of ["JESTER"]
        ["COMPASS_ERRATIC_INDIACATON"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COMPASS_ERRATIC_INDIACATON",
            ["mm"] = 0,
        }, -- end of ["COMPASS_ERRATIC_INDIACATON"]
        ["FCS_FAILURE_AOA_SENSOR_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_AOA_SENSOR_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_AOA_SENSOR_1"]
        ["ppf_LeftOil"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ppf_LeftOil",
            ["mm"] = 0,
        }, -- end of ["ppf_LeftOil"]
        ["GMC_GYRO_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GMC_GYRO_FAILURE",
            ["mm"] = 0,
        }, -- end of ["GMC_GYRO_FAILURE"]
        ["es_damage_VU3"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "es_damage_VU3",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["es_damage_VU3"]
        ["FCS_FAILURE_YAW_AUGD_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_YAW_AUGD_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_YAW_AUGD_2"]
        ["CTRL_LANDING_FLAPS_LH_DRIVE_DAMAGED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_LANDING_FLAPS_LH_DRIVE_DAMAGED",
            ["mm"] = 0,
        }, -- end of ["CTRL_LANDING_FLAPS_LH_DRIVE_DAMAGED"]
        ["ELEC_UC_LAMP_RHD_BULB_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_UC_LAMP_RHD_BULB_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_UC_LAMP_RHD_BULB_FAILURE"]
        ["ENG0_STARTER_MOTOR_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_STARTER_MOTOR_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ENG0_STARTER_MOTOR_FAILURE"]
        ["GUN_LEFT_OUT_AMMUN_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_LEFT_OUT_AMMUN_FAULT",
            ["mm"] = 0,
        }, -- end of ["GUN_LEFT_OUT_AMMUN_FAULT"]
        ["engine_droop_failure"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "engine_droop_failure",
            ["mm"] = 0,
        }, -- end of ["engine_droop_failure"]
        ["mlws"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "mlws",
            ["mm"] = 0,
        }, -- end of ["mlws"]
        ["RADARDISPL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RADARDISPL",
            ["mm"] = 0,
        }, -- end of ["RADARDISPL"]
        ["ELEC_AMBER_SIGNAL_LIGHT_BROKEN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_AMBER_SIGNAL_LIGHT_BROKEN",
            ["mm"] = 0,
        }, -- end of ["ELEC_AMBER_SIGNAL_LIGHT_BROKEN"]
        ["pp_damage_EmergMaxFreq"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pp_damage_EmergMaxFreq",
            ["mm"] = 0,
        }, -- end of ["pp_damage_EmergMaxFreq"]
        ["OIL_T_IND_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OIL_T_IND_FAULT",
            ["mm"] = 0,
        }, -- end of ["OIL_T_IND_FAULT"]
        ["ELEC_LH_CABIN_LIGHT_POOR_CONTACT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_LH_CABIN_LIGHT_POOR_CONTACT",
            ["mm"] = 0,
        }, -- end of ["ELEC_LH_CABIN_LIGHT_POOR_CONTACT"]
        ["ICS_FAILURE_AMPLIFIER_PILOT_NORM"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ICS_FAILURE_AMPLIFIER_PILOT_NORM",
            ["mm"] = 0,
        }, -- end of ["ICS_FAILURE_AMPLIFIER_PILOT_NORM"]
        ["PNEM_LOW_PRS_JUNCTION_BOX_DESTROYED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PNEM_LOW_PRS_JUNCTION_BOX_DESTROYED",
            ["mm"] = 0,
        }, -- end of ["PNEM_LOW_PRS_JUNCTION_BOX_DESTROYED"]
        ["generator_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "generator_fail",
            ["mm"] = 0,
        }, -- end of ["generator_fail"]
        ["aoa_limiter"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "aoa_limiter",
            ["mm"] = 0,
        }, -- end of ["aoa_limiter"]
        ["ssf_full_pressure_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ssf_full_pressure_fail",
            ["mm"] = 0,
        }, -- end of ["ssf_full_pressure_fail"]
        ["TURNIND_POINTER_FAILS_DEFECTIVE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TURNIND_POINTER_FAILS_DEFECTIVE",
            ["mm"] = 0,
        }, -- end of ["TURNIND_POINTER_FAILS_DEFECTIVE"]
        ["FLEX_S_MAIN_LAMP_DEFECTIVE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FLEX_S_MAIN_LAMP_DEFECTIVE",
            ["mm"] = 0,
        }, -- end of ["FLEX_S_MAIN_LAMP_DEFECTIVE"]
        ["RADAR_ALTIMETR_LEFT_ANT_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RADAR_ALTIMETR_LEFT_ANT_FAILURE",
            ["mm"] = 0,
        }, -- end of ["RADAR_ALTIMETR_LEFT_ANT_FAILURE"]
        ["GUN_FAIL_RIGHT_OUT_GUN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_FAIL_RIGHT_OUT_GUN",
            ["mm"] = 0,
        }, -- end of ["GUN_FAIL_RIGHT_OUT_GUN"]
        ["Failure_Fuel_Tank4Transfer"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Fuel_Tank4Transfer",
            ["mm"] = 0,
        }, -- end of ["Failure_Fuel_Tank4Transfer"]
        ["ppf_LeftNozzleControl"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ppf_LeftNozzleControl",
            ["mm"] = 0,
        }, -- end of ["ppf_LeftNozzleControl"]
        ["FUELTANK4L"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUELTANK4L",
            ["mm"] = 0,
        }, -- end of ["FUELTANK4L"]
        ["MWMMC_FAILURE_1553B_EMMC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_1553B_EMMC",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_1553B_EMMC"]
        ["Failure_Elec_LeftTransformerRectifier"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Elec_LeftTransformerRectifier",
            ["mm"] = 0,
        }, -- end of ["Failure_Elec_LeftTransformerRectifier"]
        ["FCS_FAILURE_YAW_LVDT_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_YAW_LVDT_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_YAW_LVDT_1"]
        ["ENGINE_FAILURE_N1_COMPRESSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENGINE_FAILURE_N1_COMPRESSOR",
            ["mm"] = 0,
        }, -- end of ["ENGINE_FAILURE_N1_COMPRESSOR"]
        ["EXT_TANK_PUMP_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EXT_TANK_PUMP_FAULT",
            ["mm"] = 0,
        }, -- end of ["EXT_TANK_PUMP_FAULT"]
        ["GUN_LEFT_OUT_MOUNT_LOOSE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_LEFT_OUT_MOUNT_LOOSE",
            ["mm"] = 0,
        }, -- end of ["GUN_LEFT_OUT_MOUNT_LOOSE"]
        ["FUEL_TANK_01_LEAK_STOPPED"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_01_LEAK_STOPPED",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_01_LEAK_STOPPED"]
        ["TAIL_GEAR_U_LOCK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TAIL_GEAR_U_LOCK",
            ["mm"] = 0,
        }, -- end of ["TAIL_GEAR_U_LOCK"]
        ["LEFT_FLAP_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LEFT_FLAP_FAULT",
            ["mm"] = 0,
        }, -- end of ["LEFT_FLAP_FAULT"]
        ["PNEM_BRAKE_RELAY_MALFUNCTION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PNEM_BRAKE_RELAY_MALFUNCTION",
            ["mm"] = 0,
        }, -- end of ["PNEM_BRAKE_RELAY_MALFUNCTION"]
        ["OXY_FAILURE_R_LEAK_SEVERE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OXY_FAILURE_R_LEAK_SEVERE",
            ["mm"] = 0,
        }, -- end of ["OXY_FAILURE_R_LEAK_SEVERE"]
        ["ILS_FAILURE_DECODER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ILS_FAILURE_DECODER",
            ["mm"] = 0,
        }, -- end of ["ILS_FAILURE_DECODER"]
        ["es_damage_Inverter115_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_Inverter115_2",
            ["mm"] = 0,
        }, -- end of ["es_damage_Inverter115_2"]
        ["TAIL_GEAR_FAIL_GO_UP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TAIL_GEAR_FAIL_GO_UP",
            ["mm"] = 0,
        }, -- end of ["TAIL_GEAR_FAIL_GO_UP"]
        ["INS_GYROS_FAIL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_GYROS_FAIL",
            ["mm"] = 0,
        }, -- end of ["INS_GYROS_FAIL"]
        ["FCS_FAILURE_EFCS_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_EFCS_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_EFCS_1"]
        ["FAILURE_SMS_PYLON_6"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_SMS_PYLON_6",
            ["mm"] = 0,
        }, -- end of ["FAILURE_SMS_PYLON_6"]
        ["FCS_FAILURE_P_SENSOR_3"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_P_SENSOR_3",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_P_SENSOR_3"]
        ["RADARALTANT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RADARALTANT",
            ["mm"] = 0,
        }, -- end of ["RADARALTANT"]
        ["EMMC_FAILURE_AC_GENERATOR_SUBSYSTEM"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_AC_GENERATOR_SUBSYSTEM",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_AC_GENERATOR_SUBSYSTEM"]
        ["ELEC_FUEL_PUMP_P2_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_FUEL_PUMP_P2_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_FUEL_PUMP_P2_FAILURE"]
        ["Failure_Hyd_HYD1B_Leak"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Hyd_HYD1B_Leak",
            ["mm"] = 0,
        }, -- end of ["Failure_Hyd_HYD1B_Leak"]
        ["pp_damage_MainMaxFreq"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pp_damage_MainMaxFreq",
            ["mm"] = 0,
        }, -- end of ["pp_damage_MainMaxFreq"]
        ["SUPERCHARGER_SOLENOID"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SUPERCHARGER_SOLENOID",
            ["mm"] = 0,
        }, -- end of ["SUPERCHARGER_SOLENOID"]
        ["CADC_CSDC_CONNECTION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_CSDC_CONNECTION",
            ["mm"] = 0,
        }, -- end of ["CADC_CSDC_CONNECTION"]
        ["TCN_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TCN_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["TCN_FAILURE_TOTAL"]
        ["SHARS_FAILURE_SENSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SHARS_FAILURE_SENSOR",
            ["mm"] = 0,
        }, -- end of ["SHARS_FAILURE_SENSOR"]
        ["ELEC_STARTER_LOOM_SEVERED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_STARTER_LOOM_SEVERED",
            ["mm"] = 0,
        }, -- end of ["ELEC_STARTER_LOOM_SEVERED"]
        ["SWMMC_DVR_NO_RS422_COMM"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_DVR_NO_RS422_COMM",
            ["mm"] = 0,
        }, -- end of ["SWMMC_DVR_NO_RS422_COMM"]
        ["CDU_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CDU_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["CDU_FAILURE_TOTAL"]
        ["CADC_FAILURE_IAS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_FAILURE_IAS",
            ["mm"] = 0,
        }, -- end of ["CADC_FAILURE_IAS"]
        ["UNCR_RH_STRUT_DRIVE_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UNCR_RH_STRUT_DRIVE_FAILURE",
            ["mm"] = 0,
        }, -- end of ["UNCR_RH_STRUT_DRIVE_FAILURE"]
        ["INS_FAILURE_ALGNMENT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_FAILURE_ALGNMENT",
            ["mm"] = 0,
        }, -- end of ["INS_FAILURE_ALGNMENT"]
        ["GUN_LEFT_MG151_BARREL_WORN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_LEFT_MG151_BARREL_WORN",
            ["mm"] = 0,
        }, -- end of ["GUN_LEFT_MG151_BARREL_WORN"]
        ["RPMFault_RightEngine"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "RPMFault_RightEngine",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["RPMFault_RightEngine"]
        ["RGear_ext_fault"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RGear_ext_fault",
            ["mm"] = 0,
        }, -- end of ["RGear_ext_fault"]
        ["ELEC_UMFORMER_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_UMFORMER_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_UMFORMER_FAILURE"]
        ["fuel_leak"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fuel_leak",
            ["mm"] = 0,
        }, -- end of ["fuel_leak"]
        ["VHF_TOTAL_DAMAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VHF_TOTAL_DAMAGE",
            ["mm"] = 0,
        }, -- end of ["VHF_TOTAL_DAMAGE"]
        ["apus"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "apus",
            ["mm"] = 0,
        }, -- end of ["apus"]
        ["FAILURE_HYDRAULICS_EMERGE_ACCU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_HYDRAULICS_EMERGE_ACCU",
            ["mm"] = 0,
        }, -- end of ["FAILURE_HYDRAULICS_EMERGE_ACCU"]
        ["CTRL_AILERON_ROD_DESTROYED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_AILERON_ROD_DESTROYED",
            ["mm"] = 0,
        }, -- end of ["CTRL_AILERON_ROD_DESTROYED"]
        ["FAILURE_HYDRAULICS_2_EXTERNAL_LEAKAGE_SEVERE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_HYDRAULICS_2_EXTERNAL_LEAKAGE_SEVERE",
            ["mm"] = 0,
        }, -- end of ["FAILURE_HYDRAULICS_2_EXTERNAL_LEAKAGE_SEVERE"]
        ["UNCR_LH_STRUT_DRIVE_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UNCR_LH_STRUT_DRIVE_FAILURE",
            ["mm"] = 0,
        }, -- end of ["UNCR_LH_STRUT_DRIVE_FAILURE"]
        ["ENGINE_FAILURE_N1_TURBINE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENGINE_FAILURE_N1_TURBINE",
            ["mm"] = 0,
        }, -- end of ["ENGINE_FAILURE_N1_TURBINE"]
        ["HYDR_EXTERNAL_LEAKAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYDR_EXTERNAL_LEAKAGE",
            ["mm"] = 0,
        }, -- end of ["HYDR_EXTERNAL_LEAKAGE"]
        ["CADC_MANEUVER_FLAP_COMMAND"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_MANEUVER_FLAP_COMMAND",
            ["mm"] = 0,
        }, -- end of ["CADC_MANEUVER_FLAP_COMMAND"]
        ["pp_damage_BladesBrake"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pp_damage_BladesBrake",
            ["mm"] = 0,
        }, -- end of ["pp_damage_BladesBrake"]
        ["BATTERY"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BATTERY",
            ["mm"] = 0,
        }, -- end of ["BATTERY"]
        ["RWR_FAILURE_RECEIVER_XX3"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_RECEIVER_XX3",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_RECEIVER_XX3"]
        ["CADC_WING_SWEEP_COMMAND_CHANNEL_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_WING_SWEEP_COMMAND_CHANNEL_2",
            ["mm"] = 0,
        }, -- end of ["CADC_WING_SWEEP_COMMAND_CHANNEL_2"]
        ["CADC_ANGLE_OF_ATTACK_SIGNAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_ANGLE_OF_ATTACK_SIGNAL",
            ["mm"] = 0,
        }, -- end of ["CADC_ANGLE_OF_ATTACK_SIGNAL"]
        ["Failure_Ctrl_FCS_Ch3"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Ctrl_FCS_Ch3",
            ["mm"] = 0,
        }, -- end of ["Failure_Ctrl_FCS_Ch3"]
        ["EMMC_FAILURE_SCU_DC2AC36V"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_SCU_DC2AC36V",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_SCU_DC2AC36V"]
        ["UNCR_C_STRUT_UP_LOCK_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UNCR_C_STRUT_UP_LOCK_FAILURE",
            ["mm"] = 0,
        }, -- end of ["UNCR_C_STRUT_UP_LOCK_FAILURE"]
        ["FAILURE_HYDRAULICS_2_ACCU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_HYDRAULICS_2_ACCU",
            ["mm"] = 0,
        }, -- end of ["FAILURE_HYDRAULICS_2_ACCU"]
        ["FUEL_TANK_01_FIRE"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_01_FIRE",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_01_FIRE"]
        ["PNEM_CANNONS_HOSE_PERFORATED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PNEM_CANNONS_HOSE_PERFORATED",
            ["mm"] = 0,
        }, -- end of ["PNEM_CANNONS_HOSE_PERFORATED"]
        ["TransitionalReductor_LowOilPressure"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "TransitionalReductor_LowOilPressure",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["TransitionalReductor_LowOilPressure"]
        ["MW_50_VALVE_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MW_50_VALVE_FAULT",
            ["mm"] = 0,
        }, -- end of ["MW_50_VALVE_FAULT"]
        ["STATION_6_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STATION_6_FAILURE",
            ["mm"] = 0,
        }, -- end of ["STATION_6_FAILURE"]
        ["CADC_TOTAL_TEMPERATURE_SIGNAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_TOTAL_TEMPERATURE_SIGNAL",
            ["mm"] = 0,
        }, -- end of ["CADC_TOTAL_TEMPERATURE_SIGNAL"]
        ["CTRL_RUDDER_ROD_MINOR_DAMAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_RUDDER_ROD_MINOR_DAMAGE",
            ["mm"] = 0,
        }, -- end of ["CTRL_RUDDER_ROD_MINOR_DAMAGE"]
        ["Failure_RightEngine"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_RightEngine",
            ["mm"] = 0,
        }, -- end of ["Failure_RightEngine"]
        ["ELEC_BOMBABWGERAT_RELEASE_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_BOMBABWGERAT_RELEASE_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_BOMBABWGERAT_RELEASE_FAILURE"]
        ["HYDR_INTERNAL_LEAKAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYDR_INTERNAL_LEAKAGE",
            ["mm"] = 0,
        }, -- end of ["HYDR_INTERNAL_LEAKAGE"]
        ["VHF_SHORTED_CTL_BOX"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VHF_SHORTED_CTL_BOX",
            ["mm"] = 0,
        }, -- end of ["VHF_SHORTED_CTL_BOX"]
        ["CLOCK_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CLOCK_FAILURE",
            ["mm"] = 0,
        }, -- end of ["CLOCK_FAILURE"]
        ["TEMPSENSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TEMPSENSOR",
            ["mm"] = 0,
        }, -- end of ["TEMPSENSOR"]
        ["OIL_RADIATOR_WIRING"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OIL_RADIATOR_WIRING",
            ["mm"] = 0,
        }, -- end of ["OIL_RADIATOR_WIRING"]
        ["GTS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GTS",
            ["mm"] = 0,
        }, -- end of ["GTS"]
        ["ILS_FAILURE_ANTENNA"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ILS_FAILURE_ANTENNA",
            ["mm"] = 0,
        }, -- end of ["ILS_FAILURE_ANTENNA"]
        ["FCS_FAILURE_Q_SENSOR_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_Q_SENSOR_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_Q_SENSOR_1"]
        ["es_damage_Inverter36x3"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_Inverter36x3",
            ["mm"] = 0,
        }, -- end of ["es_damage_Inverter36x3"]
        ["es_damage_Starter"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_Starter",
            ["mm"] = 0,
        }, -- end of ["es_damage_Starter"]
        ["IMU_FAILURE_QUANTIZER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "IMU_FAILURE_QUANTIZER",
            ["mm"] = 0,
        }, -- end of ["IMU_FAILURE_QUANTIZER"]
        ["CTRL_LANDING_FLAPS_RH_DRIVE_DAMAGED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_LANDING_FLAPS_RH_DRIVE_DAMAGED",
            ["mm"] = 0,
        }, -- end of ["CTRL_LANDING_FLAPS_RH_DRIVE_DAMAGED"]
        ["EMMC_FAILURE_DADS_MPTU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_DADS_MPTU",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_DADS_MPTU"]
        ["Failure_PP_LeftPTS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_PP_LeftPTS",
            ["mm"] = 0,
        }, -- end of ["Failure_PP_LeftPTS"]
        ["SWMMC_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE"]
        ["VHF_VT_BURNED_OUT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VHF_VT_BURNED_OUT",
            ["mm"] = 0,
        }, -- end of ["VHF_VT_BURNED_OUT"]
        ["COPILOT_KILLED_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COPILOT_KILLED_FAILURE",
            ["mm"] = 0,
        }, -- end of ["COPILOT_KILLED_FAILURE"]
        ["CTRL_LANDING_FLAPS_RH_MECHANICAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_LANDING_FLAPS_RH_MECHANICAL",
            ["mm"] = 0,
        }, -- end of ["CTRL_LANDING_FLAPS_RH_MECHANICAL"]
        ["FCS_FAILURE_WOW_3"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_WOW_3",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_WOW_3"]
        ["CADC_FAILURE_STATIC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_FAILURE_STATIC",
            ["mm"] = 0,
        }, -- end of ["CADC_FAILURE_STATIC"]
        ["GUN_LEFT_CENTER_BARREL_WORN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_LEFT_CENTER_BARREL_WORN",
            ["mm"] = 0,
        }, -- end of ["GUN_LEFT_CENTER_BARREL_WORN"]
        ["dme_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "dme_fail",
            ["mm"] = 0,
        }, -- end of ["dme_fail"]
        ["FCS_FAILURE_R_ELEVATOR_HYD_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_R_ELEVATOR_HYD_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_R_ELEVATOR_HYD_1"]
        ["ELEC_DROPTANK_FUEL_PUMP_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_DROPTANK_FUEL_PUMP_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_DROPTANK_FUEL_PUMP_FAILURE"]
        ["FUEL_BOOSTER_FUEL_PUMP_1_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_BOOSTER_FUEL_PUMP_1_FAILURE",
            ["mm"] = 0,
        }, -- end of ["FUEL_BOOSTER_FUEL_PUMP_1_FAILURE"]
        ["REAR_TANK_PUMP_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "REAR_TANK_PUMP_FAULT",
            ["mm"] = 0,
        }, -- end of ["REAR_TANK_PUMP_FAULT"]
        ["PUMP_FAILS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PUMP_FAILS",
            ["mm"] = 0,
        }, -- end of ["PUMP_FAILS"]
        ["hydro_common"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hydro_common",
            ["mm"] = 0,
        }, -- end of ["hydro_common"]
        ["CNI_FAILURE_ILS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CNI_FAILURE_ILS",
            ["mm"] = 0,
        }, -- end of ["CNI_FAILURE_ILS"]
        ["STATION_4_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STATION_4_FAILURE",
            ["mm"] = 0,
        }, -- end of ["STATION_4_FAILURE"]
        ["RWR_FAILURE_BLANKER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_BLANKER",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_BLANKER"]
        ["FUEL_TANK_00_FIRE_STOPPED"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_00_FIRE_STOPPED",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_00_FIRE_STOPPED"]
        ["TILS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TILS",
            ["mm"] = 0,
        }, -- end of ["TILS"]
        ["MWMMC_FAILURE_1553B_RDR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_1553B_RDR",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_1553B_RDR"]
        ["FCS_FAILURE_R_ELEVATOR_HYD_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_R_ELEVATOR_HYD_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_R_ELEVATOR_HYD_2"]
        ["FUEL_REAR_TANK_MINOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_REAR_TANK_MINOR_LEAK",
            ["mm"] = 0,
        }, -- end of ["FUEL_REAR_TANK_MINOR_LEAK"]
        ["MWMMC_FAILURE_1553B_SAIU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_1553B_SAIU",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_1553B_SAIU"]
        ["DATACARTRIDGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DATACARTRIDGE",
            ["mm"] = 0,
        }, -- end of ["DATACARTRIDGE"]
        ["ENG0_MAGNETO1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_MAGNETO1",
            ["mm"] = 0,
        }, -- end of ["ENG0_MAGNETO1"]
        ["pitch_trim_runaway_down"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pitch_trim_runaway_down",
            ["mm"] = 0,
        }, -- end of ["pitch_trim_runaway_down"]
        ["INSUF_FUEL_PRES"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INSUF_FUEL_PRES",
            ["mm"] = 0,
        }, -- end of ["INSUF_FUEL_PRES"]
        ["K14_MOV_LAMP_DEFECTIVE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "K14_MOV_LAMP_DEFECTIVE",
            ["mm"] = 0,
        }, -- end of ["K14_MOV_LAMP_DEFECTIVE"]
        ["eng_computer_total_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "eng_computer_total_fail",
            ["mm"] = 0,
        }, -- end of ["eng_computer_total_fail"]
        ["PROP_GOVERNOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PROP_GOVERNOR",
            ["mm"] = 0,
        }, -- end of ["PROP_GOVERNOR"]
        ["MANIFOLD_SHIFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MANIFOLD_SHIFT",
            ["mm"] = 0,
        }, -- end of ["MANIFOLD_SHIFT"]
        ["GUN_RIGHT_MG131_BARREL_WORN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_RIGHT_MG131_BARREL_WORN",
            ["mm"] = 0,
        }, -- end of ["GUN_RIGHT_MG131_BARREL_WORN"]
        ["FUEL_TANK_04_MINOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_TANK_04_MINOR_LEAK",
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_04_MINOR_LEAK"]
        ["OESP_FAILURE_CH_DISP_R"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OESP_FAILURE_CH_DISP_R",
            ["mm"] = 0,
        }, -- end of ["OESP_FAILURE_CH_DISP_R"]
        ["RIGHT_GUNNER_KILLED_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RIGHT_GUNNER_KILLED_FAILURE",
            ["mm"] = 0,
        }, -- end of ["RIGHT_GUNNER_KILLED_FAILURE"]
        ["ELEC_SUPERCHARGER_BULB_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_SUPERCHARGER_BULB_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_SUPERCHARGER_BULB_FAILURE"]
        ["PNEM_PRIMARY_CONTAINER_PERFORATED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PNEM_PRIMARY_CONTAINER_PERFORATED",
            ["mm"] = 0,
        }, -- end of ["PNEM_PRIMARY_CONTAINER_PERFORATED"]
        ["GUN_RIGHT_MG151_AMMUN_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_RIGHT_MG151_AMMUN_FAULT",
            ["mm"] = 0,
        }, -- end of ["GUN_RIGHT_MG151_AMMUN_FAULT"]
        ["FCS_FAILURE_ROLL_LVDT_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_ROLL_LVDT_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_ROLL_LVDT_2"]
        ["fs_damage_EnginePump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fs_damage_EnginePump",
            ["mm"] = 0,
        }, -- end of ["fs_damage_EnginePump"]
        ["COPILOT_GYRO_TOTAL_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COPILOT_GYRO_TOTAL_FAILURE",
            ["mm"] = 0,
        }, -- end of ["COPILOT_GYRO_TOTAL_FAILURE"]
        ["HYD_Flight"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYD_Flight",
            ["mm"] = 0,
        }, -- end of ["HYD_Flight"]
        ["EGI_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EGI_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["EGI_FAILURE_TOTAL"]
        ["HYDR_PUMP_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYDR_PUMP_FAILURE",
            ["mm"] = 0,
        }, -- end of ["HYDR_PUMP_FAILURE"]
        ["NOSE_AIRSPEED_INDICATOR_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "NOSE_AIRSPEED_INDICATOR_FAILURE",
            ["mm"] = 0,
        }, -- end of ["NOSE_AIRSPEED_INDICATOR_FAILURE"]
        ["loc_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "loc_fail",
            ["mm"] = 0,
        }, -- end of ["loc_fail"]
        ["MainReducer_Fire"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MainReducer_Fire",
            ["mm"] = 0,
        }, -- end of ["MainReducer_Fire"]
        ["ENG0_MAGNETO0"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_MAGNETO0",
            ["mm"] = 0,
        }, -- end of ["ENG0_MAGNETO0"]
        ["OXY_FAILURE_AIR_O2_SWITCH"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OXY_FAILURE_AIR_O2_SWITCH",
            ["mm"] = 0,
        }, -- end of ["OXY_FAILURE_AIR_O2_SWITCH"]
        ["UHF_ARC_159_FAILURE_TRANSCEIVER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UHF_ARC_159_FAILURE_TRANSCEIVER",
            ["mm"] = 0,
        }, -- end of ["UHF_ARC_159_FAILURE_TRANSCEIVER"]
        ["COOLANT_BREAK_BULB"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COOLANT_BREAK_BULB",
            ["mm"] = 0,
        }, -- end of ["COOLANT_BREAK_BULB"]
        ["UNCR_RH_WHEEL_BRAKE_DAMAGED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UNCR_RH_WHEEL_BRAKE_DAMAGED",
            ["mm"] = 0,
        }, -- end of ["UNCR_RH_WHEEL_BRAKE_DAMAGED"]
        ["ELEC_MSB_DAMAGED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_MSB_DAMAGED",
            ["mm"] = 0,
        }, -- end of ["ELEC_MSB_DAMAGED"]
        ["STATION_1_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STATION_1_FAILURE",
            ["mm"] = 0,
        }, -- end of ["STATION_1_FAILURE"]
        ["ELEC_CABIN_LIGHTS_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_CABIN_LIGHTS_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_CABIN_LIGHTS_FAILURE"]
        ["RUDDER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RUDDER",
            ["mm"] = 0,
        }, -- end of ["RUDDER"]
        ["ENG0_BOOST_REGULATOR_MALFUNCTION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_BOOST_REGULATOR_MALFUNCTION",
            ["mm"] = 0,
        }, -- end of ["ENG0_BOOST_REGULATOR_MALFUNCTION"]
        ["UNCR_LH_STRUT_DOWN_LOCK_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UNCR_LH_STRUT_DOWN_LOCK_FAILURE",
            ["mm"] = 0,
        }, -- end of ["UNCR_LH_STRUT_DOWN_LOCK_FAILURE"]
        ["SWMMC_FAILURE_CSU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_CSU",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_CSU"]
        ["COMPRESSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COMPRESSOR",
            ["mm"] = 0,
        }, -- end of ["COMPRESSOR"]
        ["MWMMC_FAILURE_PS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_PS",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_PS"]
        ["fuel_sys_transfer_pumps"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fuel_sys_transfer_pumps",
            ["mm"] = 0,
        }, -- end of ["fuel_sys_transfer_pumps"]
        ["SUCTION_PUMP_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SUCTION_PUMP_FAILURE",
            ["mm"] = 0,
        }, -- end of ["SUCTION_PUMP_FAILURE"]
        ["FAILURE_EXT_LIGHT_NAV_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_EXT_LIGHT_NAV_LEFT",
            ["mm"] = 0,
        }, -- end of ["FAILURE_EXT_LIGHT_NAV_LEFT"]
        ["HYDR2PUMP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYDR2PUMP",
            ["mm"] = 0,
        }, -- end of ["HYDR2PUMP"]
        ["MWMMC_FAILURE_MBI"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_MBI",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_MBI"]
        ["FCS_FAILURE_LG_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_LG_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_LG_1"]
        ["GUN_RIGHT_CENTER_MOUNT_LOOSE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_RIGHT_CENTER_MOUNT_LOOSE",
            ["mm"] = 0,
        }, -- end of ["GUN_RIGHT_CENTER_MOUNT_LOOSE"]
        ["ELEC_NAVLIGHT_GREEN_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_NAVLIGHT_GREEN_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_NAVLIGHT_GREEN_FAILURE"]
        ["PILOT_KILLED_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PILOT_KILLED_FAILURE",
            ["mm"] = 0,
        }, -- end of ["PILOT_KILLED_FAILURE"]
        ["asc"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "asc",
            ["mm"] = 0,
        }, -- end of ["asc"]
        ["SWMMC_FAILURE_MBI"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_MBI",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_MBI"]
        ["FCS_FAILURE_AOA_SENSOR_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_AOA_SENSOR_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_AOA_SENSOR_2"]
        ["EMMC_FAILURE_FUEL_UPPER_PUMP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_FUEL_UPPER_PUMP",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_FUEL_UPPER_PUMP"]
        ["TACH_BREAK_IN_INDICATOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TACH_BREAK_IN_INDICATOR",
            ["mm"] = 0,
        }, -- end of ["TACH_BREAK_IN_INDICATOR"]
        ["TGP_FAILURE_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TGP_FAILURE_RIGHT",
            ["mm"] = 0,
        }, -- end of ["TGP_FAILURE_RIGHT"]
        ["CADC_FAILURE_TAS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_FAILURE_TAS",
            ["mm"] = 0,
        }, -- end of ["CADC_FAILURE_TAS"]
        ["es_damage_GeneratorRight"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_GeneratorRight",
            ["mm"] = 0,
        }, -- end of ["es_damage_GeneratorRight"]
        ["LEFT_WING_TANK_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LEFT_WING_TANK_LEAK",
            ["mm"] = 0,
        }, -- end of ["LEFT_WING_TANK_LEAK"]
        ["UHF_ARC_159_FAILURE_ANTENNA"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UHF_ARC_159_FAILURE_ANTENNA",
            ["mm"] = 0,
        }, -- end of ["UHF_ARC_159_FAILURE_ANTENNA"]
        ["INS_FAILURE_NAV_COMPUTER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_FAILURE_NAV_COMPUTER",
            ["mm"] = 0,
        }, -- end of ["INS_FAILURE_NAV_COMPUTER"]
        ["MAINGENERATOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MAINGENERATOR",
            ["mm"] = 0,
        }, -- end of ["MAINGENERATOR"]
        ["ENG0_OIL_HOSE_0_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_OIL_HOSE_0_LEAK",
            ["mm"] = 0,
        }, -- end of ["ENG0_OIL_HOSE_0_LEAK"]
        ["BATT_FAIL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BATT_FAIL",
            ["mm"] = 0,
        }, -- end of ["BATT_FAIL"]
        ["MWMMC_FAILURE_1553B_LMFCD"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_1553B_LMFCD",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_1553B_LMFCD"]
        ["PNEM_COMPRESSOR_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PNEM_COMPRESSOR_FAILURE",
            ["mm"] = 0,
        }, -- end of ["PNEM_COMPRESSOR_FAILURE"]
        ["ELEC_LH_JUNCTION_BOX_DESTROYED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_LH_JUNCTION_BOX_DESTROYED",
            ["mm"] = 0,
        }, -- end of ["ELEC_LH_JUNCTION_BOX_DESTROYED"]
        ["ADC_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ADC_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["ADC_FAILURE_TOTAL"]
        ["AFN2_DAMAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AFN2_DAMAGE",
            ["mm"] = 0,
        }, -- end of ["AFN2_DAMAGE"]
        ["RDR_FAILURE_TRANSMITTER_OVERHEAT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RDR_FAILURE_TRANSMITTER_OVERHEAT",
            ["mm"] = 0,
        }, -- end of ["RDR_FAILURE_TRANSMITTER_OVERHEAT"]
        ["esf_StaticInverter"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "esf_StaticInverter",
            ["mm"] = 0,
        }, -- end of ["esf_StaticInverter"]
        ["AHRS_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AHRS_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["AHRS_FAILURE_TOTAL"]
        ["LGear_ret_fault"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LGear_ret_fault",
            ["mm"] = 0,
        }, -- end of ["LGear_ret_fault"]
        ["FCS_FAILURE_AOA_SENSOR_3"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_AOA_SENSOR_3",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_AOA_SENSOR_3"]
        ["PPF_LE_TEMPER_LIM_OFF"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "PPF_LE_TEMPER_LIM_OFF",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["PPF_LE_TEMPER_LIM_OFF"]
        ["VHF_VT207_DEFECTIVE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VHF_VT207_DEFECTIVE",
            ["mm"] = 0,
        }, -- end of ["VHF_VT207_DEFECTIVE"]
        ["ELEC_RETICLE_BULB_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_RETICLE_BULB_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_RETICLE_BULB_FAILURE"]
        ["STARTER_SOLENOID"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STARTER_SOLENOID",
            ["mm"] = 0,
        }, -- end of ["STARTER_SOLENOID"]
        ["EMMC_FAILURE_PROBES_HEATING"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_PROBES_HEATING",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_PROBES_HEATING"]
        ["FCS_FAILURE_NY_SENSOR_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_NY_SENSOR_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_NY_SENSOR_2"]
        ["CNI_FAILURE_COM1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CNI_FAILURE_COM1",
            ["mm"] = 0,
        }, -- end of ["CNI_FAILURE_COM1"]
        ["ELEC_BOOSTER_FUEL_PUMP_1_COIL_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_BOOSTER_FUEL_PUMP_1_COIL_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_BOOSTER_FUEL_PUMP_1_COIL_FAILURE"]
        ["RightEngine_LowOilPressure"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RightEngine_LowOilPressure",
            ["mm"] = 0,
        }, -- end of ["RightEngine_LowOilPressure"]
        ["OXY_FAILURE_L_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OXY_FAILURE_L_LEAK",
            ["mm"] = 0,
        }, -- end of ["OXY_FAILURE_L_LEAK"]
        ["radar"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "radar",
            ["mm"] = 0,
        }, -- end of ["radar"]
        ["FCS_FAILURE_LG_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_LG_2",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_LG_2"]
        ["RWRANTRIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWRANTRIGHT",
            ["mm"] = 0,
        }, -- end of ["RWRANTRIGHT"]
        ["TailRotorControlFailure"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TailRotorControlFailure",
            ["mm"] = 0,
        }, -- end of ["TailRotorControlFailure"]
        ["LEFT_CYLINDER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LEFT_CYLINDER",
            ["mm"] = 0,
        }, -- end of ["LEFT_CYLINDER"]
        ["COOLANT_UNPRES"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COOLANT_UNPRES",
            ["mm"] = 0,
        }, -- end of ["COOLANT_UNPRES"]
        ["ARN_82_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ARN_82_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["ARN_82_FAILURE_TOTAL"]
        ["VHF_ARC_182_FAILURE_TRANSCEIVER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VHF_ARC_182_FAILURE_TRANSCEIVER",
            ["mm"] = 0,
        }, -- end of ["VHF_ARC_182_FAILURE_TRANSCEIVER"]
        ["AGD1_GYRO_TOTAL_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AGD1_GYRO_TOTAL_FAILURE",
            ["mm"] = 0,
        }, -- end of ["AGD1_GYRO_TOTAL_FAILURE"]
        ["TURNIND_INCORRECT_SENS_DEFECTIVE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TURNIND_INCORRECT_SENS_DEFECTIVE",
            ["mm"] = 0,
        }, -- end of ["TURNIND_INCORRECT_SENS_DEFECTIVE"]
        ["eos"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "eos",
            ["mm"] = 0,
        }, -- end of ["eos"]
        ["EMMC_FAILURE_DC_GENERATOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_DC_GENERATOR",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_DC_GENERATOR"]
        ["CADC_STABILIZER_AUTHORITY_COMMAND"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_STABILIZER_AUTHORITY_COMMAND",
            ["mm"] = 0,
        }, -- end of ["CADC_STABILIZER_AUTHORITY_COMMAND"]
        ["EMMC_FAILURE_LANDING_GEAR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_LANDING_GEAR",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_LANDING_GEAR"]
        ["FUEL_TANK_01_FIRE_STOPPED"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_01_FIRE_STOPPED",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_01_FIRE_STOPPED"]
        ["EMMC_FAILURE_FUEL_LOW_LEVEL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_FUEL_LOW_LEVEL",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_FUEL_LOW_LEVEL"]
        ["FUEL_BOOSTER_FUEL_PUMP_0_DEGRADED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_BOOSTER_FUEL_PUMP_0_DEGRADED",
            ["mm"] = 0,
        }, -- end of ["FUEL_BOOSTER_FUEL_PUMP_0_DEGRADED"]
        ["HYDR_UNLOAD_VALVE_NOT_LOAD"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYDR_UNLOAD_VALVE_NOT_LOAD",
            ["mm"] = 0,
        }, -- end of ["HYDR_UNLOAD_VALVE_NOT_LOAD"]
        ["FCS_FAILURE_Q_SENSOR_4"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_Q_SENSOR_4",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_Q_SENSOR_4"]
        ["PITOT_HEAT_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PITOT_HEAT_FAULT",
            ["mm"] = 0,
        }, -- end of ["PITOT_HEAT_FAULT"]
        ["EMMC_FAILURE_AC_GENERATOR_FEED_LINE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_AC_GENERATOR_FEED_LINE",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_AC_GENERATOR_FEED_LINE"]
        ["ENG0_OIL_PUMP_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_OIL_PUMP_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ENG0_OIL_PUMP_FAILURE"]
        ["FCS_FAILURE_NZ_SENSOR_4"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_NZ_SENSOR_4",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_NZ_SENSOR_4"]
        ["RDR_FAILURE_ANTENNA_DEGRATION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RDR_FAILURE_ANTENNA_DEGRATION",
            ["mm"] = 0,
        }, -- end of ["RDR_FAILURE_ANTENNA_DEGRATION"]
        ["HUD_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HUD_FAILURE",
            ["mm"] = 0,
        }, -- end of ["HUD_FAILURE"]
        ["BAT_SOLENOID_DEFECTIVE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BAT_SOLENOID_DEFECTIVE",
            ["mm"] = 0,
        }, -- end of ["BAT_SOLENOID_DEFECTIVE"]
        ["GUN_FAIL_LEFT_CENTER_GUN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_FAIL_LEFT_CENTER_GUN",
            ["mm"] = 0,
        }, -- end of ["GUN_FAIL_LEFT_CENTER_GUN"]
        ["RWR_FAILURE_DISPLAY_RIO"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_DISPLAY_RIO",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_DISPLAY_RIO"]
        ["BOMBS_DAMAGE_ELINKAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_DAMAGE_ELINKAGE",
            ["mm"] = 0,
        }, -- end of ["BOMBS_DAMAGE_ELINKAGE"]
        ["LeftEngine_Fire"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LeftEngine_Fire",
            ["mm"] = 0,
        }, -- end of ["LeftEngine_Fire"]
        ["L_GEAR_DLK_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_GEAR_DLK_FAULT",
            ["mm"] = 0,
        }, -- end of ["L_GEAR_DLK_FAULT"]
        ["pp_damage_OilPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pp_damage_OilPump",
            ["mm"] = 0,
        }, -- end of ["pp_damage_OilPump"]
        ["L_GEAR_UPL_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_GEAR_UPL_FAULT",
            ["mm"] = 0,
        }, -- end of ["L_GEAR_UPL_FAULT"]
        ["RDR_FAILURE_RX_FRONT_END"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RDR_FAILURE_RX_FRONT_END",
            ["mm"] = 0,
        }, -- end of ["RDR_FAILURE_RX_FRONT_END"]
        ["AAR_47_FAILURE_SENSOR_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AAR_47_FAILURE_SENSOR_RIGHT",
            ["mm"] = 0,
        }, -- end of ["AAR_47_FAILURE_SENSOR_RIGHT"]
        ["VHF_ARC_182_FAILURE_ANTENNA"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VHF_ARC_182_FAILURE_ANTENNA",
            ["mm"] = 0,
        }, -- end of ["VHF_ARC_182_FAILURE_ANTENNA"]
        ["FCS_FAILURE_R_ELEVATOR_ELEC_B"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_R_ELEVATOR_ELEC_B",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_R_ELEVATOR_ELEC_B"]
        ["INST_DI_EXCESSIVE_DRIFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_DI_EXCESSIVE_DRIFT",
            ["mm"] = 0,
        }, -- end of ["INST_DI_EXCESSIVE_DRIFT"]
        ["RWR_FAILURE_ANTENNA_FRONT_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_ANTENNA_FRONT_LEFT",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_ANTENNA_FRONT_LEFT"]
        ["BURNER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BURNER",
            ["mm"] = 0,
        }, -- end of ["BURNER"]
        ["GUN_RIGHT_IN_MOUNT_LOOSE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_RIGHT_IN_MOUNT_LOOSE",
            ["mm"] = 0,
        }, -- end of ["GUN_RIGHT_IN_MOUNT_LOOSE"]
        ["TailReductor_ShaveInOil"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TailReductor_ShaveInOil",
            ["mm"] = 0,
        }, -- end of ["TailReductor_ShaveInOil"]
        ["INST_DI_MECHANICAL_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_DI_MECHANICAL_FAILURE",
            ["mm"] = 0,
        }, -- end of ["INST_DI_MECHANICAL_FAILURE"]
        ["ENGINE_FAILURE_DEEC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENGINE_FAILURE_DEEC",
            ["mm"] = 0,
        }, -- end of ["ENGINE_FAILURE_DEEC"]
        ["FCS_FAILURE_P_SENSOR_4"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_P_SENSOR_4",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_P_SENSOR_4"]
        ["FCS_FAILURE_YAW_ELEC_SERVO_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_YAW_ELEC_SERVO_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_YAW_ELEC_SERVO_1"]
        ["R_GEAR_UPL_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_GEAR_UPL_FAULT",
            ["mm"] = 0,
        }, -- end of ["R_GEAR_UPL_FAULT"]
        ["BOMBS_TRAIN_DEFECTIVE_WIRING"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_TRAIN_DEFECTIVE_WIRING",
            ["mm"] = 0,
        }, -- end of ["BOMBS_TRAIN_DEFECTIVE_WIRING"]
        ["Failure_Fuel_ExtTankTransferL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Fuel_ExtTankTransferL",
            ["mm"] = 0,
        }, -- end of ["Failure_Fuel_ExtTankTransferL"]
        ["TACAN_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TACAN_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["TACAN_FAILURE_TOTAL"]
        ["CARBAIR_SHORT_CIRCUIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CARBAIR_SHORT_CIRCUIT",
            ["mm"] = 0,
        }, -- end of ["CARBAIR_SHORT_CIRCUIT"]
        ["CMS_FAILURE_LEFT_DISPENSER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CMS_FAILURE_LEFT_DISPENSER",
            ["mm"] = 0,
        }, -- end of ["CMS_FAILURE_LEFT_DISPENSER"]
        ["STARTER_RELAY"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STARTER_RELAY",
            ["mm"] = 0,
        }, -- end of ["STARTER_RELAY"]
        ["COM2_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COM2_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["COM2_FAILURE_TOTAL"]
        ["DMT_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DMT_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["DMT_FAILURE_TOTAL"]
        ["PNEM_RH_BRAKE_HOSE_PERFORATED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PNEM_RH_BRAKE_HOSE_PERFORATED",
            ["mm"] = 0,
        }, -- end of ["PNEM_RH_BRAKE_HOSE_PERFORATED"]
        ["TACAN_FAILURE_RECEIVER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TACAN_FAILURE_RECEIVER",
            ["mm"] = 0,
        }, -- end of ["TACAN_FAILURE_RECEIVER"]
        ["OESP_FAILURE_FL_DISP_L"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OESP_FAILURE_FL_DISP_L",
            ["mm"] = 0,
        }, -- end of ["OESP_FAILURE_FL_DISP_L"]
        ["Failure_Sens_RightPitotHeater"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Sens_RightPitotHeater",
            ["mm"] = 0,
        }, -- end of ["Failure_Sens_RightPitotHeater"]
        ["FUEL_DROPTANK_LINE_SEVERED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_DROPTANK_LINE_SEVERED",
            ["mm"] = 0,
        }, -- end of ["FUEL_DROPTANK_LINE_SEVERED"]
        ["HAW"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HAW",
            ["mm"] = 0,
        }, -- end of ["HAW"]
        ["SWMMC_FAILURE_IOC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_IOC",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_IOC"]
        ["RWR_FAILURE_DB_NOT_LOADED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_DB_NOT_LOADED",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_DB_NOT_LOADED"]
        ["vor_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "vor_fail",
            ["mm"] = 0,
        }, -- end of ["vor_fail"]
        ["LEFT_MFCD_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LEFT_MFCD_FAILURE",
            ["mm"] = 0,
        }, -- end of ["LEFT_MFCD_FAILURE"]
        ["SAR_hover_flight_glide"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "SAR_hover_flight_glide",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["SAR_hover_flight_glide"]
        ["AN_ALE_40V_FAILURE_CONTAINER_LEFT_WING"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AN_ALE_40V_FAILURE_CONTAINER_LEFT_WING",
            ["mm"] = 0,
        }, -- end of ["AN_ALE_40V_FAILURE_CONTAINER_LEFT_WING"]
        ["CNI_FAILURE_COM2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CNI_FAILURE_COM2",
            ["mm"] = 0,
        }, -- end of ["CNI_FAILURE_COM2"]
        ["BOOSTER_COIL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOOSTER_COIL",
            ["mm"] = 0,
        }, -- end of ["BOOSTER_COIL"]
        ["DOORS_TVC_BROKEN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DOORS_TVC_BROKEN",
            ["mm"] = 0,
        }, -- end of ["DOORS_TVC_BROKEN"]
        ["FAILURE_SMS_PYLON_3"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_SMS_PYLON_3",
            ["mm"] = 0,
        }, -- end of ["FAILURE_SMS_PYLON_3"]
        ["HYDRRESERVPUMP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYDRRESERVPUMP",
            ["mm"] = 0,
        }, -- end of ["HYDRRESERVPUMP"]
        ["fs_damage_left_cell_boost_pump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fs_damage_left_cell_boost_pump",
            ["mm"] = 0,
        }, -- end of ["fs_damage_left_cell_boost_pump"]
        ["ENG0_OIL_RADIATOR_0_PIERCED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_OIL_RADIATOR_0_PIERCED",
            ["mm"] = 0,
        }, -- end of ["ENG0_OIL_RADIATOR_0_PIERCED"]
        ["BOMBS_DAMAGE_ELINKAGE_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_DAMAGE_ELINKAGE_LEFT",
            ["mm"] = 0,
        }, -- end of ["BOMBS_DAMAGE_ELINKAGE_LEFT"]
        ["AGK_47B_GYRO_TOTAL_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AGK_47B_GYRO_TOTAL_FAILURE",
            ["mm"] = 0,
        }, -- end of ["AGK_47B_GYRO_TOTAL_FAILURE"]
        ["FUEL_BOOSTER_FUEL_PUMP_1_DEGRADED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_BOOSTER_FUEL_PUMP_1_DEGRADED",
            ["mm"] = 0,
        }, -- end of ["FUEL_BOOSTER_FUEL_PUMP_1_DEGRADED"]
        ["ENGINE_JAM"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENGINE_JAM",
            ["mm"] = 0,
        }, -- end of ["ENGINE_JAM"]
        ["OXY_FAILURE_L_LEAK_SEVERE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OXY_FAILURE_L_LEAK_SEVERE",
            ["mm"] = 0,
        }, -- end of ["OXY_FAILURE_L_LEAK_SEVERE"]
        ["MAGNETO_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MAGNETO_2",
            ["mm"] = 0,
        }, -- end of ["MAGNETO_2"]
        ["DTC_FAILURE_READER_BROKEN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DTC_FAILURE_READER_BROKEN",
            ["mm"] = 0,
        }, -- end of ["DTC_FAILURE_READER_BROKEN"]
        ["IFF"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "IFF",
            ["mm"] = 0,
        }, -- end of ["IFF"]
        ["RWR_FAILURE_SENSOR_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_SENSOR_RIGHT",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_SENSOR_RIGHT"]
        ["Failure_Elec_EmergencyBattery"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Elec_EmergencyBattery",
            ["mm"] = 0,
        }, -- end of ["Failure_Elec_EmergencyBattery"]
        ["RKL_41_ANT_DAMAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RKL_41_ANT_DAMAGE",
            ["mm"] = 0,
        }, -- end of ["RKL_41_ANT_DAMAGE"]
        ["ENG0_OIL_HOSE_0_BURST"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_OIL_HOSE_0_BURST",
            ["mm"] = 0,
        }, -- end of ["ENG0_OIL_HOSE_0_BURST"]
        ["ENG0_WATER_RADIATOR_0_PIERCED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_WATER_RADIATOR_0_PIERCED",
            ["mm"] = 0,
        }, -- end of ["ENG0_WATER_RADIATOR_0_PIERCED"]
        ["RWR_FAILURE_MBE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_MBE",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_MBE"]
        ["RWR_FAILURE_SENSOR_TAIL_F"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_SENSOR_TAIL_F",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_SENSOR_TAIL_F"]
        ["ELEC_UC_LAMP_CU_BULB_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_UC_LAMP_CU_BULB_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_UC_LAMP_CU_BULB_FAILURE"]
        ["ELEC_STARTER_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_STARTER_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_STARTER_FAILURE"]
        ["PITOT_HEAT_ELEMENT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PITOT_HEAT_ELEMENT",
            ["mm"] = 0,
        }, -- end of ["PITOT_HEAT_ELEMENT"]
        ["engine_driveshaft_failure"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "engine_driveshaft_failure",
            ["mm"] = 0,
        }, -- end of ["engine_driveshaft_failure"]
        ["PUMP_RELIEF_VALVE_LEAKS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PUMP_RELIEF_VALVE_LEAKS",
            ["mm"] = 0,
        }, -- end of ["PUMP_RELIEF_VALVE_LEAKS"]
        ["hs_damage_AuxAccumulator"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hs_damage_AuxAccumulator",
            ["mm"] = 0,
        }, -- end of ["hs_damage_AuxAccumulator"]
        ["GUN_RIGHT_MG131_AMMUN_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_RIGHT_MG131_AMMUN_FAULT",
            ["mm"] = 0,
        }, -- end of ["GUN_RIGHT_MG131_AMMUN_FAULT"]
        ["ENGINE_FAILURE_NOZZLE_CONTROLLER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENGINE_FAILURE_NOZZLE_CONTROLLER",
            ["mm"] = 0,
        }, -- end of ["ENGINE_FAILURE_NOZZLE_CONTROLLER"]
        ["PNEM_LH_FLAP_JACK_BUSTED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PNEM_LH_FLAP_JACK_BUSTED",
            ["mm"] = 0,
        }, -- end of ["PNEM_LH_FLAP_JACK_BUSTED"]
        ["Failure_Elec_UtilityBattery"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Elec_UtilityBattery",
            ["mm"] = 0,
        }, -- end of ["Failure_Elec_UtilityBattery"]
        ["sas_pitch_left"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "sas_pitch_left",
            ["mm"] = 0,
        }, -- end of ["sas_pitch_left"]
        ["PUMP_RELIEF_VALVE_SCREEN_CLOGGED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PUMP_RELIEF_VALVE_SCREEN_CLOGGED",
            ["mm"] = 0,
        }, -- end of ["PUMP_RELIEF_VALVE_SCREEN_CLOGGED"]
        ["IFFCC_FAILURE_GUN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "IFFCC_FAILURE_GUN",
            ["mm"] = 0,
        }, -- end of ["IFFCC_FAILURE_GUN"]
        ["COM1_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COM1_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["COM1_FAILURE_TOTAL"]
        ["CNI_FAILURE_IFF_RX"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CNI_FAILURE_IFF_RX",
            ["mm"] = 0,
        }, -- end of ["CNI_FAILURE_IFF_RX"]
        ["BAT_SOLENOID_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BAT_SOLENOID_FAULT",
            ["mm"] = 0,
        }, -- end of ["BAT_SOLENOID_FAULT"]
        ["UNCR_CONTROLLER_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UNCR_CONTROLLER_FAILURE",
            ["mm"] = 0,
        }, -- end of ["UNCR_CONTROLLER_FAILURE"]
        ["FUEL_MAIN_TANK_MINOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_MAIN_TANK_MINOR_LEAK",
            ["mm"] = 0,
        }, -- end of ["FUEL_MAIN_TANK_MINOR_LEAK"]
        ["ELEC_BOOSTER_FUEL_PUMP_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_BOOSTER_FUEL_PUMP_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_BOOSTER_FUEL_PUMP_FAILURE"]
        ["DTC_FAILURE_DATA_CRC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DTC_FAILURE_DATA_CRC",
            ["mm"] = 0,
        }, -- end of ["DTC_FAILURE_DATA_CRC"]
        ["CNI_FAILURE_RALT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CNI_FAILURE_RALT",
            ["mm"] = 0,
        }, -- end of ["CNI_FAILURE_RALT"]
        ["OESP_FAILURE_MAWS_L"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OESP_FAILURE_MAWS_L",
            ["mm"] = 0,
        }, -- end of ["OESP_FAILURE_MAWS_L"]
        ["AN_ALE_40V_FAILURE_CONTAINER_RIGHT_WING"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AN_ALE_40V_FAILURE_CONTAINER_RIGHT_WING",
            ["mm"] = 0,
        }, -- end of ["AN_ALE_40V_FAILURE_CONTAINER_RIGHT_WING"]
        ["GUN_FAIL_LEFT_OUT_GUN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_FAIL_LEFT_OUT_GUN",
            ["mm"] = 0,
        }, -- end of ["GUN_FAIL_LEFT_OUT_GUN"]
        ["hs_damage_MainAutoUnload"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hs_damage_MainAutoUnload",
            ["mm"] = 0,
        }, -- end of ["hs_damage_MainAutoUnload"]
        ["FCS_FAILURE_Q_SENSOR_3"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_Q_SENSOR_3",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_Q_SENSOR_3"]
        ["INS_FAILURE_GYRO"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_FAILURE_GYRO",
            ["mm"] = 0,
        }, -- end of ["INS_FAILURE_GYRO"]
        ["EMMC_FAILURE_DC_GENERATOR_CONTROLLER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_DC_GENERATOR_CONTROLLER",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_DC_GENERATOR_CONTROLLER"]
        ["MWMMC_FAILURE_1553B_RALT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_1553B_RALT",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_1553B_RALT"]
        ["Failure_PP_EngL_OilLeak"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_PP_EngL_OilLeak",
            ["mm"] = 0,
        }, -- end of ["Failure_PP_EngL_OilLeak"]
        ["SWMMC_FAILURE_AAP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_AAP",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_AAP"]
        ["PITOT_HEAT_WIRING"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PITOT_HEAT_WIRING",
            ["mm"] = 0,
        }, -- end of ["PITOT_HEAT_WIRING"]
        ["hs_damage_MainHydro"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hs_damage_MainHydro",
            ["mm"] = 0,
        }, -- end of ["hs_damage_MainHydro"]
        ["FDU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FDU",
            ["mm"] = 0,
        }, -- end of ["FDU"]
        ["COOLANT_T_IND_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COOLANT_T_IND_FAULT",
            ["mm"] = 0,
        }, -- end of ["COOLANT_T_IND_FAULT"]
        ["INST_TACH0_LOOM_SEVERED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_TACH0_LOOM_SEVERED",
            ["mm"] = 0,
        }, -- end of ["INST_TACH0_LOOM_SEVERED"]
        ["F2_BOTTOM_CYLINDER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "F2_BOTTOM_CYLINDER",
            ["mm"] = 0,
        }, -- end of ["F2_BOTTOM_CYLINDER"]
        ["AN_ALR69V_FAILURE_SENSOR_TAIL_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AN_ALR69V_FAILURE_SENSOR_TAIL_LEFT",
            ["mm"] = 0,
        }, -- end of ["AN_ALR69V_FAILURE_SENSOR_TAIL_LEFT"]
        ["BOMBS_DAMAGE_LINKAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_DAMAGE_LINKAGE",
            ["mm"] = 0,
        }, -- end of ["BOMBS_DAMAGE_LINKAGE"]
        ["pitch_trim_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pitch_trim_fail",
            ["mm"] = 0,
        }, -- end of ["pitch_trim_fail"]
        ["RDR_FAILURE_TRANSMITTER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RDR_FAILURE_TRANSMITTER",
            ["mm"] = 0,
        }, -- end of ["RDR_FAILURE_TRANSMITTER"]
        ["fs_aft_central_leakage"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fs_aft_central_leakage",
            ["mm"] = 0,
        }, -- end of ["fs_aft_central_leakage"]
        ["BATTERY_OVERHEAT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BATTERY_OVERHEAT",
            ["mm"] = 0,
        }, -- end of ["BATTERY_OVERHEAT"]
        ["K14_MOTOR_DEFECTIVE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "K14_MOTOR_DEFECTIVE",
            ["mm"] = 0,
        }, -- end of ["K14_MOTOR_DEFECTIVE"]
        ["HYD_Combined"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYD_Combined",
            ["mm"] = 0,
        }, -- end of ["HYD_Combined"]
        ["RADIO_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RADIO_FAILURE",
            ["mm"] = 0,
        }, -- end of ["RADIO_FAILURE"]
        ["EMMC_FAILURE_SCU_DC2AC115V"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_SCU_DC2AC115V",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_SCU_DC2AC115V"]
        ["FCS_FAILURE_WOW_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_WOW_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_WOW_1"]
        ["GUN_FAIL_RIGHT_IN_GUN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_FAIL_RIGHT_IN_GUN",
            ["mm"] = 0,
        }, -- end of ["GUN_FAIL_RIGHT_IN_GUN"]
        ["Failure_PP_EngL_AB_FFCS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_PP_EngL_AB_FFCS",
            ["mm"] = 0,
        }, -- end of ["Failure_PP_EngL_AB_FFCS"]
        ["PNEM_RADIATOR_JACK_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PNEM_RADIATOR_JACK_FAILURE",
            ["mm"] = 0,
        }, -- end of ["PNEM_RADIATOR_JACK_FAILURE"]
        ["DC_BUS_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DC_BUS_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["DC_BUS_FAILURE_TOTAL"]
        ["BOMBS_NO_VOLATAGE_AT_RACK_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_NO_VOLATAGE_AT_RACK_RIGHT",
            ["mm"] = 0,
        }, -- end of ["BOMBS_NO_VOLATAGE_AT_RACK_RIGHT"]
        ["TACH_BREAK_CIRCUIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TACH_BREAK_CIRCUIT",
            ["mm"] = 0,
        }, -- end of ["TACH_BREAK_CIRCUIT"]
        ["AC_BUS_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AC_BUS_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["AC_BUS_FAILURE_TOTAL"]
        ["TAIL_GEAR_D_LOCK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TAIL_GEAR_D_LOCK",
            ["mm"] = 0,
        }, -- end of ["TAIL_GEAR_D_LOCK"]
        ["hud"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hud",
            ["mm"] = 0,
        }, -- end of ["hud"]
        ["EMMC_FAILURE_ECS_OFF"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_ECS_OFF",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_ECS_OFF"]
        ["PITOT_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PITOT_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["PITOT_FAILURE_TOTAL"]
        ["BOMBS_DAMAGE_LINKAGE_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_DAMAGE_LINKAGE_RIGHT",
            ["mm"] = 0,
        }, -- end of ["BOMBS_DAMAGE_LINKAGE_RIGHT"]
        ["ppf_FireRight"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ppf_FireRight",
            ["mm"] = 0,
        }, -- end of ["ppf_FireRight"]
        ["esf_RightRectifier"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "esf_RightRectifier",
            ["mm"] = 0,
        }, -- end of ["esf_RightRectifier"]
        ["EZ42_MOTOR_DEFECTIVE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EZ42_MOTOR_DEFECTIVE",
            ["mm"] = 0,
        }, -- end of ["EZ42_MOTOR_DEFECTIVE"]
        ["Failure_PP_EngR_AB_FFCS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_PP_EngR_AB_FFCS",
            ["mm"] = 0,
        }, -- end of ["Failure_PP_EngR_AB_FFCS"]
        ["FCS_FAILURE_LG_4"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_LG_4",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_LG_4"]
        ["Failure_Ctrl_FCS_Ch4"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Ctrl_FCS_Ch4",
            ["mm"] = 0,
        }, -- end of ["Failure_Ctrl_FCS_Ch4"]
        ["ENG_ALT_1_FAIL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG_ALT_1_FAIL",
            ["mm"] = 0,
        }, -- end of ["ENG_ALT_1_FAIL"]
        ["LGear_ext_fault"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LGear_ext_fault",
            ["mm"] = 0,
        }, -- end of ["LGear_ext_fault"]
        ["pp_damage_OilSeparator"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pp_damage_OilSeparator",
            ["mm"] = 0,
        }, -- end of ["pp_damage_OilSeparator"]
        ["NGear_ext_fault"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "NGear_ext_fault",
            ["mm"] = 0,
        }, -- end of ["NGear_ext_fault"]
        ["GUN_RIGHT_CENTER_AMMUN_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_RIGHT_CENTER_AMMUN_FAULT",
            ["mm"] = 0,
        }, -- end of ["GUN_RIGHT_CENTER_AMMUN_FAULT"]
        ["MWMMC_FAILURE_1553B_INS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_1553B_INS",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_1553B_INS"]
        ["sas_pitch_right"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "sas_pitch_right",
            ["mm"] = 0,
        }, -- end of ["sas_pitch_right"]
        ["RPMSENSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RPMSENSOR",
            ["mm"] = 0,
        }, -- end of ["RPMSENSOR"]
        ["engine_antiice_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "engine_antiice_fail",
            ["mm"] = 0,
        }, -- end of ["engine_antiice_fail"]
        ["INST_TACH1_RESISTANCE_MISMATCH"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_TACH1_RESISTANCE_MISMATCH",
            ["mm"] = 0,
        }, -- end of ["INST_TACH1_RESISTANCE_MISMATCH"]
        ["INST_VARIOMETR_DEPRESSURIZATION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_VARIOMETR_DEPRESSURIZATION",
            ["mm"] = 0,
        }, -- end of ["INST_VARIOMETR_DEPRESSURIZATION"]
        ["AN_ALR69V_FAILURE_SENSOR_NOSE_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AN_ALR69V_FAILURE_SENSOR_NOSE_RIGHT",
            ["mm"] = 0,
        }, -- end of ["AN_ALR69V_FAILURE_SENSOR_NOSE_RIGHT"]
        ["VHF_CRYSTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VHF_CRYSTAL",
            ["mm"] = 0,
        }, -- end of ["VHF_CRYSTAL"]
        ["VHF_ARC_182_FAILURE_REMOTE_DISPLAY"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VHF_ARC_182_FAILURE_REMOTE_DISPLAY",
            ["mm"] = 0,
        }, -- end of ["VHF_ARC_182_FAILURE_REMOTE_DISPLAY"]
        ["GUN_LEFT_CENTER_AMMUN_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_LEFT_CENTER_AMMUN_FAULT",
            ["mm"] = 0,
        }, -- end of ["GUN_LEFT_CENTER_AMMUN_FAULT"]
        ["Failure_Fuel_ExtTankTransferR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Fuel_ExtTankTransferR",
            ["mm"] = 0,
        }, -- end of ["Failure_Fuel_ExtTankTransferR"]
        ["EMMC_FAILURE_AC_GENERATOR_CONTROLLER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_AC_GENERATOR_CONTROLLER",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_AC_GENERATOR_CONTROLLER"]
        ["R_GEAR_UPL_NOT_LOCK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_GEAR_UPL_NOT_LOCK",
            ["mm"] = 0,
        }, -- end of ["R_GEAR_UPL_NOT_LOCK"]
        ["ENGINE_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENGINE_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ENGINE_FAILURE"]
        ["EMMC_FAILURE_DC_GENERATOR_SUBSYSTEM"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_DC_GENERATOR_SUBSYSTEM",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_DC_GENERATOR_SUBSYSTEM"]
        ["FR22RADIO"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FR22RADIO",
            ["mm"] = 0,
        }, -- end of ["FR22RADIO"]
        ["ppf_RightGearbox"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ppf_RightGearbox",
            ["mm"] = 0,
        }, -- end of ["ppf_RightGearbox"]
        ["fs_damage_FuelBoosterPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fs_damage_FuelBoosterPump",
            ["mm"] = 0,
        }, -- end of ["fs_damage_FuelBoosterPump"]
        ["Failure_Fuel_Tank1Transfer"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Fuel_Tank1Transfer",
            ["mm"] = 0,
        }, -- end of ["Failure_Fuel_Tank1Transfer"]
        ["CARBAIR_SHORT_CIRCUIT_LEADS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CARBAIR_SHORT_CIRCUIT_LEADS",
            ["mm"] = 0,
        }, -- end of ["CARBAIR_SHORT_CIRCUIT_LEADS"]
        ["PNEM_BRAKE_RELAY_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PNEM_BRAKE_RELAY_FAILURE",
            ["mm"] = 0,
        }, -- end of ["PNEM_BRAKE_RELAY_FAILURE"]
        ["FCS_FAILURE_PITCH_LVDT_1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_PITCH_LVDT_1",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_PITCH_LVDT_1"]
        ["FWD_TANK_PUMP_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FWD_TANK_PUMP_FAULT",
            ["mm"] = 0,
        }, -- end of ["FWD_TANK_PUMP_FAULT"]
        ["GUN_RIGHT_CENTER_OPEN_CIRCUIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GUN_RIGHT_CENTER_OPEN_CIRCUIT",
            ["mm"] = 0,
        }, -- end of ["GUN_RIGHT_CENTER_OPEN_CIRCUIT"]
        ["Failure_Comp_MC1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Comp_MC1",
            ["mm"] = 0,
        }, -- end of ["Failure_Comp_MC1"]
        ["ILS_FAILURE_ANT_MARKER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ILS_FAILURE_ANT_MARKER",
            ["mm"] = 0,
        }, -- end of ["ILS_FAILURE_ANT_MARKER"]
        ["VDI_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VDI_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["VDI_FAILURE_TOTAL"]
        ["GMC1AE_GYRO_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GMC1AE_GYRO_FAILURE",
            ["mm"] = 0,
        }, -- end of ["GMC1AE_GYRO_FAILURE"]
        ["esf_RightGenerator"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "esf_RightGenerator",
            ["mm"] = 0,
        }, -- end of ["esf_RightGenerator"]
        ["es_damage_VU1"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "es_damage_VU1",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["es_damage_VU1"]
        ["ELEC_C5_LAMP_1_POOR_CONTACT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_C5_LAMP_1_POOR_CONTACT",
            ["mm"] = 0,
        }, -- end of ["ELEC_C5_LAMP_1_POOR_CONTACT"]
        ["SAR_1_101"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SAR_1_101",
            ["mm"] = 0,
        }, -- end of ["SAR_1_101"]
        ["ENG0_JAMMED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_JAMMED",
            ["mm"] = 0,
        }, -- end of ["ENG0_JAMMED"]
        ["EXT_HYDRO_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EXT_HYDRO_LEAK",
            ["mm"] = 0,
        }, -- end of ["EXT_HYDRO_LEAK"]
        ["PNEM_MAIN_HOSE_PERFORATED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PNEM_MAIN_HOSE_PERFORATED",
            ["mm"] = 0,
        }, -- end of ["PNEM_MAIN_HOSE_PERFORATED"]
        ["BOMBS_ARMING_NO_VOLATAGE_BOTH"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_ARMING_NO_VOLATAGE_BOTH",
            ["mm"] = 0,
        }, -- end of ["BOMBS_ARMING_NO_VOLATAGE_BOTH"]
        ["ols_damage_OilPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ols_damage_OilPump",
            ["mm"] = 0,
        }, -- end of ["ols_damage_OilPump"]
        ["Failure_Hyd_HYD2B_Leak"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Hyd_HYD2B_Leak",
            ["mm"] = 0,
        }, -- end of ["Failure_Hyd_HYD2B_Leak"]
        ["RWR_FAILURE_ANTENNA_REAR_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_ANTENNA_REAR_LEFT",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_ANTENNA_REAR_LEFT"]
        ["OXYN_TOP_CONTAINER_PERFORATED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OXYN_TOP_CONTAINER_PERFORATED",
            ["mm"] = 0,
        }, -- end of ["OXYN_TOP_CONTAINER_PERFORATED"]
        ["RDR_FAILURE_PROCESSOR_OVERHEAT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RDR_FAILURE_PROCESSOR_OVERHEAT",
            ["mm"] = 0,
        }, -- end of ["RDR_FAILURE_PROCESSOR_OVERHEAT"]
        ["COOLANT_RADIATOR_MOTOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COOLANT_RADIATOR_MOTOR",
            ["mm"] = 0,
        }, -- end of ["COOLANT_RADIATOR_MOTOR"]
        ["FAILURE_EXT_LIGHT_NAV_TAIL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_EXT_LIGHT_NAV_TAIL",
            ["mm"] = 0,
        }, -- end of ["FAILURE_EXT_LIGHT_NAV_TAIL"]
        ["AAR_47_FAILURE_SENSOR_TAIL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AAR_47_FAILURE_SENSOR_TAIL",
            ["mm"] = 0,
        }, -- end of ["AAR_47_FAILURE_SENSOR_TAIL"]
        ["INS_FAILURE_GPS_RECEIVER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_FAILURE_GPS_RECEIVER",
            ["mm"] = 0,
        }, -- end of ["INS_FAILURE_GPS_RECEIVER"]
        ["SAR_fast"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "SAR_fast",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["SAR_fast"]
        ["COOLANT_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COOLANT_LEAK",
            ["mm"] = 0,
        }, -- end of ["COOLANT_LEAK"]
        ["CTRL_AILERON_TRIM_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_AILERON_TRIM_FAILURE",
            ["mm"] = 0,
        }, -- end of ["CTRL_AILERON_TRIM_FAILURE"]
        ["RWR_FAILURE_LOW_BAND"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_LOW_BAND",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_LOW_BAND"]
        ["INST_TACH1_LOOM_SEVERED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_TACH1_LOOM_SEVERED",
            ["mm"] = 0,
        }, -- end of ["INST_TACH1_LOOM_SEVERED"]
        ["FAILURE_EXT_LIGHT_NAV_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_EXT_LIGHT_NAV_RIGHT",
            ["mm"] = 0,
        }, -- end of ["FAILURE_EXT_LIGHT_NAV_RIGHT"]
        ["RWR_FAILURE_QUAD135"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_QUAD135",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_QUAD135"]
        ["RIGHT_CYLINDER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RIGHT_CYLINDER",
            ["mm"] = 0,
        }, -- end of ["RIGHT_CYLINDER"]
        ["ROCKETS_INTERVALOMETER_SEQ"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ROCKETS_INTERVALOMETER_SEQ",
            ["mm"] = 0,
        }, -- end of ["ROCKETS_INTERVALOMETER_SEQ"]
        ["ppf_RightOil"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ppf_RightOil",
            ["mm"] = 0,
        }, -- end of ["ppf_RightOil"]
        ["Failure_Ctrl_FCS_Ch2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Ctrl_FCS_Ch2",
            ["mm"] = 0,
        }, -- end of ["Failure_Ctrl_FCS_Ch2"]
        ["SAR_2_101"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SAR_2_101",
            ["mm"] = 0,
        }, -- end of ["SAR_2_101"]
        ["DEFECTIVE_MECHANISM"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DEFECTIVE_MECHANISM",
            ["mm"] = 0,
        }, -- end of ["DEFECTIVE_MECHANISM"]
        ["FUEL_TANK_00_MINOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_00_MINOR_LEAK",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_00_MINOR_LEAK"]
        ["FAULTY_ROCKET_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAULTY_ROCKET_RIGHT",
            ["mm"] = 0,
        }, -- end of ["FAULTY_ROCKET_RIGHT"]
        ["ELEC_MSB_CB_BUSTED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_MSB_CB_BUSTED",
            ["mm"] = 0,
        }, -- end of ["ELEC_MSB_CB_BUSTED"]
        ["hsf_UtilityHydraulic"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hsf_UtilityHydraulic",
            ["mm"] = 0,
        }, -- end of ["hsf_UtilityHydraulic"]
        ["BOMBS_ARMING_BROKEN_WIRING_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_ARMING_BROKEN_WIRING_RIGHT",
            ["mm"] = 0,
        }, -- end of ["BOMBS_ARMING_BROKEN_WIRING_RIGHT"]
        ["MainReductor_LowOilPressure"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MainReductor_LowOilPressure",
            ["mm"] = 0,
        }, -- end of ["MainReductor_LowOilPressure"]
        ["OESP_FAILURE_FL_DISP_R"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OESP_FAILURE_FL_DISP_R",
            ["mm"] = 0,
        }, -- end of ["OESP_FAILURE_FL_DISP_R"]
        ["BOMBS_RUST_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_RUST_RIGHT",
            ["mm"] = 0,
        }, -- end of ["BOMBS_RUST_RIGHT"]
        ["CLOGGED_FUEL_STRAINER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CLOGGED_FUEL_STRAINER",
            ["mm"] = 0,
        }, -- end of ["CLOGGED_FUEL_STRAINER"]
        ["ACCSENSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ACCSENSOR",
            ["mm"] = 0,
        }, -- end of ["ACCSENSOR"]
        ["es_damage_SpareInverter"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_SpareInverter",
            ["mm"] = 0,
        }, -- end of ["es_damage_SpareInverter"]
        ["Failure_Elec_RightTransformerRectifier"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Elec_RightTransformerRectifier",
            ["mm"] = 0,
        }, -- end of ["Failure_Elec_RightTransformerRectifier"]
        ["HYD_PUMP_2_FAIL_100"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYD_PUMP_2_FAIL_100",
            ["mm"] = 0,
        }, -- end of ["HYD_PUMP_2_FAIL_100"]
        ["ELEC_OIL_GAUGE_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_OIL_GAUGE_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_OIL_GAUGE_FAILURE"]
        ["UNCR_RH_STRUT_DOWN_LOCK_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UNCR_RH_STRUT_DOWN_LOCK_FAILURE",
            ["mm"] = 0,
        }, -- end of ["UNCR_RH_STRUT_DOWN_LOCK_FAILURE"]
        ["FAILURE_EXT_LIGHT_ANTICOL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_EXT_LIGHT_ANTICOL",
            ["mm"] = 0,
        }, -- end of ["FAILURE_EXT_LIGHT_ANTICOL"]
        ["A11_CLOCK_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "A11_CLOCK_FAILURE",
            ["mm"] = 0,
        }, -- end of ["A11_CLOCK_FAILURE"]
        ["ELEC_MSB_CONTROLS_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_MSB_CONTROLS_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_MSB_CONTROLS_FAILURE"]
        ["FAILURE_HYDRAULICS_2_INTERNAL_LEAKAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_HYDRAULICS_2_INTERNAL_LEAKAGE",
            ["mm"] = 0,
        }, -- end of ["FAILURE_HYDRAULICS_2_INTERNAL_LEAKAGE"]
        ["SWMMC_FAILURE_CTVS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_CTVS",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_CTVS"]
        ["FAILURE_SNS_CABLE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_SNS_CABLE",
            ["mm"] = 0,
        }, -- end of ["FAILURE_SNS_CABLE"]
        ["RWR_FAILURE_RECEIVER_XX2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_RECEIVER_XX2",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_RECEIVER_XX2"]
        ["HYDR_ACCUMULATOR_LOW_AIR_PRESSURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYDR_ACCUMULATOR_LOW_AIR_PRESSURE",
            ["mm"] = 0,
        }, -- end of ["HYDR_ACCUMULATOR_LOW_AIR_PRESSURE"]
        ["FUELTANK3L"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUELTANK3L",
            ["mm"] = 0,
        }, -- end of ["FUELTANK3L"]
        ["RDR_FAILURE_ARRAY"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RDR_FAILURE_ARRAY",
            ["mm"] = 0,
        }, -- end of ["RDR_FAILURE_ARRAY"]
        ["INS_TOTAL_FAIL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_TOTAL_FAIL",
            ["mm"] = 0,
        }, -- end of ["INS_TOTAL_FAIL"]
        ["BOMBS_ARMING_NO_VOLATAGE_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOMBS_ARMING_NO_VOLATAGE_RIGHT",
            ["mm"] = 0,
        }, -- end of ["BOMBS_ARMING_NO_VOLATAGE_RIGHT"]
        ["csf_YawDamper"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "csf_YawDamper",
            ["mm"] = 0,
        }, -- end of ["csf_YawDamper"]
        ["Failure_Fuel_ExtTankTransferC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Fuel_ExtTankTransferC",
            ["mm"] = 0,
        }, -- end of ["Failure_Fuel_ExtTankTransferC"]
        ["FCS_FAILURE_R_ELEVATOR_ELEC_C"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FCS_FAILURE_R_ELEVATOR_ELEC_C",
            ["mm"] = 0,
        }, -- end of ["FCS_FAILURE_R_ELEVATOR_ELEC_C"]
    }, -- end of ["failures"]
} -- end of mission
