mission = 
{
    ["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"]
    ["maxDictId"] = 5,
    ["trig"] = 
    {
        ["actions"] = 
        {
            [1] = "a_do_script(\"dcsCommon = {}\\\
dcsCommon.version = \\\"2.8.8\\\"\\\
--[[-- 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 understands 'red' and 'blue'\\\
 2.5.0 - \\\"Line\\\" formation with one unit places unit at center     \\\
 2.5.1 - vNorm(a)  \\\
 2.5.1 - added SA-18 Igla manpad to unitIsInfantry()\\\
 2.5.2 - added copyArray method\\\
       - corrected heading in createStaticObjectData\\\
 2.5.3 - corrected rotateGroupData bug for cz \\\
       - removed forced error in failed pickRandom\\\
 2.5.4 - rotateUnitData()\\\
       - randomBetween()\\\
 2.5.5 - stringStartsWithDigit()\\\
       - stringStartsWithLetter()\\\
       - stringIsPositiveNumber()\\\
 2.5.6 - corrected stringEndsWith() bug with str\\\
 2.5.7 - point2text(p) \\\
 2.5.8 - string2GroupCat()\\\
 2.5.9 - string2ObjectCat()\\\
 2.6.0 - unified uuid, removed uuIdent\\\
 2.6.1 - removed bug in rotateUnitData: cy --> cz param passing  \\\
 2.6.2 - new combineTables()\\\
 2.6.3 - new tacan2freq()\\\
 2.6.4 - new processHMS()\\\
 2.6.5 - new bearing2compass()\\\
       - new bearingdegrees2compass()\\\
       - new latLon2Text() - based on mist \\\
 2.6.6 - new nowString() \\\
       - new str2num()\\\
       - new stringRemainsStartingWith()\\\
       - new stripLF()\\\
       - new removeBlanks()\\\
 2.6.7 - new menu2text()\\\
 2.6.8 - new getMissionName()\\\
       - new flagArrayFromString()\\\
 2.6.9 - new getSceneryObjectsInZone()\\\
       - new getSceneryObjectInZoneByName()\\\
 2.7.0 - new synchGroupData()\\\
         clone, topClone and copyArray now all nil-trap \\\
 2.7.1 - new isPlayerUnit() -- moved from cfxPlayer\\\
         new getAllExistingPlayerUnitsRaw - from cfxPlayer\\\
         new typeIsInfantry()\\\
 2.7.2 - new rangeArrayFromString()\\\
         fixed leading blank bug in flagArrayFromString\\\
         new incFlag()\\\
         new decFlag()\\\
         nil trap in stringStartsWith()\\\
         new getClosestFreeSlotForCatInAirbaseTo()\\\
 2.7.3 - new string2Array()\\\
       - additional guard for isPlayerUnit\\\
 2.7.4 - new array2string()\\\
 2.7.5 - new bitAND32()\\\
       - new LSR()\\\
       - new num2bin()\\\
 2.7.6 - new getObjectsForCatAtPointWithRadius()\\\
 2.7.7 - clone() has new stripMeta option. pass true to remove all meta tables \\\
       - dumpVar2Str detects meta tables \\\
       - rotateGroupData kills unit's psi value if it existed since it messes with heading \\\
       - rotateGroupData - changes psi to -heading if it exists rather than nilling\\\
 2.7.8 - new getGeneralDirection()\\\
       - new getNauticalDirection()\\\
       - more robust guards for getUnitSpeed\\\
 2.7.9 - new bool2Num(theBool)\\\
       - new aspectByDirection()\\\
       - createGroundGroupWithUnits corrected spelling of minDist, crashed scattered formation\\\
       - randomPointInCircle fixed erroneous local for x, z \\\
       - \\\"scattered\\\" formation repaired\\\
 2.7.10- semaphore groundwork \\\
 2.8.0 - new collectMissionIDs at start-up  \\\
       - new getUnitNameByID\\\
       - new getGroupNameByID\\\
       - bool2YesNo alsco can return NIL\\\
       - new getUnitStartPosByID\\\
 2.8.1 - arrayContainsString: type checking for theArray and warning\\\
       - processStringWildcards()\\\
       - new wildArrayContainsString() \\\
       - fix for stringStartsWith oddity with aircraft types \\\
 2.8.2 - better fixes for string.find() in stringStartsWith and containsString\\\
       - dcsCommon.isTroopCarrier(theUnit, carriers) new carriers optional param\\\
       - better guards for getUnitAlt and getUnitAGL\\\
       - new newPointAtDegreesRange()\\\
       - new newPointAtAngleRange()\\\
       - new isTroopCarrierType()\\\
       - stringStartsWith now supports case insensitive match \\\
       - isTroopCarrier() supports 'any' and 'all'\\\
       - made getEnemyCoalitionFor() more resilient \\\
       - fix to smallRandom for negative numbers\\\
       - isTroopCarrierType uses wildArrayContainsString\\\
 2.8.3 - small optimizations in bearingFromAtoB()\\\
       - new whichSideOfMine()\\\
 2.8.4 - new rotatePointAroundOriginRad()\\\
       - new rotatePointAroundPointDeg()\\\
       - new rotatePointAroundPointRad()\\\
       - getClosestAirbaseTo() now supports passing list of air bases\\\
 2.8.5 - better guard in getGroupUnit()\\\
 2.8.6 - phonetic helpers \\\
         new spellString()\\\
 2.8.7 - new flareColor2Num()\\\
       - new flareColor2Text()\\\
       - new iteratePlayers()\\\
 2.8.8 - new hexString2RGBA()\\\
       - new playerName2Coalition()\\\
       - new coalition2Text()\\\
--]]--\\\
\\\
    -- dcsCommon is a library of common lua functions \\\
    -- for easy access and simple mission programming\\\
    -- (c) 2021 - 2023 by Chritian Franz and cf/x AG\\\
\\\
    dcsCommon.verbose = false -- set to true to see debug messages. Lots of them\\\
    dcsCommon.uuidStr = \\\"uuid-\\\"\\\
    dcsCommon.simpleUUID = 76543 -- a number to start. as good as any\\\
    \\\
    -- globals\\\
    dcsCommon.cbID = 0 -- callback id for simple callback scheduling\\\
    dcsCommon.troopCarriers = {\\\"Mi-8MT\\\", \\\"UH-1H\\\", \\\"Mi-24P\\\"} -- Ka-50, Apache and Gazelle can't carry troops\\\
    dcsCommon.coalitionSides = {0, 1, 2}\\\
    \\\
    -- lookup tables\\\
    dcsCommon.groupID2Name = {}\\\
    dcsCommon.unitID2Name = {}\\\
    dcsCommon.unitID2X = {}\\\
    dcsCommon.unitID2Y = {}\\\
\\\
    -- 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\\\
\\\
    -- read all groups and units from miz and build a reference table\\\
    function dcsCommon.collectMissionIDs()\\\
    -- create cross reference tables to be able to get a group or\\\
    -- unit's name by ID\\\
        for coa_name_miz, coa_data in pairs(env.mission.coalition) do -- iterate all coalitions\\\
            local coa_name = coa_name_miz\\\
            if string.lower(coa_name_miz) == 'neutrals' then -- remove 's' at neutralS\\\
                coa_name = 'neutral'\\\
            end\\\
            -- directly convert coalition into number for easier access later\\\
            local coaNum = 0\\\
            if coa_name == \\\"red\\\" then coaNum = 1 end \\\
            if coa_name == \\\"blue\\\" then coaNum = 2 end \\\
            \\\
            if type(coa_data) == 'table' then -- coalition = {bullseye, nav_points, name, county}, \\\
                                              -- with county being an array \\\
                if coa_data.country then -- make sure there a country table for this coalition\\\
                    for cntry_id, cntry_data in pairs(coa_data.country) do -- iterate all countries for this \\\
                        -- per country = {id, name, vehicle, helicopter, plane, ship, static}\\\
                        local countryName = string.lower(cntry_data.name)\\\
                        local countryID = cntry_data.id \\\
                        if type(cntry_data) == 'table' then    -- filter strings .id and .name \\\
                            for obj_type_name, obj_type_data in pairs(cntry_data) do\\\
                                -- only look at helos, ships, planes and vehicles\\\
                                if obj_type_name == \\\"helicopter\\\" or \\\
                                   obj_type_name == \\\"ship\\\" or \\\
                                   obj_type_name == \\\"plane\\\" or \\\
                                   obj_type_name == \\\"vehicle\\\" or \\\
                                   obj_type_name == \\\"static\\\" -- what about \\\"cargo\\\"?\\\
                                then -- (so it's not id or name)\\\
                                    local category = obj_type_name\\\
                                    if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then    --there's at least one group!\\\
                                        for group_num, group_data in pairs(obj_type_data.group) do\\\
                                            \\\
                                            local aName = group_data.name \\\
                                            local aID = group_data.groupId\\\
                                            -- store this reference \\\
                                            dcsCommon.groupID2Name[aID] = aName \\\
                                            \\\
                                            -- now iterate all units in this group \\\
                                            -- for player into \\\
                                            for unit_num, unit_data in pairs(group_data.units) do\\\
                                                if unit_data.name and unit_data.unitId then \\\
                                                    -- store this reference \\\
                                                    dcsCommon.unitID2Name[unit_data.unitId] = unit_data.name\\\
                                                    dcsCommon.unitID2X[unit_data.unitId] = unit_data.x\\\
                                                    dcsCommon.unitID2Y[unit_data.unitId] = unit_data.y\\\
                                                end\\\
                                            end -- for all units\\\
                                        end -- for all groups \\\
                                    end --if has category data \\\
                                end --if plane, helo etc... category\\\
                            end --for all objects in country \\\
                        end --if has country data \\\
                    end --for all countries in coalition\\\
                end --if coalition has country table \\\
            end -- if there is coalition data  \\\
        end --for all coalitions in mission \\\
    end\\\
\\\
    function dcsCommon.getUnitNameByID(theID)\\\
        -- accessor function for later expansion\\\
        return dcsCommon.unitID2Name[theID]\\\
    end\\\
    \\\
    function dcsCommon.getGroupNameByID(theID)\\\
        -- accessor function for later expansion \\\
        return dcsCommon.groupID2Name[theID]\\\
    end\\\
\\\
    function dcsCommon.getUnitStartPosByID(theID)\\\
        local x = dcsCommon.unitID2X[theID]\\\
        local y = dcsCommon.unitID2Y[theID]\\\
        return x, y\\\
    end\\\
    \\\
    -- returns only positive values, lo must be >0 and <= hi \\\
    function dcsCommon.randomBetween(loBound, hiBound)\\\
        if not loBound then loBound = 1 end \\\
        if not hiBound then hiBound = 1 end \\\
        if loBound == hiBound then return loBound end \\\
\\\
        local delayMin = loBound\\\
        local delayMax = hiBound \\\
        local delay = delayMax \\\
    \\\
        if delayMin ~= delayMax then \\\
            -- pick random in range , say 3-7 --> 5 s!\\\
            local delayDiff = (delayMax - delayMin) + 1 -- 7-3 + 1\\\
            delay = dcsCommon.smallRandom(delayDiff) - 1 --> 0-4\\\
            delay = delay + delayMin \\\
            if delay > delayMax then delay = delayMax end \\\
            if delay < 1 then delay = 1 end \\\
        \\\
            if dcsCommon.verbose then \\\
                trigger.action.outText(\\\"+++dcsC: delay range \\\" .. delayMin .. \\\"-\\\" .. delayMax .. \\\": selected \\\" .. delay, 30)\\\
            end\\\
        end\\\
        \\\
        return delay\\\
    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\\\
        theNum = math.floor(theNum)\\\
        if theNum >= 50 then return math.random(theNum) end\\\
        if theNum < 1 then\\\
            trigger.action.outText(\\\"smallRandom: invoke with argument < 1 (\\\" .. theNum .. \\\"), using 1\\\", 30)\\\
            theNum = 1 \\\
        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\\\
\\\
    -- combine table. creates new \\\
    function dcsCommon.combineTables(inOne, inTwo)\\\
        local outTable = {}\\\
        for idx, element in pairs(inOne) do \\\
            table.insert(outTable, element)\\\
        end\\\
        for idx, element in pairs(inTwo) do \\\
            table.insert(outTable, element)\\\
        end\\\
        return outTable\\\
    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, allYourBase)\\\
        local delta = math.huge\\\
        if not allYourBase then \\\
            allYourBase = dcsCommon.getAirbasesWhoseNameContains(\\\"*\\\", filterCat, filterCoalition) -- get em all and filter\\\
        end \\\
        \\\
        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\\\
\\\
    function dcsCommon.getClosestFreeSlotForCatInAirbaseTo(cat, x, y, theAirbase, ignore)\\\
        if not theAirbase then return nil end \\\
        if not ignore then ignore = {} end \\\
        if not cat then return nil end \\\
        if (not cat == \\\"helicopter\\\") and (not cat == \\\"plane\\\") then \\\
            trigger.action.outText(\\\"+++common-getslotforcat: wrong cat <\\\" .. cat .. \\\">\\\", 30)\\\
            return nil \\\
        end\\\
        local allFree = theAirbase:getParking(true) --  only free slots\\\
        local filterFreeByType = {}\\\
        for idx, aSlot in pairs(allFree) do \\\
            local termT = aSlot.Term_Type\\\
            if termT == 104 or \\\
            (termT == 72 and cat == \\\"plane\\\") or \\\
            (termT == 68 and cat == \\\"plane\\\") or \\\
            (termT == 40 and cat == \\\"helicopter\\\") then \\\
                table.insert(filterFreeByType, aSlot)\\\
            else \\\
                -- we skip this slot, not good for type \\\
            end\\\
        end\\\
        \\\
        if #filterFreeByType == 0 then \\\
            return nil\\\
        end \\\
        \\\
        local reallyFree = {}\\\
        for idx, aSlot in pairs(filterFreeByType) do \\\
            local slotNum = aSlot.Term_Index\\\
            isTaken = false \\\
            for idy, taken in pairs(ignore) do \\\
                if taken == slotNum then isTaken = true end \\\
            end\\\
            if not isTaken then \\\
                table.insert(reallyFree, aSlot)\\\
            end\\\
        end\\\
        \\\
        if #reallyFree < 1 then \\\
            reallyFree = filterFreeByType\\\
        end\\\
        \\\
        local closestDist = math.huge \\\
        local closestSlot = nil \\\
        local p = {x = x, y = 0, z = y} -- !!\\\
        for idx, aSlot in pairs(reallyFree) do \\\
            local sp = {x = aSlot.vTerminalPos.x, y = 0, z = aSlot.vTerminalPos.z}\\\
            local currDist = dcsCommon.distFlat(p, sp)\\\
            --trigger.action.outText(\\\"slot <\\\" .. aSlot.Term_Index .. \\\"> has dist \\\" .. math.floor(currDist) .. \\\" and _0 of <\\\" .. aSlot.Term_Index_0 .. \\\">\\\", 30)\\\
            if currDist < closestDist then \\\
                closestSlot = aSlot \\\
                closestDist = currDist \\\
            end\\\
        end\\\
        --trigger.action.outText(\\\"slot <\\\" .. closestSlot.Term_Index .. \\\"> has closest dist <\\\" .. math.floor(closestDist) .. \\\">\\\", 30)\\\
        return closestSlot\\\
    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 \\\
        if not A then \\\
            trigger.action.outText(\\\"WARNING: no 'A' in bearingFromAtoB\\\", 30)\\\
            return 0\\\
        end\\\
        if not B then\\\
            trigger.action.outText(\\\"WARNING: no 'A' in bearingFromAtoB\\\", 30)\\\
            return 0\\\
        end\\\
        if not A.x then \\\
            trigger.action.outText(\\\"WARNING: no 'A.x' (type A =<\\\" .. type(A) .. \\\">)in bearingFromAtoB\\\", 30)\\\
            return 0\\\
        end\\\
        if not A.y then \\\
            trigger.action.outText(\\\"WARNING: no 'A.x' (type A =<\\\" .. type(A) .. \\\">)in bearingFromAtoB\\\", 30)\\\
            return 0\\\
        end\\\
        if not B.x then \\\
            trigger.action.outText(\\\"WARNING: no 'B.x' (type B =<\\\" .. type(B) .. \\\">)in bearingFromAtoB\\\", 30)\\\
            return 0\\\
        end\\\
        if not B.y then \\\
            trigger.action.outText(\\\"WARNING: no 'B.y' (type B =<\\\" .. type(B) .. \\\">)in bearingFromAtoB\\\", 30)\\\
            return 0\\\
        end\\\
        \\\
        local dx = B.x - A.x\\\
        local dz = B.z - A.z\\\
        local 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.bearing2compass(inrad)\\\
        local bearing = math.floor(inrad / math.pi * 180)\\\
        if bearing < 0 then bearing = bearing + 360 end\\\
        if bearing > 360 then bearing = bearing - 360 end\\\
        return dcsCommon.bearingdegrees2compass(bearing)\\\
    end\\\
    \\\
    function dcsCommon.bearingdegrees2compass(bearing)\\\
        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\\\
        while direction >= 360 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.getGeneralDirection(direction) -- inspired by cws, improvements my own\\\
        if not direction then return \\\"unkown\\\" end\\\
        direction = math.fmod (direction, 360)\\\
        while direction < 0 do \\\
            direction = direction + 360\\\
        end\\\
        while direction >= 360 do \\\
            direction = direction - 360\\\
        end\\\
        if direction < 45 then return \\\"ahead\\\" end    \\\
        if direction < 135 then return \\\"right\\\" end\\\
        if direction < 225 then return \\\"behind\\\" end\\\
        if direction < 315 then return \\\"left\\\" end \\\
        return \\\"ahead\\\"\\\
    end\\\
    \\\
    function dcsCommon.getNauticalDirection(direction) -- inspired by cws, improvements my own\\\
        if not direction then return \\\"unkown\\\" end\\\
        direction = math.fmod (direction, 360)\\\
        while direction < 0 do \\\
            direction = direction + 360\\\
        end\\\
        while direction >= 360 do \\\
            direction = direction - 360\\\
        end\\\
        if direction < 45 then return \\\"ahead\\\" end    \\\
        if direction < 135 then return \\\"starboard\\\" end\\\
        if direction < 225 then return \\\"aft\\\" end\\\
        if direction < 315 then return \\\"port\\\" end \\\
        return \\\"ahead\\\"\\\
    end\\\
\\\
    function dcsCommon.aspectByDirection(direction) -- inspired by cws, improvements my own\\\
        if not direction then return \\\"unkown\\\" end\\\
        direction = math.fmod (direction, 360)\\\
        while direction < 0 do \\\
            direction = direction + 360\\\
        end\\\
        while direction >= 360 do \\\
            direction = direction - 360\\\
        end\\\
        \\\
        if direction < 45 then return \\\"hot\\\" end    \\\
        if direction < 135 then return \\\"beam\\\" end\\\
        if direction < 225 then return \\\"drag\\\" end\\\
        if direction < 315 then return \\\"beam\\\" end \\\
        return \\\"hot\\\"\\\
    end\\\
    \\\
    function dcsCommon.whichSideOfMine(theUnit, target) -- returs two values: -1/1 = left/right and \\\"left\\\"/\\\"right\\\" \\\
        if not theUnit then return nil end \\\
        if not target then return nil end \\\
        local uDOF = theUnit:getPosition() -- returns p, x, y, z Vec3\\\
        -- with x, y, z being the normalised vectors for right, up, forward \\\
        local heading = math.atan2(uDOF.x.z, uDOF.x.x) -- returns rads\\\
        if heading < 0 then\\\
            heading = heading + 2 * math.pi    -- put heading in range of 0 to 2*pi\\\
        end\\\
        -- heading now runs from 0 through 2Pi\\\
        local A = uDOF.p\\\
        local B = target:getPoint() \\\
         \\\
        -- now get bearing from theUnit to target  \\\
        local dx = B.x - A.x\\\
        local dz = B.z - A.z\\\
        local bearing = math.atan2(dz, dx) -- in rads\\\
        if bearing < 0 then\\\
            bearing = bearing + 2 * math.pi    -- make bearing 0 to 2*pi\\\
        end\\\
\\\
        -- we now have bearing to B, and own heading. \\\
        -- subtract own heading from bearing to see at what \\\
        -- bearing target would be if we 'turned the world' so\\\
        -- that theUnit is heading 0\\\
        local dBearing = bearing - heading\\\
        -- if result < 0 or > Pi (=180°), target is left from us\\\
        if dBearing < 0 or dBearing > math.pi then return -1, \\\"left\\\" end\\\
        return 1, \\\"right\\\"\\\
        -- note: no separate case for straight in front or behind\\\
    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\\\
        if not z then z = 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 \\\
        x = x + (innerRadius + r) * math.cos(degrees)\\\
        z = z + (innerRadius + r) * math.sin(degrees)\\\
    \\\
        local thePoint = {}\\\
        thePoint.x = x\\\
        thePoint.y = 0\\\
        thePoint.z = z \\\
        \\\
        return thePoint, degrees\\\
    end\\\
\\\
    function dcsCommon.newPointAtDegreesRange(p1, degrees, radius)\\\
        local rads = degrees * 3.14152 / 180\\\
        local p2 = dcsCommon.newPointAtAngleRange(p1, rads, radius)\\\
        return p2 \\\
    end\\\
    \\\
    function dcsCommon.newPointAtAngleRange(p1, angle, radius)\\\
        local p2 = {}\\\
        p2.x = p1.x + radius * math.cos(angle)\\\
        p2.y = p1.y \\\
        p2.z = p1.z + radius * math.sin(angle)\\\
        return p2 \\\
    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 Unit.isExist(theUnit) 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 type(aCoalition) == \\\"string\\\" then \\\
            aCoalition = aCoalition:lower()\\\
            if aCoalition == \\\"red\\\" then return 2 end\\\
            if aCoalition == \\\"blue\\\" then return 1 end\\\
            return nil \\\
        end\\\
        if aCoalition == 1 then return 2 end\\\
        if aCoalition == 2 then return 1 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)\\\
        if not orig then return nil end \\\
        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, stripMeta)\\\
        if not orig then return nil end \\\
        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\\\
            if not stripMeta then \\\
                -- also connect meta data\\\
                setmetatable(copy, dcsCommon.clone(getmetatable(orig)))\\\
            else \\\
                -- strip all except string, and for strings use a fresh string \\\
                if type(copy) == \\\"string\\\" then \\\
                    local tmp = \\\"\\\"\\\
                    tmp = tmp .. copy -- will get rid of any foreign metas for string \\\
                    copy = tmp \\\
                end\\\
            end\\\
        else -- number, string, boolean, etc\\\
            copy = orig\\\
        end\\\
        return copy\\\
    end\\\
\\\
    function dcsCommon.copyArray(inArray)\\\
        if not inArray then return nil end \\\
        \\\
        -- warning: this is a ref copy!\\\
        local theCopy = {}\\\
        for idx, element in pairs(inArray) do \\\
            table.insert(theCopy, element)\\\
        end\\\
        return theCopy \\\
    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)\\\
            -- if only one, place in middle of circle and be done \\\
            if num == 1 then \\\
                -- nothing. just stay in the middle \\\
            else \\\
                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    \\\
            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 until mindistance to all is kept or emergencybreak\\\
                    thePoint = dcsCommon.randomPointInCircle(radius, innerRadius) -- returns x, 0, z\\\
                    -- check if too close to others\\\
                    for idx, rUnit in pairs(processedUnits) do -- get min dist to all positioned units\\\
                        --trigger.action.outText(\\\"rPnt: thePoint =  \\\" .. dcsCommon.point2text(thePoint), 30)\\\
                        uPoint.x = rUnit.x\\\
                        uPoint.y = 0\\\
                        uPoint.z = rUnit.y \\\
                        --trigger.action.outText(\\\"rPnt: uPoint =  \\\" .. dcsCommon.point2text(uPoint), 30)\\\
                        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(\\\"+++dcsC: creating unit \\\" .. name .. \\\"-\\\" .. num .. \\\": \\\" .. theType, 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.rotatePointAroundOriginRad(inX, inY, angle) -- angle in degrees\\\
        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.rotatePointAroundOrigin(inX, inY, angle) -- angle in degrees\\\
        local rads =  3.14152 / 180 -- convert to radiants. \\\
        angle = angle * rads -- turns into rads\\\
        local px, py = dcsCommon.rotatePointAroundOriginRad(inX, inY, angle)\\\
        return px, py        \\\
    end\\\
    \\\
    function dcsCommon.rotatePointAroundPointRad(x, y, px, py, angle)\\\
        x = x - px \\\
        y = y - py\\\
        x, y = dcsCommon.rotatePointAroundOriginRad(x, y, angle)\\\
        x = x + px \\\
        y = y + py \\\
        return x, y\\\
    end\\\
\\\
    function dcsCommon.rotatePointAroundPointDeg(x, y, px, py, degrees)\\\
        x, y = dcsCommon.rotatePointAroundPointRad(x, y, px, py, degrees * 3.14152 / 180)\\\
        return x, y\\\
    end\\\
\\\
    -- rotates a Vec3-base inPoly on XZ pane around inPoint on XZ pane\\\
     function dcsCommon.rotatePoly3AroundVec3Rad(inPoly, inPoint, rads)\\\
        local outPoly = {}\\\
        for idx, aVertex in pairs(inPoly) do \\\
            local x, z = dcsCommon.rotatePointAroundPointRad(aVertex.x, aVertex.z, inPoint.x, inPoint.z, rads)        \\\
            local v3 = {x = x, y = aVertex.y, z = z}\\\
            outPoly[idx] = v3\\\
        end \\\
        return outPoly \\\
    end\\\
\\\
    function dcsCommon.rotateUnitData(theUnit, degrees, cx, cz)\\\
        if not cx then cx = 0 end\\\
        if not cz then cz = 0 end\\\
        local cy = cz \\\
        --trigger.action.outText(\\\"+++dcsC:rotGrp cy,cy = \\\"..cx .. \\\",\\\" .. cy, 30)\\\
        \\\
        local rads = degrees *  3.14152 / 180\\\
        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 degrees\\\
            theUnit.heading = theUnit.heading + rads \\\
        end\\\
    end\\\
    \\\
\\\
    function dcsCommon.rotateGroupData(theGroup, degrees, cx, cz)\\\
        if not cx then cx = 0 end\\\
        if not cz then cz = 0 end\\\
        local cy = cz \\\
        --trigger.action.outText(\\\"+++dcsC:rotGrp cy,cy = \\\"..cx .. \\\",\\\" .. cy, 30)\\\
        \\\
        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 degrees\\\
            theUnit.heading = theUnit.heading + rads \\\
            -- now kill psi if it existed before \\\
            -- theUnit.psi = nil\\\
            -- better code: psi is always -heading. Nobody knows what psi is, though\\\
            if theUnit.psi then \\\
                theUnit.psi = -theUnit.heading \\\
            end\\\
        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 = heading\\\
        -- 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\\\
\\\
function dcsCommon.synchGroupData(inGroupData) -- update group data block by \\\
-- comparing it to spawned group and update units by x, y, heding and isExist \\\
-- modifies inGroupData!\\\
    if not inGroupData then return end \\\
    -- groupdata from game, NOT MX DATA!\\\
    -- we synch the units and their coords \\\
    local livingUnits = {}\\\
    for idx, unitData in pairs(inGroupData.units) do \\\
        local theUnit = Unit.getByName(unitData.name)\\\
        if theUnit and theUnit:isExist() and theUnit:getLife()>1 then \\\
            -- update x and y and heading\\\
            local pos = theUnit:getPoint()\\\
            unitData.unitId = theUnit:getID()\\\
            unitData.x = pos.x \\\
            unitData.y = pos.z -- !!!!\\\
            unitData.heading = dcsCommon.getUnitHeading(gUnit)\\\
            table.insert(livingUnits, unitData)\\\
        end\\\
    end\\\
    inGroupData.units = livingUnits \\\
end\\\
\\\
--\\\
--\\\
-- M I S C   M E T H O D S \\\
--\\\
--\\\
\\\
-- as arrayContainsString, except it includes wildcard matches if EITHER \\\
-- ends on \\\"*\\\"\\\
    function dcsCommon.wildArrayContainsString(theArray, theString, caseSensitive) \\\
        if not theArray then return false end\\\
        if not theString then return false end\\\
        if not caseSensitive then caseSensitive = false end \\\
        if type(theArray) ~= \\\"table\\\" then \\\
            trigger.action.outText(\\\"***arrayContainsString: theArray is not type table but <\\\" .. type(theArray) .. \\\">\\\", 30)\\\
        end\\\
        if not caseSensitive then theString = string.upper(theString) end \\\
        \\\
        --trigger.action.outText(\\\"wildACS: theString = <\\\" .. theString .. \\\">, theArray contains <\\\" .. #theArray .. \\\"> elements\\\", 30)\\\
        local wildIn = dcsCommon.stringEndsWith(theString, \\\"*\\\")\\\
        if wildIn then dcsCommon.removeEnding(theString, \\\"*\\\") end \\\
        for idx, theElement in pairs(theArray) do -- i = 1, #theArray do \\\
            --local theElement = theArray[i]\\\
            --trigger.action.outText(\\\"test e <\\\" .. theElement .. \\\"> against s <\\\" .. theString .. \\\">\\\", 30)\\\
            if not caseSensitive then theElement = string.upper(theElement) end \\\
            local wildEle = dcsCommon.stringEndsWith(theElement, \\\"*\\\")\\\
            if wildEle then theElement = dcsCommon.removeEnding(theElement, \\\"*\\\") end \\\
            --trigger.action.outText(\\\"matching s=<\\\" .. theString .. \\\"> with e=<\\\" .. theElement .. \\\">\\\", 30)\\\
            if wildEle and wildIn then \\\
                -- both end on wildcards, partial match for both\\\
                if dcsCommon.stringStartsWith(theElement, theString) then return true end \\\
                if dcsCommon.stringStartsWith(theString, theElement) then return true end \\\
                --trigger.action.outText(\\\"match e* with s* failed.\\\", 30)\\\
            elseif wildEle then \\\
                -- Element is a wildcard, partial match \\\
                if dcsCommon.stringStartsWith(theString, theElement) then return true end\\\
                --trigger.action.outText(\\\"startswith - match e* <\\\" .. theElement .. \\\"> with s <\\\" .. theString .. \\\"> failed.\\\", 30)\\\
            elseif wildIn then\\\
                -- theString is a wildcard. partial match \\\
                if dcsCommon.stringStartsWith(theElement, theString) then return true end\\\
                --trigger.action.outText(\\\"match e with s* failed.\\\", 30)\\\
            else\\\
                -- standard: no wildcards, full match\\\
                if theElement == theString then return true end \\\
                --trigger.action.outText(\\\"match e with s (straight) failed.\\\", 30)\\\
            end\\\
            \\\
        end\\\
        return false \\\
    end\\\
\\\
\\\
    function dcsCommon.arrayContainsString(theArray, theString) \\\
        if not theArray then return false end\\\
        if not theString then return false end\\\
        if type(theArray) ~= \\\"table\\\" then \\\
            trigger.action.outText(\\\"***arrayContainsString: theArray is not type table but <\\\" .. type(theArray) .. \\\">\\\", 30)\\\
        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\\\
    \\\
    function dcsCommon.string2Array(inString, deli, uCase)\\\
        if not inString then return {} end \\\
        if not deli then return {} end \\\
        if not uCase then uCase = false end\\\
        if uCase then inString = string.upper(inString) end\\\
        inString = dcsCommon.trim(inString)\\\
        if dcsCommon.containsString(inString, deli) then \\\
            local a = dcsCommon.splitString(inString, deli)\\\
            a = dcsCommon.trimArray(a)\\\
            return a \\\
        else \\\
            return {inString}\\\
        end\\\
    end\\\
    \\\
    function dcsCommon.array2string(inArray, deli)\\\
        if not deli then deli = \\\",\\\" end\\\
        if type(inArray) ~= \\\"table\\\" then return \\\"<err in array2string: not an array>\\\" end\\\
        local s = \\\"\\\"\\\
        local count = 0\\\
        for idx, ele in pairs(inArray) do\\\
            if count > 0 then s = s .. deli .. \\\" \\\" end\\\
            s = s .. ele\\\
        end\\\
        return s\\\
    end\\\
    \\\
    function dcsCommon.stripLF(theString)\\\
        return theString:gsub(\\\"[\\\\r\\\\n]\\\", \\\"\\\")\\\
    end\\\
    \\\
    function dcsCommon.removeBlanks(theString)\\\
        return theString:gsub(\\\"%s\\\", \\\"\\\")\\\
    end\\\
    \\\
    function dcsCommon.stringIsPositiveNumber(theString)\\\
        -- only full integer positive numbers supported \\\
        if not theString then return false end \\\
--        if theString == \\\"\\\" then return false end \\\
        for i = 1, #theString do \\\
            local c = theString:sub(i,i)\\\
            if c < \\\"0\\\" or c > \\\"9\\\" then return false end \\\
        end\\\
        return true \\\
    end\\\
    \\\
    function dcsCommon.stringStartsWithDigit(theString)\\\
        if #theString < 1 then return false end \\\
        local c = string.sub(theString, 1, 1) \\\
        return c >= \\\"0\\\" and c <= \\\"9\\\" \\\
    end\\\
    \\\
    function dcsCommon.stringStartsWithLetter(theString)\\\
        if #theString < 1 then return false end \\\
        local c = string.sub(theString, 1, 1)\\\
        if c >= \\\"a\\\" and c <= \\\"z\\\" then return true end  \\\
        if c >= \\\"A\\\" and c <= \\\"Z\\\" then return true end \\\
        return false \\\
    end\\\
    \\\
    function dcsCommon.stringStartsWith(theString, thePrefix, caseInsensitive)\\\
        if not theString then return false end \\\
        if not thePrefix then return false end \\\
        if not caseInsensitive then caseInsensitive = false end \\\
        \\\
        if caseInsensitive then \\\
            theString = string.upper(theString)\\\
            thePrefix = string.upper(theString)\\\
        end\\\
        -- new code because old 'string.find' had some really \\\
        -- strange results with aircraft types. Prefix \\\"A-10\\\" did not \\\
        -- match string \\\"A-10A\\\" etc. \\\
        \\\
        -- superseded: string.find (s, pattern [, init [, plain]]) solves the problem \\\
        \\\
        --[[\\\
        local pl = string.len(thePrefix)\\\
        if pl > string.len(theString) then return false end\\\
        if pl < 1 then return false end\\\
         for i=1, pl do \\\
        local left =  string.sub(theString, i, i)\\\
        local right = string.sub(thePrefix, i, i)\\\
            if left ~= right then \\\
                return false\\\
            end\\\
        end\\\
    \\\
        return true \\\
--]]--        trigger.action.outText(\\\"---- OK???\\\", 30)\\\
        -- strange stuff happening with some strings, let's investigate \\\
        \\\
        local i, j = string.find(theString, thePrefix, 1, true)\\\
        return (i == 1)\\\
--[[--\\\
        if res then\\\
            trigger.action.outText(\\\"startswith: <\\\" .. theString .. \\\"> pre <\\\" .. thePrefix .. \\\"> --> YES\\\", 30)\\\
        else \\\
            trigger.action.outText(\\\"startswith: <\\\" .. theString .. \\\"> nojoy pre <\\\" .. thePrefix .. \\\">\\\", 30)\\\
        end\\\
        return res \\\
--]]--\\\
    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 theString: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, 1, true) -- 1, true means start at 1, plaintext\\\
    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\\\
            return \\\"NIL\\\"\\\
        end \\\
        if theBool then return \\\"yes\\\" end \\\
        return \\\"no\\\"\\\
    end\\\
    \\\
    function dcsCommon.bool2Num(theBool)\\\
        if not theBool then theBool = false end \\\
        if theBool then return 1 end \\\
        return 0\\\
    end\\\
\\\
    function dcsCommon.point2text(p) \\\
        if not p then return \\\"<!NIL!>\\\" end \\\
        local t = \\\"[x=\\\"\\\
        if p.x then t = t .. p.x .. \\\", \\\" else t = t .. \\\"<nil>, \\\" end \\\
        if p.y then t = t .. \\\"y=\\\" .. p.y .. \\\", \\\" else t = t .. \\\"y=<nil>, \\\" end \\\
        if p.z then t = t .. \\\"z=\\\" .. p.z .. \\\"]\\\" else t = t .. \\\"z=<nil>]\\\" end \\\
        return t \\\
    end\\\
\\\
    function dcsCommon.string2GroupCat(inString)\\\
\\\
        if not inString then return 2 end -- default ground \\\
        inString = inString:lower()\\\
        inString = dcsCommon.trim(inString)\\\
\\\
        local catNum = tonumber(inString)\\\
        if catNum then \\\
            if catNum < 0 then catNum = 0 end \\\
            if catNum > 4 then catNum = 4 end \\\
            return catNum \\\
        end\\\
    \\\
        catNum = 2 -- ground default \\\
        if dcsCommon.stringStartsWith(inString, \\\"grou\\\") then catNum = 2 end \\\
        if dcsCommon.stringStartsWith(inString, \\\"air\\\") then catNum = 0 end\\\
        if dcsCommon.stringStartsWith(inString, \\\"hel\\\") then catNum = 1 end\\\
        if dcsCommon.stringStartsWith(inString, \\\"shi\\\") then catNum = 3 end\\\
        if dcsCommon.stringStartsWith(inString, \\\"trai\\\") then catNum = 4 end\\\
\\\
        return catNum\\\
    end\\\
\\\
    function dcsCommon.string2ObjectCat(inString)\\\
\\\
        if not inString then return 3 end -- default static \\\
        inString = inString:lower()\\\
        inString = dcsCommon.trim(inString)\\\
\\\
        local catNum = tonumber(inString)\\\
        if catNum then \\\
            if catNum < 0 then catNum = 0 end \\\
            if catNum > 6 then catNum = 6 end \\\
            return catNum \\\
        end\\\
    \\\
        catNum = 3 -- static default \\\
        if dcsCommon.stringStartsWith(inString, \\\"uni\\\") then catNum = 1 end \\\
        if dcsCommon.stringStartsWith(inString, \\\"wea\\\") then catNum = 2 end\\\
        if dcsCommon.stringStartsWith(inString, \\\"bas\\\") then catNum = 4 end\\\
        if dcsCommon.stringStartsWith(inString, \\\"sce\\\") then catNum = 5 end\\\
        if dcsCommon.stringStartsWith(inString, \\\"car\\\") then catNum = 6 end\\\
\\\
        return catNum\\\
    end\\\
\\\
    function dcsCommon.menu2text(inMenu)\\\
        if not inMenu then return \\\"<nil>\\\" end\\\
        local s = \\\"\\\"\\\
        for n, v in pairs(inMenu) do \\\
            if type(v) == \\\"string\\\" then \\\
                if s == \\\"\\\" then s = \\\"[\\\" .. v .. \\\"]\\\"  else \\\
                    s = s .. \\\" | [\\\" .. type(v) .. \\\"]\\\" end\\\
            else \\\
                if s == \\\"\\\" then s = \\\"[<\\\" .. type(v) .. \\\">]\\\"  else\\\
                    s = s .. \\\" | [<\\\" .. type(v) .. \\\">]\\\" end\\\
            end\\\
        end\\\
        return s\\\
    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 getmetatable(value) then \\\
            if type(value) == \\\"string\\\" then \\\
            else \\\
                trigger.action.outText(prefix .. key (\\\" .. type(value) .. \\\") .. \\\" HAS META\\\", 30)\\\
            end\\\
        end\\\
        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\\\
    \\\
\\\
    \\\
    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.numberUUID() -- 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.flareColor2Text(flareColor)\\\
        if (flareColor == 0) then return \\\"Green\\\" end\\\
        if (flareColor == 1) then return \\\"Red\\\" end\\\
        if (flareColor == 2) then return \\\"White\\\" end\\\
        if (flareColor == 3) then return \\\"Yellow\\\" end\\\
        if (flareColor < 0) then return \\\"Random\\\" end \\\
        return (\\\"unknown: \\\" .. flareColor)\\\
    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.flareColor2Num(flareColor)\\\
        if not flareColor then flareColor = \\\"green\\\" end \\\
        if type(flareColor) ~= \\\"string\\\" then return 0 end \\\
        flareColor = flareColor:lower()\\\
        if (flareColor == \\\"green\\\") then return 0 end \\\
        if (flareColor == \\\"red\\\") then return 1 end \\\
        if (flareColor == \\\"white\\\") then return 2 end \\\
        if (flareColor == \\\"yellow\\\") then return 3 end \\\
        if (flareColor == \\\"random\\\") then return -1 end \\\
        if (flareColor == \\\"rnd\\\") then return -1 end \\\
        return 0\\\
    end\\\
\\\
    \\\
    function dcsCommon.markPointWithSmoke(p, smokeColor)\\\
        if not smokeColor then smokeColor = 0 end \\\
        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\\\
\\\
-- based on buzzer1977's idea, channel is number, eg in 74X, channel is 74, mode is \\\"X\\\"\\\
    function tacan2freq(channel, mode)    \\\
        if not mode then mode = \\\"X\\\" end \\\
        if not channel then channel = 1 end \\\
        if type(mode) ~= \\\"string\\\" then mode = \\\"X\\\" end \\\
        mode = mode:upper()\\\
        local offset = 1000000 * channel\\\
        if channel < 64 then \\\
            if mode == \\\"Y\\\" then\\\
                return 1087000000 + offset\\\
            end\\\
            return 961000000 + offset -- mode x\\\
        end\\\
    \\\
        if mode == \\\"Y\\\" then\\\
            return 961000000 + offset\\\
        end\\\
        return 1087000000 + offset -- mode x\\\
    end\\\
    \\\
    function dcsCommon.processHMS(msg, delta)\\\
        local rS = math.floor(delta)\\\
        local remainS = tostring(rS)\\\
        local rM = math.floor(delta/60)\\\
        local remainM = tostring(rM)\\\
        local rH = math.floor(delta/3600)\\\
        local remainH = tostring(rH)\\\
        local hmsH = remainH \\\
        if rH < 10 then hmsH = \\\"0\\\" .. hmsH end \\\
        \\\
        local hmsCount = delta - (rH * 3600) -- mins left \\\
        local mins = math.floor (hmsCount / 60)\\\
        local hmsM = tostring(mins)\\\
        if mins < 10 then hmsM = \\\"0\\\" .. hmsM end \\\
        \\\
        hmsCount = hmsCount - (mins * 60) \\\
        local secs = math.floor(hmsCount)\\\
        local hmsS = tostring(secs)\\\
        if secs < 10 then hmsS = \\\"0\\\" .. hmsS end \\\
        \\\
        msg = string.gsub(msg, \\\"<s>\\\", remainS)\\\
        msg = string.gsub(msg, \\\"<m>\\\", remainM)\\\
        msg = string.gsub(msg, \\\"<h>\\\", remainH)\\\
        \\\
        msg = string.gsub(msg, \\\"<:s>\\\", hmsS)\\\
        msg = string.gsub(msg, \\\"<:m>\\\", hmsM)\\\
        msg = string.gsub(msg, \\\"<:h>\\\", hmsH)\\\
        \\\
        return msg \\\
    end\\\
    \\\
    function dcsCommon.nowString()\\\
        local absSecs = timer.getAbsTime()-- + env.mission.start_time\\\
        while absSecs > 86400 do \\\
            absSecs = absSecs - 86400 -- subtract out all days \\\
        end\\\
        return dcsCommon.processHMS(\\\"<:h>:<:m>:<:s>\\\", absSecs)\\\
    end\\\
    \\\
    function dcsCommon.str2num(inVal, default) \\\
        if not default then default = 0 end\\\
        if not inVal then return default end\\\
        if type(inVal) == \\\"number\\\" then return inVal end                 \\\
        local num = nil\\\
        if type(inVal) == \\\"string\\\" then num = tonumber(inVal) end\\\
        if not num then return default end\\\
        return num\\\
    end\\\
    \\\
    function dcsCommon.stringRemainsStartingWith(theString, startingWith)\\\
        -- find the first position where startingWith starts \\\
        local pos = theString:find(startingWith)\\\
        if not pos then return theString end \\\
        -- now return the entire remainder of the string from pos \\\
        local nums = theString:len() - pos + 1\\\
        return theString:sub(-nums)\\\
    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.vNorm(a) \\\
    if not a then return {x = 0, y = 0, z = 0} end \\\
    m = dcsCommon.vMag(a)\\\
    if m <= 0 then return {x = 0, y = 0, z = 0} end \\\
    local r = {}\\\
    r.x = a.x / m \\\
    r.y = a.y / m \\\
    r.z = a.z / m\\\
    return r \\\
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.isTroopCarrierType(theType, carriers)\\\
    if not theType then return false end \\\
    if not carriers then carriers = dcsCommon.troopCarriers \\\
    end \\\
    -- remember that arrayContainsString is case INsensitive by default \\\
    if dcsCommon.wildArrayContainsString(carriers, theType) then \\\
        -- may add additional tests before returning true\\\
        return true\\\
    end\\\
    \\\
    -- see if user wanted 'any' or 'all' supported\\\
    if dcsCommon.arrayContainsString(carriers, \\\"any\\\") then \\\
        return true \\\
    end \\\
    \\\
    if dcsCommon.arrayContainsString(carriers, \\\"all\\\") then \\\
        return true \\\
    end \\\
    \\\
    return false\\\
end\\\
\\\
function dcsCommon.isTroopCarrier(theUnit, carriers)\\\
    -- return true if conf can carry troups\\\
    if not theUnit then return false end \\\
    local uType = theUnit:getTypeName()\\\
    return dcsCommon.isTroopCarrierType(uType, carriers) \\\
end\\\
\\\
function dcsCommon.isPlayerUnit(theUnit)\\\
    -- new patch. simply check if getPlayerName returns something\\\
    if not theUnit then return false end \\\
    if not Unit.isExist(theUnit) then return end \\\
    if not theUnit.getPlayerName then return false end -- map/static object \\\
    local pName = theUnit:getPlayerName()\\\
    if pName then return true end \\\
    return false \\\
end\\\
\\\
function dcsCommon.getAllExistingPlayerUnitsRaw()\\\
    local apu = {}\\\
    for idx, theSide in pairs(dcsCommon.coalitionSides) do\\\
        local thePlayers = coalition.getPlayers(theSide) \\\
        for idy, theUnit in pairs (thePlayers) do \\\
            if theUnit and theUnit:isExist() then \\\
                table.insert(apu, theUnit)\\\
            end\\\
        end\\\
    end\\\
    return apu \\\
end\\\
\\\
function dcsCommon.getUnitAlt(theUnit)\\\
    if not theUnit then return 0 end\\\
    if not Unit.isExist(theUnit) then return 0 end -- safer \\\
    local p = theUnit:getPoint()\\\
    return p.y \\\
end\\\
\\\
function dcsCommon.getUnitAGL(theUnit)\\\
    if not theUnit then return 0 end\\\
    if not Unit.isExist(theUnit) then return 0 end -- safe fix\\\
    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 Unit.isExist(theUnit) 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 360 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.typeIsInfantry(theType)\\\
    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) or \\\
                dcsCommon.containsString(theType, \\\"SA-18 Igla\\\", false)\\\
    return isInfantry\\\
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) or \\\
                dcsCommon.containsString(theType, \\\"SA-18 Igla\\\", false)\\\
    return isInfantry\\\
--]]--\\\
    return dcsCommon.typeIsInfantry(theType)\\\
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\\\
\\\
function dcsCommon.coalition2Text(coa)\\\
    if not coa then return \\\"!nil!\\\" end \\\
    if coa == 0 then return \\\"NEUTRAL\\\" end \\\
    if coa == 1 then return \\\"RED\\\" end \\\
    if coa == 2 then return \\\"BLUE\\\" end \\\
    return \\\"?UNKNOWN?\\\"\\\
end\\\
\\\
function dcsCommon.latLon2Text(lat, lon)\\\
    -- inspired by mist, thanks Grimes!\\\
    -- returns two strings: lat and lon \\\
    \\\
    -- determine hemispheres by sign\\\
    local latHemi, lonHemi\\\
    if lat > 0 then latHemi = 'N' else latHemi = 'S' end\\\
    if lon > 0 then lonHemi = 'E' else lonHemi = 'W' end\\\
\\\
    -- remove sign since we have hemi\\\
    lat = math.abs(lat)\\\
    lon = math.abs(lon)\\\
\\\
    -- calc deg / mins \\\
    local latDeg = math.floor(lat)\\\
    local latMin = (lat - latDeg) * 60\\\
    local lonDeg = math.floor(lon)\\\
    local lonMin = (lon - lonDeg) * 60\\\
\\\
    -- calc seconds \\\
    local rawLatMin = latMin\\\
    latMin = math.floor(latMin)\\\
    local latSec = (rawLatMin - latMin) * 60\\\
    local rawLonMin = lonMin\\\
    lonMin = math.floor(lonMin)\\\
    local lonSec = (rawLonMin - lonMin) * 60\\\
\\\
    -- correct for rounding errors \\\
    if latSec >= 60 then\\\
        latSec = latSec - 60\\\
        latMin = latMin + 1\\\
    end\\\
    if lonSec >= 60 then\\\
        lonSec = lonSec - 60\\\
        lonMin = lonMin + 1\\\
    end\\\
\\\
    -- prepare string output \\\
    local secFrmtStr = '%06.3f'\\\
    local lat = string.format('%02d', latDeg) .. '°' .. string.format('%02d', latMin) .. \\\"'\\\" .. string.format(secFrmtStr, latSec) .. '\\\"' .. latHemi\\\
    local lon = string.format('%02d', lonDeg) .. '°' .. string.format('%02d', lonMin) .. \\\"'\\\" .. string.format(secFrmtStr, lonSec) .. '\\\"' .. lonHemi\\\
    return lat, lon  \\\
end\\\
\\\
-- get mission name. If mission file name without \\\".miz\\\"\\\
function dcsCommon.getMissionName()\\\
    local mn = net.dostring_in(\\\"gui\\\", \\\"return DCS.getMissionName()\\\")\\\
    return mn\\\
end\\\
\\\
function dcsCommon.flagArrayFromString(inString, verbose)\\\
    if not verbose then verbose = false end \\\
    \\\
    if verbose then \\\
        trigger.action.outText(\\\"+++flagArray: processing <\\\" .. inString .. \\\">\\\", 30)\\\
    end \\\
\\\
    if string.len(inString) < 1 then \\\
        trigger.action.outText(\\\"+++flagArray: empty flags\\\", 30)\\\
        return {} \\\
    end\\\
    \\\
    \\\
    local flags = {}\\\
    local rawElements = dcsCommon.splitString(inString, \\\",\\\")\\\
    -- go over all elements \\\
    for idx, anElement in pairs(rawElements) do \\\
        anElement = dcsCommon.trim(anElement)\\\
        if dcsCommon.stringStartsWithDigit(anElement) and  dcsCommon.containsString(anElement, \\\"-\\\") then \\\
            -- interpret this as a range\\\
            local theRange = dcsCommon.splitString(anElement, \\\"-\\\")\\\
            local lowerBound = theRange[1]\\\
            lowerBound = tonumber(lowerBound)\\\
            local upperBound = theRange[2]\\\
            upperBound = tonumber(upperBound)\\\
            if lowerBound and upperBound then\\\
                -- swap if wrong order\\\
                if lowerBound > upperBound then \\\
                    local temp = upperBound\\\
                    upperBound = lowerBound\\\
                    lowerBound = temp \\\
                end\\\
                -- now add add numbers to flags\\\
                for f=lowerBound, upperBound do \\\
                    table.insert(flags, f)\\\
\\\
                end\\\
            else\\\
                -- bounds illegal\\\
                trigger.action.outText(\\\"+++flagArray: ignored range <\\\" .. anElement .. \\\"> (range)\\\", 30)\\\
            end\\\
        else\\\
            -- single number\\\
            local f = dcsCommon.trim(anElement) -- DML flag upgrade: accept strings tonumber(anElement)\\\
            if f then \\\
                table.insert(flags, f)\\\
\\\
            else \\\
                trigger.action.outText(\\\"+++flagArray: ignored element <\\\" .. anElement .. \\\"> (single)\\\", 30)\\\
            end\\\
        end\\\
    end\\\
    if verbose then \\\
        trigger.action.outText(\\\"+++flagArray: <\\\" .. #flags .. \\\"> flags total\\\", 30)\\\
    end \\\
    return flags\\\
end\\\
\\\
function dcsCommon.rangeArrayFromString(inString, verbose)\\\
    if not verbose then verbose = false end \\\
    \\\
    if verbose then \\\
        trigger.action.outText(\\\"+++rangeArray: processing <\\\" .. inString .. \\\">\\\", 30)\\\
    end \\\
\\\
    if string.len(inString) < 1 then \\\
        trigger.action.outText(\\\"+++rangeArray: empty ranges\\\", 30)\\\
        return {} \\\
    end\\\
    \\\
    local ranges = {}\\\
    local rawElements = dcsCommon.splitString(inString, \\\",\\\")\\\
    -- go over all elements \\\
    for idx, anElement in pairs(rawElements) do \\\
        anElement = dcsCommon.trim(anElement)\\\
        local outRange = {}\\\
        if dcsCommon.stringStartsWithDigit(anElement) and  dcsCommon.containsString(anElement, \\\"-\\\") then \\\
            -- interpret this as a range\\\
            local theRange = dcsCommon.splitString(anElement, \\\"-\\\")\\\
            local lowerBound = theRange[1]\\\
            lowerBound = tonumber(lowerBound)\\\
            local upperBound = theRange[2]\\\
            upperBound = tonumber(upperBound)\\\
            if lowerBound and upperBound then\\\
                -- swap if wrong order\\\
                if lowerBound > upperBound then \\\
                    local temp = upperBound\\\
                    upperBound = lowerBound\\\
                    lowerBound = temp \\\
                end\\\
                -- now add to ranges\\\
                outRange[1] = lowerBound\\\
                outRange[2] = upperBound\\\
                table.insert(ranges, outRange)\\\
                if verbose then \\\
                    trigger.action.outText(\\\"+++rangeArray: new range <\\\" .. lowerBound .. \\\"> to <\\\" .. upperBound .. \\\">\\\", 30)\\\
                end\\\
            else\\\
                -- bounds illegal\\\
                trigger.action.outText(\\\"+++rangeArray: ignored range <\\\" .. anElement .. \\\"> (range)\\\", 30)\\\
            end\\\
        else\\\
            -- single number\\\
            local f = dcsCommon.trim(anElement) \\\
            f = tonumber(f)\\\
            if f then \\\
                outRange[1] = f\\\
                outRange[2] = f\\\
                table.insert(ranges, outRange)\\\
                if verbose then \\\
                    trigger.action.outText(\\\"+++rangeArray: new (single-val) range <\\\" .. f .. \\\"> to <\\\" .. f .. \\\">\\\", 30)\\\
                end\\\
            else \\\
                trigger.action.outText(\\\"+++rangeArray: ignored element <\\\" .. anElement .. \\\"> (single)\\\", 30)\\\
            end\\\
        end\\\
    end\\\
    if verbose then \\\
        trigger.action.outText(\\\"+++rangeArray: <\\\" .. #ranges .. \\\"> ranges total\\\", 30)\\\
    end \\\
    return ranges\\\
end\\\
\\\
function dcsCommon.incFlag(flagName)\\\
    local v = trigger.misc.getUserFlag(flagName)\\\
    trigger.action.setUserFlag(flagName, v + 1)\\\
end\\\
\\\
function dcsCommon.decFlag(flagName)\\\
    local v = trigger.misc.getUserFlag(flagName)\\\
    trigger.action.setUserFlag(flagName, v - 1)\\\
end\\\
\\\
function dcsCommon.objectHandler(theObject, theCollector)\\\
    table.insert(theCollector, theObject)\\\
    return true \\\
end\\\
\\\
function dcsCommon.getObjectsForCatAtPointWithRadius(aCat, thePoint, theRadius)\\\
    if not aCat then aCat = Object.Category.UNIT end \\\
    local p = {x=thePoint.x, y=thePoint.y, z=thePoint.z}\\\
    local collector = {}\\\
    \\\
    -- now build the search argument \\\
    local args = {\\\
            id = world.VolumeType.SPHERE,\\\
            params = {\\\
                point = p,\\\
                radius = theRadius\\\
            }\\\
        }\\\
    \\\
    -- now call search\\\
    world.searchObjects(aCat, args, dcsCommon.objectHandler, collector)\\\
    return collector\\\
end\\\
\\\
function dcsCommon.getSceneryObjectsInZone(theZone) -- DCS ZONE!!! \\\
    local aCat = 5 -- scenery\\\
    -- WARNING: WE ARE USING DCS ZONES, NOT CFX!!!\\\
    local p = {x=theZone.x, y=0, z=theZone.y}\\\
    local lp = {x = p.x, y = p.z}\\\
    p.y = land.getHeight(lp)\\\
    local collector = {}\\\
    \\\
    -- now build the search argument \\\
    local args = {\\\
            id = world.VolumeType.SPHERE,\\\
            params = {\\\
                point = p,\\\
                radius = theZone.radius\\\
            }\\\
        }\\\
    \\\
    -- now call search\\\
    world.searchObjects(aCat, args, dcsCommon.objectHandler, collector)\\\
    return collector\\\
end\\\
\\\
function dcsCommon.getSceneryObjectInZoneByName(theName, theZone) -- DCS ZONE!!!\\\
    local allObs = dcsCommon.getSceneryObjectsInZone(theZone)\\\
    for idx, anObject in pairs(allObs) do \\\
        if tostring(anObject:getName()) == theName then return anObject end \\\
    end\\\
    return nil \\\
end\\\
\\\
--\\\
-- bitwise operators\\\
--\\\
function dcsCommon.bitAND32(a, b)\\\
    if not a then a = 0 end \\\
    if not b then b = 0 end \\\
    local z = 0\\\
    local e = 1\\\
    for i = 0, 31 do \\\
        local a1 = a % 2 -- 0 or 1\\\
        local b1 = b % 2 -- 0 or 1\\\
        if a1 == 1 and b1 == 1 then \\\
            a = a - 1 -- remove bit \\\
            b = b - 1 \\\
            z = z + e\\\
        else\\\
            if a1 == 1 then a = a - 1 end -- remove bit \\\
            if b1 == 1 then b = b - 1 end \\\
        end\\\
        a = a / 2 -- shift right\\\
        b = b / 2        \\\
        e = e * 2 -- raise e by 1 \\\
    end\\\
    return z\\\
end\\\
\\\
function dcsCommon.num2bin(a)\\\
    if not a then a = 0 end \\\
    local z = \\\"\\\"\\\
    for i = 0, 31 do \\\
        local a1 = a % 2 -- 0 or 1\\\
        if a1 == 1 then \\\
            a = a - 1 -- remove bit \\\
            z = \\\"1\\\"..z\\\
        else\\\
            z = \\\"0\\\"..z\\\
        end\\\
        a = a / 2 -- shift right\\\
    end\\\
    return z\\\
end\\\
\\\
function dcsCommon.LSR(a, num)\\\
    if not a then a = 0 end \\\
    if not num then num = 16 end \\\
    for i = 1, num do \\\
        local a1 = a % 2 -- 0 or 1\\\
        if a1 == 1 then \\\
            a = a - 1 -- remove bit \\\
        end\\\
        a = a / 2 -- shift right\\\
    end\\\
    return a\\\
end\\\
\\\
--\\\
-- string wildcards \\\
--\\\
function dcsCommon.processStringWildcards(inMsg)\\\
    -- Replace STATIC bits of message like CR and zone name \\\
    if not inMsg then return \\\"<nil inMsg>\\\" end\\\
    local formerType = type(inMsg)\\\
    if formerType ~= \\\"string\\\" then inMsg = tostring(inMsg) end  \\\
    if not inMsg then inMsg = \\\"<inMsg is incompatible type \\\" .. formerType .. \\\">\\\" end \\\
    local outMsg = \\\"\\\"\\\
    -- replace line feeds \\\
    outMsg = inMsg:gsub(\\\"<n>\\\", \\\"\\\\n\\\")\\\
\\\
    return outMsg \\\
end\\\
\\\
--\\\
-- phonetic alphabet \\\
--\\\
dcsCommon.alphabet = {\\\
    a = \\\"alpha\\\",\\\
    b = \\\"bravo\\\",\\\
    c = \\\"charlie\\\",\\\
    d = \\\"delta\\\",\\\
    e = \\\"echo\\\",\\\
    f = \\\"foxtrot\\\",\\\
    g = \\\"golf\\\",\\\
    h = \\\"hotel\\\",\\\
    i = \\\"india\\\",\\\
    j = \\\"juliet\\\",\\\
    k = \\\"kilo\\\",\\\
    l = \\\"lima\\\",\\\
    m = \\\"mike\\\",\\\
    n = \\\"november\\\",\\\
    o = \\\"oscar\\\",\\\
    p = \\\"papa\\\",\\\
    q = \\\"quebec\\\",\\\
    r = \\\"romeo\\\",\\\
    s = \\\"sierra\\\",\\\
    t = \\\"tango\\\",\\\
    u = \\\"uniform\\\",\\\
    v = \\\"victor\\\",\\\
    w = \\\"whiskey\\\",\\\
    x = \\\"x-ray\\\",\\\
    y = \\\"yankee\\\",\\\
    z = \\\"zulu\\\",\\\
[\\\"0\\\"] = \\\"zero\\\",\\\
[\\\"1\\\"] = \\\"wun\\\",\\\
[\\\"2\\\"] = \\\"too\\\",\\\
[\\\"3\\\"] = \\\"tree\\\",\\\
[\\\"4\\\"] = \\\"fower\\\",\\\
[\\\"5\\\"] = \\\"fife\\\" ,\\\
[\\\"6\\\"] = \\\"six\\\",\\\
[\\\"7\\\"] = \\\"seven\\\",\\\
[\\\"8\\\"] = \\\"att\\\",\\\
[\\\"9\\\"] = \\\"niner\\\",\\\
[\\\" \\\"] = \\\"break\\\",\\\
}\\\
\\\
function dcsCommon.letter(inChar)\\\
    local theChar = \\\"\\\"\\\
    if type(inChar == \\\"string\\\") then \\\
        if #inChar < 1 then return \\\"#ERROR0#\\\" end\\\
        inChar = string.lower(inChar)\\\
        theChar = string.sub(inChar, 1, 1)\\\
    elseif type(inChar == \\\"number\\\") then \\\
        if inChar > 255 then return \\\"#ERROR>#\\\" end \\\
        if inChar < 0 then return \\\"#ERROR<#\\\" end \\\
        theChar = char(inChar)\\\
    else \\\
        return \\\"#ERRORT#\\\"\\\
    end\\\
--    trigger.action.outText(\\\"doing <\\\" .. theChar .. \\\">\\\", 30)\\\
    local a = dcsCommon.alphabet[theChar]\\\
    if a == nil then a = \\\"#ERROR?#\\\" end \\\
    return a \\\
end\\\
\\\
function dcsCommon.spellString(inString)\\\
    local res = \\\"\\\"\\\
    local first = true \\\
    for i = 1, #inString do\\\
        local c = inString:sub(i,i)\\\
        if first then \\\
            res = dcsCommon.letter(c)\\\
            first = false \\\
        else \\\
            res = res .. \\\" \\\" .. dcsCommon.letter(c)\\\
        end\\\
    end\\\
    return res \\\
end\\\
\\\
--\\\
-- RGBA from hex\\\
--\\\
function dcsCommon.hexString2RGBA(inString) \\\
    -- enter with \\\"#FF0020\\\" (RGB) or \\\"#FF00AB99\\\" RGBA\\\
    -- check if it starts with #\\\
    if not inString then return nil end \\\
    if #inString ~= 7 and #inString ~=9 then return nil end \\\
    if inString:sub(1, 1) ~= \\\"#\\\" then return nil end \\\
    inString = inString:lower()\\\
    local red = tonumber(\\\"0x\\\" .. inString:sub(2,3)) \\\
    if not red then red = 0 end \\\
    local green = tonumber(\\\"0x\\\" .. inString:sub(4,5))\\\
    if not green then green = 0 end \\\
    local blue = tonumber(\\\"0x\\\" .. inString:sub(6,7))\\\
    if not blue then blue = 0 end \\\
    local alpha = 255 \\\
    if #inString == 9 then \\\
        alpha = tonumber(\\\"0x\\\" .. inString:sub(8,9))\\\
    end\\\
    if not alpha then alpha = 0 end\\\
    return {red/255, green/255, blue/255, alpha/255}\\\
end\\\
\\\
\\\
--\\\
-- Player handling \\\
--\\\
function dcsCommon.playerName2Coalition(playerName)\\\
    if not playerName then return 0 end \\\
    local factions = {1,2}\\\
    for idx, theFaction in pairs(factions) do \\\
        local players = coalition.getPlayers(theFaction)\\\
        for idy, theUnit in pairs(players) do \\\
            local upName = theUnit:getPlayerName()\\\
            if upName == playerName then return theFaction end\\\
        end\\\
    end\\\
    return 0\\\
end\\\
\\\
--\\\
-- iterators\\\
--\\\
-- iteratePlayers - call callback for all player units\\\
-- callback is of signature callback(playerUnit)\\\
--\\\
\\\
function dcsCommon.iteratePlayers(callBack)\\\
    local factions = {0, 1, 2}\\\
    for idx, theFaction in pairs(factions) do \\\
        local players = coalition.getPlayers(theFaction)\\\
        for idy, theUnit in pairs(players) do \\\
            callBack(theUnit)\\\
        end\\\
    end\\\
end\\\
\\\
--\\\
-- SEMAPHORES\\\
--\\\
dcsCommon.semaphores = {}\\\
\\\
-- replacement for trigger.misc.getUserFlag\\\
function dcsCommon.getUserFlag(flagName)\\\
    if dcsCommon.semaphores[flagName] then \\\
        return dcsCommon.semaphores[flagName]\\\
    end\\\
    \\\
    return trigger.misc.getUserFlag(flagName)\\\
end\\\
\\\
-- replacement for trigger.action.setUserFlag \\\
function dcsCommon.setUserFlag(flagName, theValue)\\\
    -- not yet connected: semaphores\\\
    \\\
    -- forget semaphore content if new value is old-school \\\
    if type(theValue) == \\\"number\\\" then \\\
        dcsCommon.semaphores[theValue] = nil --return to old-school \\\
    end\\\
    trigger.action.setUserFlag(flagName, theValue)\\\
end\\\
\\\
--\\\
--\\\
-- INIT\\\
--\\\
--\\\
    -- init any variables, tables etc that the lib requires internally\\\
    function dcsCommon.init()\\\
        cbID = 0\\\
        -- create ID tables\\\
        dcsCommon.collectMissionIDs()\\\
        \\\
        --dcsCommon.uuIdent = 0\\\
        if (dcsCommon.verbose) or true then\\\
          trigger.action.outText(\\\"dcsCommon v\\\" .. dcsCommon.version .. \\\" loaded\\\", 10)\\\
        end\\\
    end\\\
\\\
    \\\
-- do init. \\\
dcsCommon.init()\\\
\\\
\");a_do_script(\"cfxZones = {}\\\
cfxZones.version = \\\"3.1.2\\\"\\\
\\\
-- cf/x zone management module\\\
-- reads dcs zones and makes them accessible and mutable \\\
-- by scripting.\\\
--\\\
-- Copyright (c) 2021, 2022 by Christian Franz and cf/x AG\\\
--\\\
\\\
--[[-- 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\\\
 - 2.4.11 - removed typo in get closest zone \\\
 - 2.4.12 - getStringFromZoneProperty\\\
 - 2.5.0  - harden getZoneProperty and all getPropertyXXXX\\\
 - 2.5.1  - markZoneWithSmoke supports alt attribute \\\
 - 2.5.2  - getPoint also writes through to zone itself for optimization\\\
          - new method getPositiveRangeFromZoneProperty(theZone, theProperty, default)\\\
 - 2.5.3  - new getAllGroupsInZone()\\\
 - 2.5.4  - cleaned up getZoneProperty break on no properties \\\
          - extractPropertyFromDCS trims key and property \\\
 - 2.5.5  - pollFlag() centralized for banging \\\
          - allStaticsInZone\\\
 - 2.5.6  - flag accessor setFlagValue(), getFlagValue()  \\\
          - pollFlag supports theZone as final parameter\\\
          - randomDelayFromPositiveRange\\\
          - isMEFlag\\\
 - 2.5.7  - pollFlag supports dml flags\\\
 - 2.5.8  - flagArrayFromString\\\
          - getFlagNumber invokes tonumber() before returning result \\\
 - 2.5.9  - removed pass-back flag in getPoint() \\\
 - 2.6.0  - testZoneFlag() method based flag testing\\\
 - 2.6.1  - Watchflag parsing of zone condition for number-named flags\\\
          - case insensitive\\\
          - verbose for zone-local accepted (but not acted upon)\\\
          - hasProperty now offers active information when looking for '*?' and '*!'\\\
 - 2.7.0  - doPollFlag - fully support multiple flags per bang!\\\
 - 2.7.1  - setFlagValueMult()\\\
 - 2.7.2  - '261 repair'\\\
 - 2.7.3  - testZoneFlag returns mathodResult, lastVal\\\
          - evalFlagMethodImmediate()\\\
 - 2.7.4  - doPollFlag supports immediate number setting \\\
 - 2.7.5  - more QoL checks when mixing up ? and ! for attributes\\\
 - 2.7.6  - trim for getBoolFromZoneProperty and getStringFromZoneProperty\\\
 - 2.7.7  - randomInRange()\\\
          - show number of zones \\\
 - 2.7.8  - inc method now triggers if curr value > last value \\\
          - dec method noew triggers when curr value < last value \\\
          - testFlagByMethodForZone supports lohi, hilo transitions \\\
          - doPollFlag supports 'pulse'\\\
          - pulseFlag\\\
          - unpulse \\\
- 2.7.9   - getFlagValue QoL for <none>\\\
          - setFlagValue QoL for <none>\\\
- 2.8.0      - new allGroupNamesInZone()\\\
- 2.8.1   - new zonesLinkedToUnit()  \\\
- 2.8.2   - flagArrayFromString trims elements before range check \\\
- 2.8.3   - new verifyMethod()\\\
          - changed extractPropertyFromDCS() to also match attributes with blanks like \\\"the Attr\\\" to \\\"theAttr\\\"\\\
          - new expandFlagName()\\\
- 2.8.4   - fixed bug in setFlagValue()\\\
- 2.8.5   - createGroundUnitsInZoneForCoalition() now always passes back a copy of the group data \\\
          - data also contains cty = country and cat = category for easy spawn\\\
          - getFlagValue additional zone name guards \\\
- 2.8.6   - fix in getFlagValue for missing delay \\\
- 2.8.7   - update isPointInsideZone(thePoint, theZone, radiusIncrease) - new radiusIncrease\\\
          - isPointInsideZone() returns delta as well\\\
- 2.9.0   - linked zones can useOffset and useHeading \\\
          - getPoint update \\\
          - pointInZone understands useOrig\\\
          - allStaticsInZone supports useOrig \\\
          - dPhi for zones with useHeading \\\
          - uHdg for zones with useHading, contains linked unit's original heading\\\
          - Late-linking implemented:\\\
          - linkUnit works for late-activating units \\\
          - linkUnit now also works for player / clients, dynamic (re-)linking \\\
          - linkUnit uses zone's origin for all calculations \\\
- 2.9.1   - new evalRemainder()\\\
          - pollFlag supports +/- for immediate numbers, flags, number flags in parantheses\\\
          - stronger guards in hasProperty \\\
- 2.9.2   - new createRandomPointInPolyZone()\\\
          - createRandomZoneInZone uses createRandomPointInPolyZone\\\
          - new createRandomPointInZone()\\\
          - new randomPointInZone()\\\
- 3.0.0   - support for DCS 2.8 linkUnit attribute, integration with \\\
            linedUnit and warning.\\\
          - initZoneVerbosity()\\\
- 3.0.1   - updateMovingZones() better tracks linked units by name\\\
- 3.0.2   - maxRadius for all zones, only differs from radius in polyZones \\\
          - re-factoring zone-base string processing from messenger module\\\
          - new processStringWildcards() that does almost all that messenger can \\\
- 3.0.3   - new getLinkedUnit()\\\
- 3.0.4   - new createRandomPointOnZoneBoundary()\\\
- 3.0.5   - getPositiveRangeFromZoneProperty() now also supports upper bound (optional)\\\
- 3.0.6   - new createSimplePolyZone()\\\
          - new createSimpleQuadZone()\\\
- 3.0.7   - getPoint() can also get land y when passing true as second param\\\
- 3.0.8   - new cfxZones.pointInOneOfZones(thePoint, zoneArray, useOrig) \\\
- 3.0.9   - new getFlareColorStringFromZoneProperty()\\\
- 3.1.0      - new getRGBVectorFromZoneProperty()\\\
            new getRGBAVectorFromZoneProperty()\\\
- 3.1.1   - getRGBAVectorFromZoneProperty now supports #RRGGBBAA and #RRGGBB format \\\
          - owner for all, default 0 \\\
- 3.1.2   - getAllZoneProperties has numbersOnly option \\\
\\\
--]]--\\\
cfxZones.verbose = false\\\
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 retrieve 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, while 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. \\\
            -- WARNING: ME linked zones have a relative x any y \\\
            --          to the linked unit \\\
            if dcsZone.linkUnit then \\\
                -- calculate the zone's real position by accessing the unit's MX data \\\
                -- as precached by dcsCommon\\\
                local ux, uy = dcsCommon.getUnitStartPosByID(dcsZone.linkUnit)\\\
                newZone.point = cfxZones.createPoint(ux + dcsZone.x, 0, uy + dcsZone.y)\\\
                newZone.dcsOrigin = cfxZones.createPoint(ux + dcsZone.x, 0, uy + dcsZone.y)\\\
            else \\\
                newZone.point = cfxZones.createPoint(dcsZone.x, 0, dcsZone.y)\\\
                newZone.dcsOrigin = cfxZones.createPoint(dcsZone.x, 0, dcsZone.y)\\\
            end\\\
\\\
            -- 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\\\
                newZone.maxRadius = newZone.radius -- same for circular\\\
    \\\
            elseif zoneType == 2 then\\\
                -- polyZone\\\
                newZone.isPoly = true \\\
                newZone.radius = dcsZone.radius -- radius is still written in DCS, may change later. The radius has no meaning and is the last radius written before zone changed to poly.\\\
                -- note that newZone.point is only inside the tone for \\\
                -- convex polys, and DML only correctly works with convex polys\\\
                -- now transfer all point in the poly\\\
                -- note: DCS in 2.7 misspells vertices as 'verticies'\\\
                -- correct for this \\\
                newZone.maxRadius = 0\\\
                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\\\
                    -- measure distance from zone's point, and store maxRadius \\\
                    -- dcs always saves a point with the poly zone \\\
                    local dist = dcsCommon.dist(newZone.point, polyPoint)\\\
                    if dist > newZone.maxRadius then newZone.maxRadius = dist end \\\
                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!!!\\\
            --trigger.action.outText(\\\"znd: procced \\\" .. newZone.name .. \\\" with radius \\\" .. newZone.radius, 30)\\\
        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])\\\
        \\\
        local pRad = dcsCommon.dist(theZone.point, poly[1]) -- rRad is radius for polygon from theZone.point \\\
        \\\
        -- 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 \\\
            local dp = dcsCommon.dist(theZone.point, vertex)\\\
            if dp > pRad then pRad = dp end -- find largst distance to vertex\\\
        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 \\\
        -- store pRad \\\
        theZone.pRad = pRad -- not sure we'll ever need that, but at least we have it\\\
--        trigger.action.outText(\\\"+++Zones: poly zone <\\\" .. theZone.name .. \\\"> has pRad = \\\" .. pRad, 30) -- remember to remove me \\\
    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\\\
    -- handle xz only \\\
    if inPoint.z then \\\
        newPoint.z = inPoint.z \\\
    else \\\
        newPoint.z = inPoint.y \\\
    end\\\
    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)\\\
    -- warning: bounds do not move woth zone! may have to be updated\\\
    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.createRandomPointOnZoneBoundary(theZone)\\\
    if not theZone then return nil end \\\
    if theZone.isPoly then \\\
        local loc, dx, dy = cfxZones.createRandomPointInPolyZone(theZone, true)\\\
        return loc, dx, dy \\\
    else \\\
        local loc, dx, dy = cfxZones.createRandomPointInCircleZone(theZone, true)\\\
        return loc, dx, dy \\\
    end\\\
end\\\
\\\
function cfxZones.createRandomPointInZone(theZone)\\\
    if not theZone then return nil end \\\
    if theZone.isPoly then \\\
        local loc, dx, dy = cfxZones.createRandomPointInPolyZone(theZone)\\\
        return loc, dx, dy \\\
    else \\\
        local loc, dx, dy = cfxZones.createRandomPointInCircleZone(theZone)\\\
        return loc, dx, dy \\\
    end\\\
end\\\
\\\
function cfxZones.randomPointInZone(theZone)\\\
    local loc, dx, dy =  cfxZones.createRandomPointInZone(theZone)\\\
    return loc, dx, dy \\\
end\\\
\\\
function cfxZones.createRandomPointInCircleZone(theZone, onEdge)\\\
    if not theZone.isCircle then \\\
        trigger.action.outText(\\\"+++Zones: warning - createRandomPointInCircleZone called for non-circle zone <\\\" .. theZone.name .. \\\">\\\", 30)\\\
        return {x=theZone.point.x, y=0, z=theZone.point.z}\\\
    end\\\
    \\\
    -- ok, let's first create a random percentage value for the new radius\\\
    -- now lets get a random degree\\\
    local degrees = math.random() * 2 * 3.14152 -- radiants. \\\
    local r = theZone.radius \\\
    if not onEdge then \\\
        r = r * math.random()\\\
    end \\\
    local p = cfxZones.getPoint(theZone) -- force update of zone if linked\\\
    local dx = r * math.cos(degrees)\\\
    local dz = r * math.sin(degrees)\\\
    local px = p.x + dx -- r * math.cos(degrees)\\\
    local pz = p.z + dz -- r * math.sin(degrees)\\\
    return {x=px, y=0, z = pz}, dx, dz -- returns loc and offsets to theZone.point\\\
end\\\
\\\
function cfxZones.createRandomPointInPolyZone(theZone, onEdge)\\\
    if not theZone.isPoly then \\\
        trigger.action.outText(\\\"+++Zones: warning - createRandomPointInPolyZone called for non-poly zone <\\\" .. theZone.name .. \\\">\\\", 30)\\\
        return cfxZones.createPoint(theZone.point.x, 0, theZone.point.z)\\\
    end\\\
    -- force update of all points \\\
    local p = cfxZones.getPoint(theZone)\\\
    \\\
    -- point in convex poly: choose two different lines from that polygon \\\
    local lineIdxA = dcsCommon.smallRandom(#theZone.poly)\\\
    repeat lineIdxB = dcsCommon.smallRandom(#theZone.poly) until (lineIdxA ~= lineIdxB)\\\
    \\\
    -- we now have two different lines. pick a random point on each. \\\
    -- we use lerp to pick any point between a and b \\\
    local a = theZone.poly[lineIdxA]\\\
    lineIdxA = lineIdxA + 1 -- get next point in poly and wrap around\\\
    if lineIdxA > #theZone.poly then lineIdxA = 1 end \\\
    local b = theZone.poly[lineIdxA] \\\
    local randompercent = math.random()\\\
    local sourceA = dcsCommon.vLerp (a, b, randompercent)\\\
    -- if all we want is a point on an edge, we are done \\\
    if onEdge then \\\
        local polyPoint = sourceA\\\
        return polyPoint, polyPoint.x - p.x, polyPoint.z - p.z -- return loc, dx, dz \\\
    end \\\
    \\\
    -- now get point on second line \\\
    a = theZone.poly[lineIdxB]\\\
    lineIdxB = lineIdxB + 1 -- get next point in poly and wrap around\\\
    if lineIdxB > #theZone.poly then lineIdxB = 1 end \\\
    b = theZone.poly[lineIdxB] \\\
    randompercent = math.random()\\\
    local sourceB = dcsCommon.vLerp (a, b, randompercent)\\\
    \\\
    -- now take a random point on that line that entirely \\\
    -- runs through the poly \\\
    randompercent = math.random()\\\
    local polyPoint = dcsCommon.vLerp (sourceA, sourceB, randompercent)\\\
    return polyPoint, polyPoint.x - p.x, polyPoint.z - p.z -- return loc, dx, dz \\\
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.createSimplePolyZone(name, location, points, addToManaged)\\\
    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.createPolyZone(name, points)\\\
    \\\
    if addToManaged then \\\
        cfxZones.addZoneToManagedZones(newZone)\\\
    end\\\
    return newZone\\\
end\\\
\\\
function cfxZones.createSimpleQuadZone(name, location, points, addToManaged)\\\
    if not location then \\\
        location = {}\\\
    end\\\
    if not location.x then location.x = 0 end \\\
    if not location.z then location.z = 0 end \\\
        \\\
    -- synthesize 4 points if they don't exist\\\
    -- remember: in DCS positive x is up, positive z is right \\\
    if not points then \\\
        points = {} \\\
    end\\\
    if not points[1] then \\\
        -- upper left \\\
        points[1] = {x = location.x-1, y = 0, z = location.z-1}\\\
    end\\\
    if not points[2] then \\\
        -- upper right \\\
        points[2] = {x = location.x-1, y = 0, z = location.z+1}\\\
    end\\\
    if not points[3] then \\\
        -- lower right \\\
        points[3] = {x = location.x+1, y = 0, z = location.z+1}\\\
    end\\\
    if not points[4] then \\\
        -- lower left \\\
        points[4] = {x = location.x+1, y = 0, z = location.z-1}\\\
    end\\\
    \\\
    return cfxZones.createSimplePolyZone(name, location, points, addToManaged)\\\
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.\\\
    -- entirelyInside is not guaranteed for polyzones\\\
    \\\
--    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.\\\
        --[[ replaced by new code \\\
        \\\
        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: emergency brake for inZone\\\" .. inZone.name,  10)\\\
                break\\\
            end\\\
        until cfxZones.isPointInsidePoly(newPoint, inZone.poly)\\\
        --]]--\\\
        local newPoint = cfxZones.createRandomPointInPolyZone(inZone)\\\
        -- 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, radiusIncrease)\\\
    -- radiusIncrease only works for circle zones \\\
    if not radiusIncrease then radiusIncrease = 0 end \\\
    local p = {x=thePoint.x, y = 0, z = thePoint.z} -- zones have no altitude\\\
    if (theZone.isCircle) then \\\
        local zp = cfxZones.getPoint(theZone)\\\
        local d = dcsCommon.dist(p, theZone.point)\\\
        return d < theZone.radius + radiusIncrease, d \\\
    end \\\
    \\\
    if (theZone.isPoly) then \\\
        --trigger.action.outText(\\\"zne: isPointInside: \\\" .. theZone.name .. \\\" is Polyzone!\\\", 30)\\\
        return (cfxZones.isPointInsidePoly(p, theZone.poly)), 0 -- always returns delta 0\\\
    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.allGroupsInZone(theZone, categ) -- categ is optional, must be code \\\
    -- warning: does not check for exiting!\\\
    --trigger.action.outText(\\\"Zone \\\" .. theZone.name .. \\\" radius \\\" .. theZone.radius, 30)\\\
    local inZones = {}\\\
    local coals = {0, 1, 2} -- all coalitions\\\
    for idx, coa in pairs(coals) do \\\
        local allGroups = coalition.getGroups(coa, categ)\\\
        for key, group in pairs(allGroups) do -- iterate all groups\\\
            if cfxZones.isGroupPartiallyInZone(group, theZone) then\\\
                table.insert(inZones, group)\\\
            end\\\
        end\\\
    end\\\
    return inZones\\\
end\\\
\\\
function cfxZones.allGroupNamesInZone(theZone, categ) -- categ is optional, must be code \\\
    -- warning: does not check for exiting!\\\
    --trigger.action.outText(\\\"Zone \\\" .. theZone.name .. \\\" radius \\\" .. theZone.radius, 30)\\\
    local inZones = {}\\\
    local coals = {0, 1, 2} -- all coalitions\\\
    for idx, coa in pairs(coals) do \\\
        local allGroups = coalition.getGroups(coa, categ)\\\
        for key, group in pairs(allGroups) do -- iterate all groups\\\
            if cfxZones.isGroupPartiallyInZone(group, theZone) then\\\
                table.insert(inZones, group:getName())\\\
            end\\\
        end\\\
    end\\\
    return inZones\\\
end\\\
\\\
function cfxZones.allStaticsInZone(theZone, useOrigin) -- categ is optional, must be code \\\
    -- warning: does not check for exiting!\\\
    local inZones = {}\\\
    local coals = {0, 1, 2} -- all coalitions\\\
    for idx, coa in pairs(coals) do \\\
        local allStats = coalition.getStaticObjects(coa)\\\
        for key, statO in pairs(allStats) do -- iterate all groups\\\
            local oP = statO:getPoint()\\\
            if useOrigin then \\\
                if cfxZones.pointInZone(oP, theZone, true) then \\\
                    -- use DCS original coords\\\
                    table.insert(inZones, statO)\\\
                end\\\
            elseif cfxZones.pointInZone(oP, theZone) then\\\
                table.insert(inZones, statO)\\\
            end\\\
        end\\\
    end\\\
    return inZones\\\
end\\\
\\\
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)            \\\
            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 \\\
        \\\
    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()\\\
            local inzone, percent, dist = cfxZones.pointInZone(p, aZone)\\\
            if inzone then -- cfxZones.isPointInsideZone(p, aZone) then             \\\
                --trigger.action.outText(\\\"zne: YAY <\\\" .. aUnit:getName() .. \\\"> IS IN \\\" .. aZone.name, 30) \\\
                return true\\\
            end \\\
            --trigger.action.outText(\\\"zne: <\\\" .. aUnit:getName() .. \\\"> not in \\\" .. aZone.name .. \\\", dist = \\\" .. dist .. \\\", rad = \\\", aZone.radius, 30) \\\
        end\\\
    end\\\
    return false\\\
end\\\
\\\
function cfxZones.isEntireGroupInZone(aGroup, aZone)\\\
    if not aGroup then return false end \\\
    if not aZone then return false end \\\
    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 \\\
        if not aZone then \\\
            trigger.action.outText(\\\"+++zone: nil aZone for \\\" .. k, 30)\\\
        else \\\
            local lU = cfxZones.getZoneProperty(aZone, propertyName)\\\
            if lU then \\\
                table.insert(theZones, aZone)\\\
            end\\\
        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 lPoint = {x=point.x, y=0, z=point.z}\\\
    local currDelta = math.huge \\\
    local closestZone = nil\\\
    for zName, zData in pairs(theZones) do \\\
        local zPoint = cfxZones.getPoint(zData)\\\
        local delta = dcsCommon.dist(lPoint, zPoint) -- emulate flag compare \\\
        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, alt)\\\
    if not alt then alt = 5 end \\\
    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}) + alt\\\
    -- 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, alt)\\\
    local rads = degrees * math.pi / 180\\\
    local dx = radius * math.sin(rads)\\\
    local dz = radius * math.cos(rads)\\\
    cfxZones.markZoneWithSmoke(theZone, dx, dz, smokeColor, alt)\\\
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\\\
\\\
function cfxZones.pointInOneOfZones(thePoint, zoneArray, useOrig) \\\
    if not zoneArray then zoneArray = cfxZones.zones end \\\
    for idx, theZone in pairs(zoneArray) do \\\
        local isIn, percent, dist = cfxZones.pointInZone(thePoint, theZone, useOrig)\\\
        if isIn then return isIn, percent, dist, theZone end \\\
    end\\\
    return false, 0, 0, nil \\\
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, useOrig)\\\
\\\
    if not (theZone) then return false, 0, 0 end\\\
        \\\
    local pflat = {x = thePoint.x, y = 0, z = thePoint.z}\\\
    \\\
    local zpoint \\\
    if useOrig then\\\
        zpoint = cfxZones.getDCSOrigin(theZone)\\\
    else \\\
        zpoint = cfxZones.getPoint(theZone) -- updates zone if linked \\\
    end\\\
    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)\\\
    -- store cty and cat for later access. DCS doesn't need it, but we may \\\
    \\\
    theGroup.cty = theSideCJTF\\\
    theGroup.cat = Group.Category.GROUND\\\
    \\\
    -- create a copy of the group data for \\\
    -- later reference \\\
    local groupDataCopy = dcsCommon.clone(theGroup)\\\
\\\
    local newGroup = coalition.addGroup(theSideCJTF, Group.Category.GROUND, theGroup)\\\
    return newGroup, groupDataCopy\\\
end\\\
\\\
--\\\
-- ===============\\\
-- FLAG PROCESSING \\\
-- ===============\\\
--\\\
\\\
--\\\
-- Flag Pulling \\\
--\\\
function cfxZones.pulseFlag(theFlag, method, theZone)\\\
    local args = {}\\\
    args.theFlag = theFlag\\\
    args.method = method\\\
    args.theZone = theZone \\\
    local delay = 3\\\
    if dcsCommon.containsString(method, \\\",\\\") then \\\
        local parts = dcsCommon.splitString(method, \\\",\\\")\\\
        delay = parts[2]\\\
        if delay then delay = tonumber(delay) end  \\\
    end\\\
    if not delay then delay = 3 end \\\
    if theZone.verbose then \\\
        trigger.action.outText(\\\"+++zne: RAISING pulse t=\\\"..delay..\\\" for flag <\\\" .. theFlag .. \\\"> in zone <\\\" .. theZone.name ..\\\">\\\", 30)\\\
    end \\\
    local newVal = 1\\\
    cfxZones.setFlagValue(theFlag, newVal, theZone)\\\
    \\\
    -- schedule second half of pulse \\\
    timer.scheduleFunction(cfxZones.unPulseFlag, args, timer.getTime() + delay)\\\
end\\\
\\\
function cfxZones.unPulseFlag(args)\\\
    local theZone = args.theZone\\\
    local method = args.method \\\
    local theFlag = args.theFlag \\\
    local newVal = 0\\\
    -- we may later use method to determine pulse direction / newVal\\\
    -- for now, we always go low \\\
    if theZone.verbose then \\\
        trigger.action.outText(\\\"+++zne: DOWNPULSE pulse for flag <\\\" .. theFlag .. \\\"> in zone <\\\" .. theZone.name ..\\\">\\\", 30)\\\
    end\\\
    cfxZones.setFlagValue(theFlag, newVal, theZone)\\\
end\\\
\\\
function cfxZones.evalRemainder(remainder)\\\
    local rNum = tonumber(remainder)\\\
    if not rNum then \\\
        -- we use remainder as name for flag \\\
        -- PROCESS ESCAPE SEQUENCES\\\
        local esc = string.sub(remainder, 1, 1)\\\
        local last = string.sub(remainder, -1)\\\
        if esc == \\\"@\\\" then \\\
            remainder = string.sub(remainder, 2)\\\
            remainder = dcsCommon.trim(remainder)\\\
        end\\\
        \\\
        if esc == \\\"(\\\" and last == \\\")\\\" and string.len(remainder) > 2 then \\\
            -- note: iisues with startswith(\\\"(\\\") ???\\\
            remainder = string.sub(remainder, 2, -2)\\\
            remainder = dcsCommon.trim(remainder)        \\\
        end\\\
        if esc == \\\"\\\\\\\"\\\" and last == \\\"\\\\\\\"\\\" and string.len(remainder) > 2 then \\\
            remainder = string.sub(remainder, 2, -2)\\\
            remainder = dcsCommon.trim(remainder)        \\\
        end\\\
        if cfxZones.verbose then \\\
            trigger.action.outText(\\\"+++zne: accessing flag <\\\" .. remainder .. \\\">\\\", 30)\\\
        end \\\
        rNum = cfxZones.getFlagValue(remainder, theZone)\\\
    end \\\
    return rNum\\\
end\\\
\\\
function cfxZones.doPollFlag(theFlag, method, theZone)\\\
    if cfxZones.verbose then \\\
        trigger.action.outText(\\\"+++zones: polling flag \\\" .. theFlag .. \\\" with \\\" .. method, 30)\\\
    end \\\
    \\\
    if not theZone then \\\
        trigger.action.outText(\\\"+++zones: nil theZone on pollFlag\\\", 30)\\\
    end\\\
    \\\
    method = method:lower()\\\
    method = dcsCommon.trim(method)\\\
    val = tonumber(method)\\\
    if dcsCommon.stringStartsWith(method, \\\"+\\\") or dcsCommon.stringStartsWith(method, \\\"-\\\")\\\
    then \\\
        -- skip this processing, a legal Lua val can start with \\\"+\\\" or \\\"-\\\"\\\
        -- but we interpret it as a method\\\
    else\\\
        if val then \\\
            cfxZones.setFlagValue(theFlag, val, theZone)\\\
            if cfxZones.verbose or theZone.verbose then\\\
                trigger.action.outText(\\\"+++zones: flag <\\\" .. theFlag .. \\\"> changed to #\\\" .. val, 30)\\\
            end \\\
            return\\\
        end \\\
    end\\\
    --trigger.action.outText(\\\"+++zones: polling \\\" .. theZone.name .. \\\" method \\\" .. method .. \\\" flag \\\" .. theFlag, 30)\\\
    local currVal = cfxZones.getFlagValue(theFlag, theZone)\\\
    if method == \\\"inc\\\" or method == \\\"f+1\\\" then \\\
        --trigger.action.setUserFlag(theFlag, currVal + 1)\\\
        cfxZones.setFlagValue(theFlag, currVal+1, theZone)\\\
        \\\
    elseif method == \\\"dec\\\" or method == \\\"f-1\\\" then \\\
        -- trigger.action.setUserFlag(theFlag, currVal - 1)\\\
        cfxZones.setFlagValue(theFlag, currVal-1, theZone)\\\
\\\
    elseif method == \\\"off\\\" or method == \\\"f=0\\\" then \\\
        -- trigger.action.setUserFlag(theFlag, 0)\\\
        cfxZones.setFlagValue(theFlag, 0, theZone)\\\
\\\
    elseif method == \\\"flip\\\" or method == \\\"xor\\\" then \\\
        if currVal ~= 0 then \\\
--            trigger.action.setUserFlag(theFlag, 0)\\\
            cfxZones.setFlagValue(theFlag, 0, theZone)\\\
\\\
        else \\\
            --trigger.action.setUserFlag(theFlag, 1)\\\
            cfxZones.setFlagValue(theFlag, 1, theZone)\\\
        end\\\
        \\\
    elseif dcsCommon.stringStartsWith(method, \\\"pulse\\\") then \\\
        cfxZones.pulseFlag(theFlag, method, theZone)\\\
        \\\
    elseif dcsCommon.stringStartsWith(method, \\\"+\\\") then \\\
        -- we add whatever is to the right \\\
        local remainder = dcsCommon.removePrefix(method, \\\"+\\\")\\\
        local adder = cfxZones.evalRemainder(remainder)\\\
        cfxZones.setFlagValue(theFlag, currVal+adder, theZone)\\\
        if theZone.verbose then \\\
            trigger.action.outText(\\\"+++zones: (poll) updating with '+' flag <\\\" .. theFlag .. \\\"> in <\\\" .. theZone.name .. \\\"> by <\\\" .. adder .. \\\"> to <\\\" .. adder + currVal .. \\\">\\\", 30)\\\
        end\\\
        \\\
    elseif dcsCommon.stringStartsWith(method, \\\"-\\\") then \\\
        -- we subtract whatever is to the right \\\
        local remainder = dcsCommon.removePrefix(method, \\\"-\\\")\\\
        local adder = cfxZones.evalRemainder(remainder)\\\
        cfxZones.setFlagValue(theFlag, currVal-adder, theZone)\\\
\\\
    else \\\
        if method ~= \\\"on\\\" and method ~= \\\"f=1\\\" then \\\
            trigger.action.outText(\\\"+++zones: unknown method <\\\" .. method .. \\\"> - using 'on'\\\", 30)\\\
        end\\\
        -- default: on.\\\
--        trigger.action.setUserFlag(theFlag, 1)\\\
        cfxZones.setFlagValue(theFlag, 1, theZone)\\\
    end\\\
    \\\
    if cfxZones.verbose then\\\
        local newVal = cfxZones.getFlagValue(theFlag, theZone)\\\
        trigger.action.outText(\\\"+++zones: flag <\\\" .. theFlag .. \\\"> changed from \\\" .. currVal .. \\\" to \\\" .. newVal, 30)\\\
    end \\\
end\\\
\\\
function cfxZones.pollFlag(theFlag, method, theZone) \\\
    local allFlags = {}\\\
    if dcsCommon.containsString(theFlag, \\\",\\\") then \\\
        if cfxZones.verbose then \\\
            trigger.action.outText(\\\"+++zones: will poll flag set <\\\" .. theFlag .. \\\"> with \\\" .. method, 30)\\\
        end\\\
        allFlags = dcsCommon.splitString(theFlag, \\\",\\\")\\\
    else \\\
        table.insert(allFlags, theFlag)\\\
    end\\\
    \\\
    for idx, aFlag in pairs(allFlags) do \\\
        aFlag = dcsCommon.trim(aFlag)\\\
        -- note: mey require range preprocessing, but that's not\\\
        -- a priority \\\
        cfxZones.doPollFlag(aFlag, method, theZone)\\\
    end \\\
    \\\
end\\\
\\\
function cfxZones.expandFlagName(theFlag, theZone) \\\
    if not theFlag then return \\\"!NIL\\\" end \\\
    local zoneName = \\\"<dummy>\\\"\\\
    if theZone then \\\
        zoneName = theZone.name -- for flag wildcards\\\
    end\\\
    \\\
    if type(theFlag) == \\\"number\\\" then \\\
        -- straight number, return \\\
        return theFlag\\\
    end\\\
    \\\
    -- we assume it's a string now\\\
    theFlag = dcsCommon.trim(theFlag) -- clear leading/trailing spaces\\\
    local nFlag = tonumber(theFlag) \\\
    if nFlag then -- a number, legal\\\
        return theFlag\\\
    end\\\
        \\\
    -- now do wildcard processing. we have alphanumeric\\\
    if dcsCommon.stringStartsWith(theFlag, \\\"*\\\") then  \\\
        theFlag = zoneName .. theFlag\\\
    end\\\
    return theFlag\\\
end\\\
\\\
function cfxZones.setFlagValueMult(theFlag, theValue, theZone)\\\
    local allFlags = {}\\\
    if dcsCommon.containsString(theFlag, \\\",\\\") then \\\
        if cfxZones.verbose then \\\
            trigger.action.outText(\\\"+++zones: will multi-set flags <\\\" .. theFlag .. \\\"> to \\\" .. theValue, 30)\\\
        end\\\
        allFlags = dcsCommon.splitString(theFlag, \\\",\\\")\\\
    else \\\
        table.insert(allFlags, theFlag)\\\
    end\\\
    \\\
    for idx, aFlag in pairs(allFlags) do \\\
        aFlag = dcsCommon.trim(aFlag)\\\
        -- note: mey require range preprocessing, but that's not\\\
        -- a priority \\\
        cfxZones.setFlagValue(aFlag, theValue, theZone)\\\
    end \\\
end\\\
\\\
function cfxZones.setFlagValue(theFlag, theValue, theZone)\\\
    local zoneName = \\\"<dummy>\\\"\\\
    if not theZone then \\\
        trigger.action.outText(\\\"+++Zne: no zone on setFlagValue\\\", 30) -- mod me for detector\\\
    else \\\
        zoneName = theZone.name -- for flag wildcards\\\
    end\\\
    \\\
    if type(theFlag) == \\\"number\\\" then \\\
        -- straight set, ME flag \\\
        trigger.action.setUserFlag(theFlag, theValue)\\\
        return \\\
    end\\\
    \\\
    -- we assume it's a string now\\\
    theFlag = dcsCommon.trim(theFlag) -- clear leading/trailing spaces\\\
    local nFlag = tonumber(theFlag) \\\
    if nFlag then \\\
        trigger.action.setUserFlag(theFlag, theValue)\\\
        return \\\
    end\\\
    \\\
    -- some QoL: detect \\\"<none>\\\"\\\
    if dcsCommon.containsString(theFlag, \\\"<none>\\\") then \\\
        trigger.action.outText(\\\"+++Zone: warning - setFlag has '<none>' flag name in zone <\\\" .. zoneName .. \\\">\\\", 30) -- if error, intended break\\\
    end\\\
    \\\
    -- now do wildcard processing. we have alphanumeric\\\
    if dcsCommon.stringStartsWith(theFlag, \\\"*\\\") then  \\\
        theFlag = zoneName .. theFlag\\\
    end\\\
    trigger.action.setUserFlag(theFlag, theValue)\\\
end \\\
\\\
function cfxZones.getFlagValue(theFlag, theZone)\\\
    local zoneName = \\\"<dummy>\\\"\\\
    if not theZone or not theZone.name then \\\
        trigger.action.outText(\\\"+++Zne: no zone or zone name on getFlagValue\\\", 30)\\\
    else \\\
        zoneName = theZone.name -- for flag wildcards\\\
    end\\\
    \\\
    if type(theFlag) == \\\"number\\\" then \\\
        -- straight get, ME flag \\\
        return tonumber(trigger.misc.getUserFlag(theFlag))\\\
    end\\\
    \\\
    -- we assume it's a string now\\\
    theFlag = dcsCommon.trim(theFlag) -- clear leading/trailing spaces\\\
    local nFlag = tonumber(theFlag) \\\
    if nFlag then \\\
        return tonumber(trigger.misc.getUserFlag(theFlag))\\\
    end\\\
    \\\
    -- some QoL: detect \\\"<none>\\\"\\\
    if dcsCommon.containsString(theFlag, \\\"<none>\\\") then \\\
        trigger.action.outText(\\\"+++Zone: warning - getFlag has '<none>' flag name in zone <\\\" .. zoneName .. \\\">\\\", 30) -- break here\\\
    end\\\
    \\\
    -- now do wildcard processing. we have alphanumeric\\\
    if dcsCommon.stringStartsWith(theFlag, \\\"*\\\") then  \\\
            theFlag = zoneName .. theFlag\\\
    end\\\
    return tonumber(trigger.misc.getUserFlag(theFlag))\\\
end\\\
\\\
function cfxZones.isMEFlag(inFlag)\\\
    -- do NOT use me\\\
    trigger.action.outText(\\\"+++zne: warning: deprecated isMEFlag\\\", 30)\\\
    return true \\\
    -- returns true if inFlag is a pure positive number\\\
end\\\
\\\
function cfxZones.verifyMethod(theMethod, theZone)\\\
    local lMethod = string.lower(theMethod)\\\
    if lMethod == \\\"#\\\" or lMethod == \\\"change\\\" then \\\
        return true\\\
    end\\\
\\\
    if lMethod == \\\"0\\\" or lMethod == \\\"no\\\" or lMethod == \\\"false\\\" \\\
       or lMethod == \\\"off\\\" then \\\
        return true  \\\
    end\\\
    \\\
    if lMethod == \\\"1\\\" or lMethod == \\\"yes\\\" or lMethod == \\\"true\\\" \\\
       or lMethod == \\\"on\\\" then \\\
        return true  \\\
    end\\\
    \\\
    if lMethod == \\\"inc\\\" or lMethod == \\\"+1\\\" then \\\
        return true\\\
    end\\\
    \\\
    if lMethod == \\\"dec\\\" or lMethod == \\\"-1\\\" then \\\
        return true \\\
    end \\\
    \\\
    if lMethod == \\\"lohi\\\" or lMethod == \\\"pulse\\\" then \\\
        return true\\\
    end\\\
    \\\
    if lMethod == \\\"hilo\\\" then \\\
        return true\\\
    end\\\
    \\\
    -- number constraints\\\
    -- or flag constraints     -- ONLY RETURN TRUE IF CHANGE AND CONSTRAINT MET \\\
    local op = string.sub(theMethod, 1, 1) \\\
    local remainder = string.sub(theMethod, 2)\\\
    remainder = dcsCommon.trim(remainder) -- remove all leading and trailing spaces\\\
\\\
    if true then \\\
        -- we have a comparison = \\\">\\\", \\\"=\\\", \\\"<\\\" followed by a number \\\
        -- THEY TRIGGER EACH TIME lastVal <> currVal AND condition IS MET  \\\
        if op == \\\"=\\\" then \\\
            return true\\\
        end\\\
        \\\
        if op == \\\"#\\\" or op == \\\"~\\\" then \\\
            return true\\\
        end \\\
        \\\
        if op == \\\"<\\\" then \\\
            return true\\\
        end\\\
        \\\
        if op == \\\">\\\" then \\\
            return true\\\
        end\\\
    end\\\
    \\\
    return false \\\
end\\\
\\\
-- method-based flag testing \\\
function cfxZones.evalFlagMethodImmediate(currVal, theMethod, theZone)\\\
    -- immediate eval - does not look at last val. \\\
    -- return true/false/value based on theMethod's contraints \\\
    -- simple constraints\\\
    local lMethod = string.lower(theMethod)\\\
    if lMethod == \\\"#\\\" or lMethod == \\\"change\\\" then \\\
        -- ALWAYS RETURNS TRUE for currval <> 0, flase if currval = 0\\\
        return currVal ~= 0  \\\
    end\\\
    \\\
    if lMethod == \\\"0\\\" or lMethod == \\\"no\\\" or lMethod == \\\"false\\\" \\\
       or lMethod == \\\"off\\\" then \\\
        -- WARNING: ALWAYS RETURNS FALSE\\\
        return false  \\\
    end\\\
    \\\
    if lMethod == \\\"1\\\" or lMethod == \\\"yes\\\" or lMethod == \\\"true\\\" \\\
       or lMethod == \\\"on\\\" then \\\
        -- WARNING: ALWAYS RETURNS TRUE\\\
        return true  \\\
    end\\\
    \\\
    if lMethod == \\\"inc\\\" or lMethod == \\\"+1\\\" then \\\
        return currVal+1 -- this may be unexpected\\\
    end\\\
    \\\
    if lMethod == \\\"dec\\\" or lMethod == \\\"-1\\\" then \\\
        return currVal-1 -- this may be unexpectd\\\
    end \\\
    \\\
    -- number constraints\\\
    -- or flag constraints \\\
    -- ONLY RETURN TRUE IF CHANGE AND CONSTRAINT MET \\\
    local op = string.sub(theMethod, 1, 1) \\\
    local remainder = string.sub(theMethod, 2)\\\
    remainder = dcsCommon.trim(remainder) -- remove all leading and trailing spaces\\\
    local rNum = tonumber(remainder)\\\
    if not rNum then \\\
        -- we use remainder as name for flag \\\
        -- PROCESS ESCAPE SEQUENCES\\\
        local esc = string.sub(remainder, 1, 1)\\\
        local last = string.sub(remainder, -1)\\\
        if esc == \\\"@\\\" then \\\
            remainder = string.sub(remainder, 2)\\\
            remainder = dcsCommon.trim(remainder)\\\
        end\\\
        \\\
        if esc == \\\"(\\\" and last == \\\")\\\" and string.len(remainder) > 2 then \\\
            -- note: iisues with startswith(\\\"(\\\") ???\\\
            remainder = string.sub(remainder, 2, -2)\\\
            remainder = dcsCommon.trim(remainder)        \\\
        end\\\
        if esc == \\\"\\\\\\\"\\\" and last == \\\"\\\\\\\"\\\" and string.len(remainder) > 2 then \\\
            remainder = string.sub(remainder, 2, -2)\\\
            remainder = dcsCommon.trim(remainder)        \\\
        end\\\
        if cfxZones.verbose then \\\
            trigger.action.outText(\\\"+++zne: accessing flag <\\\" .. remainder .. \\\">\\\", 30)\\\
        end \\\
        rNum = cfxZones.getFlagValue(remainder, theZone)\\\
    end \\\
    if rNum then \\\
        -- we have a comparison = \\\">\\\", \\\"=\\\", \\\"<\\\" followed by a number  \\\
        if op == \\\"=\\\" then \\\
            return currVal == rNum\\\
        end\\\
        \\\
        if op == \\\"#\\\" or op == \\\"~\\\" then \\\
            return currVal ~= rNum \\\
        end \\\
        \\\
        if op == \\\"<\\\" then \\\
            return currVal < rNum\\\
        end\\\
        \\\
        if op == \\\">\\\" then \\\
            return currVal > rNum\\\
        end\\\
    end\\\
    \\\
    -- if we get here, we have an error \\\
    local zoneName = \\\"<NIL>\\\"\\\
    if theZone then zoneName = theZone.name end \\\
    trigger.action.outText(\\\"+++Zne: illegal |\\\" .. theMethod .. \\\"| in eval for zone \\\" .. zoneName, 30 )\\\
    return false     \\\
end\\\
\\\
function cfxZones.testFlagByMethodForZone(currVal, lastVal, theMethod, theZone)\\\
    -- return true/false based on theMethod's contraints \\\
    -- simple constraints\\\
    -- ONLY RETURN TRUE IF CHANGE AND CONSTRAINT MET \\\
    local lMethod = string.lower(theMethod)\\\
    if lMethod == \\\"#\\\" or lMethod == \\\"change\\\" then \\\
        -- check if currVal different from lastVal\\\
        return currVal ~= lastVal  \\\
    end\\\
    \\\
    if lMethod == \\\"0\\\" or lMethod == \\\"no\\\" or lMethod == \\\"false\\\" \\\
       or lMethod == \\\"off\\\" then \\\
        -- WARNING: ONLY RETURNS TRUE IF FALSE AND lastval not zero!\\\
        return currVal == 0 and currVal ~= lastVal  \\\
    end\\\
    \\\
    if lMethod == \\\"1\\\" or lMethod == \\\"yes\\\" or lMethod == \\\"true\\\" \\\
       or lMethod == \\\"on\\\" then \\\
        -- WARNING: only returns true if lastval was false!!!!\\\
        return (currVal ~= 0 and lastVal == 0)  \\\
    end\\\
    \\\
    if lMethod == \\\"inc\\\" or lMethod == \\\"+1\\\" then \\\
--        return currVal == lastVal+1 -- better: test for greater than \\\
        return currVal > lastVal\\\
    end\\\
    \\\
    if lMethod == \\\"dec\\\" or lMethod == \\\"-1\\\" then \\\
        --return currVal == lastVal-1\\\
        return currVal < lastVal \\\
    end \\\
    \\\
    if lMethod == \\\"lohi\\\" or lMethod == \\\"pulse\\\" then \\\
        return (lastVal <= 0 and currVal > 0)\\\
    end\\\
    \\\
    if lMethod == \\\"hilo\\\" then \\\
        return (lastVal > 0 and currVal <= 0)\\\
    end\\\
    \\\
    -- number constraints\\\
    -- or flag constraints \\\
    -- ONLY RETURN TRUE IF CHANGE AND CONSTRAINT MET \\\
    local op = string.sub(theMethod, 1, 1) \\\
    local remainder = string.sub(theMethod, 2)\\\
    remainder = dcsCommon.trim(remainder) -- remove all leading and trailing spaces\\\
    local rNum = tonumber(remainder)\\\
    if not rNum then \\\
        -- we use remainder as name for flag \\\
        -- PROCESS ESCAPE SEQUENCES\\\
        local esc = string.sub(remainder, 1, 1)\\\
        local last = string.sub(remainder, -1)\\\
        if esc == \\\"@\\\" then \\\
            remainder = string.sub(remainder, 2)\\\
            remainder = dcsCommon.trim(remainder)\\\
        end\\\
        \\\
        if esc == \\\"(\\\" and last == \\\")\\\" and string.len(remainder) > 2 then \\\
            -- note: iisues with startswith(\\\"(\\\") ???\\\
            remainder = string.sub(remainder, 2, -2)\\\
            remainder = dcsCommon.trim(remainder)        \\\
        end\\\
        if esc == \\\"\\\\\\\"\\\" and last == \\\"\\\\\\\"\\\" and string.len(remainder) > 2 then \\\
            remainder = string.sub(remainder, 2, -2)\\\
            remainder = dcsCommon.trim(remainder)        \\\
        end\\\
        if cfxZones.verbose then \\\
            trigger.action.outText(\\\"+++zne: accessing flag <\\\" .. remainder .. \\\">\\\", 30)\\\
        end \\\
        rNum = cfxZones.getFlagValue(remainder, theZone)\\\
    end \\\
    if rNum then \\\
        -- we have a comparison = \\\">\\\", \\\"=\\\", \\\"<\\\" followed by a number \\\
        -- THEY TRIGGER EACH TIME lastVal <> currVal AND condition IS MET  \\\
        if op == \\\"=\\\" then \\\
            return currVal == rNum and lastVal ~= currVal\\\
        end\\\
        \\\
        if op == \\\"#\\\" or op == \\\"~\\\" then \\\
            return currVal ~= rNum and lastVal ~= currVal \\\
        end \\\
        \\\
        if op == \\\"<\\\" then \\\
            return currVal < rNum and lastVal ~= currVal\\\
        end\\\
        \\\
        if op == \\\">\\\" then \\\
            return currVal > rNum and lastVal ~= currVal\\\
        end\\\
    end\\\
    \\\
    -- if we get here, we have an error \\\
    local zoneName = \\\"<NIL>\\\"\\\
    if theZone then zoneName = theZone.name end \\\
    trigger.action.outText(\\\"+++Zne: illegal method constraints |\\\" .. theMethod .. \\\"| for zone \\\" .. zoneName, 30 )\\\
    return false \\\
end\\\
\\\
\\\
function cfxZones.testZoneFlag(theZone, theFlagName, theMethod, latchName)\\\
    -- returns two values: true/false method result, and curr value\\\
    -- returns true if method constraints are met for flag theFlagName\\\
    -- as defined by theMethod \\\
    if not theMethod then \\\
        theMethod = \\\"change\\\"\\\
    end \\\
    \\\
    -- will read and update theZone[latchName] as appropriate \\\
    if not theZone then \\\
        trigger.action.outText(\\\"+++Zne: no zone for testZoneFlag\\\", 30)\\\
        return nil, nil \\\
    end \\\
    if not theFlagName then \\\
        -- this is common, no error, only on verbose \\\
        if cfxZones.verbose then \\\
            trigger.action.outText(\\\"+++Zne: no flagName for zone \\\" .. theZone.name .. \\\" for testZoneFlag\\\", 30)\\\
        end \\\
        return nil, nil\\\
    end\\\
    if not latchName then \\\
        trigger.action.outText(\\\"+++Zne: no latchName for zone \\\" .. theZone.name .. \\\" for testZoneFlag\\\", 30)\\\
        return nil, nil \\\
    end\\\
    -- get current value \\\
    local currVal = cfxZones.getFlagValue(theFlagName, theZone)\\\
    \\\
    -- get last value from latch\\\
    local lastVal = theZone[latchName]\\\
    if not lastVal then \\\
        trigger.action.outText(\\\"+++Zne: latch <\\\" .. latchName .. \\\"> not valid for zone \\\" .. theZone.name, 30) -- intentional break here \\\
        return nil, nil\\\
    end\\\
    \\\
    -- now, test by method \\\
    -- we should only test if currVal <> lastVal \\\
    if currVal == lastVal then\\\
        return false, currVal\\\
    end \\\
    \\\
    --trigger.action.outText(\\\"+++Zne: about to test: c = \\\" .. currVal .. \\\", l = \\\" .. lastVal, 30)\\\
    local testResult = cfxZones.testFlagByMethodForZone(currVal, lastVal, theMethod, theZone)\\\
\\\
    -- update latch by method\\\
    theZone[latchName] = currVal \\\
\\\
    -- return result\\\
    return testResult, currVal\\\
end\\\
\\\
\\\
\\\
function cfxZones.flagArrayFromString(inString)\\\
-- original code from RND flag\\\
    if string.len(inString) < 1 then \\\
        trigger.action.outText(\\\"+++zne: empty flags\\\", 30)\\\
        return {} \\\
    end\\\
    if cfxZones.verbose then \\\
        trigger.action.outText(\\\"+++zne: processing <\\\" .. inString .. \\\">\\\", 30)\\\
    end \\\
    \\\
    local flags = {}\\\
    local rawElements = dcsCommon.splitString(inString, \\\",\\\")\\\
    -- go over all elements \\\
    for idx, anElement in pairs(rawElements) do \\\
        anElement = dcsCommon.trim(anElement)\\\
        if dcsCommon.stringStartsWithDigit(anElement) and dcsCommon.containsString(anElement, \\\"-\\\") then \\\
            -- interpret this as a range\\\
            local theRange = dcsCommon.splitString(anElement, \\\"-\\\")\\\
            local lowerBound = theRange[1]\\\
            lowerBound = tonumber(lowerBound)\\\
            local upperBound = theRange[2]\\\
            upperBound = tonumber(upperBound)\\\
            if lowerBound and upperBound then\\\
                -- swap if wrong order\\\
                if lowerBound > upperBound then \\\
                    local temp = upperBound\\\
                    upperBound = lowerBound\\\
                    lowerBound = temp \\\
                end\\\
                -- now add add numbers to flags\\\
                for f=lowerBound, upperBound do \\\
                    table.insert(flags, tostring(f))\\\
                end\\\
            else\\\
                -- bounds illegal\\\
                trigger.action.outText(\\\"+++zne: ignored range <\\\" .. anElement .. \\\"> (range)\\\", 30)\\\
            end\\\
        else\\\
            -- single number\\\
            f = dcsCommon.trim(anElement) -- DML flag upgrade: accept strings tonumber(anElement)\\\
            if f then \\\
                table.insert(flags, f)\\\
\\\
            else \\\
                trigger.action.outText(\\\"+++zne: ignored element <\\\" .. anElement .. \\\"> (single)\\\", 30)\\\
            end\\\
        end\\\
    end\\\
    if cfxZones.verbose then \\\
        trigger.action.outText(\\\"+++zne: <\\\" .. #flags .. \\\"> flags total\\\", 30)\\\
    end \\\
    return flags\\\
end\\\
\\\
--\\\
-- ===================\\\
-- PROPERTY PROCESSING\\\
-- =================== \\\
--\\\
\\\
function cfxZones.getAllZoneProperties(theZone, caseInsensitive, numbersOnly) -- return as dict \\\
    if not caseInsensitive then caseInsensitive = false end \\\
    if not numbersOnly then numbersOnly = 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 \\\
        local v = theProp.value \\\
        if numbersOnly then \\\
            v = tonumber(v)\\\
            if not v then v = 0 end \\\
        end\\\
        props[theKey] = v\\\
    end\\\
    return props \\\
end\\\
\\\
function cfxZones.extractPropertyFromDCS(theKey, theProperties)\\\
-- trim\\\
    theKey = dcsCommon.trim(theKey) \\\
--    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 = dcsCommon.trim(theP.key)  \\\
        if not cfxZones.caseSensitiveProperties then \\\
            existingKey = string.lower(existingKey)\\\
        end\\\
        if existingKey == theKey then \\\
            return theP.value\\\
        end\\\
        \\\
        -- now check after removing all blanks \\\
        existingKey = dcsCommon.removeBlanks(existingKey)\\\
        if existingKey == theKey then \\\
            return theP.value\\\
        end\\\
    end\\\
    return nil \\\
end\\\
\\\
function cfxZones.getZoneProperty(cZone, theKey)\\\
    if not cZone then \\\
        trigger.action.outText(\\\"+++zone: no zone in getZoneProperty\\\", 30)\\\
--        breek.here.noew = 1\\\
        return nil\\\
    end \\\
    if not theKey then \\\
        trigger.action.outText(\\\"+++zone: no property key in getZoneProperty for zone \\\" .. cZone.name, 30)\\\
--        breakme.here = 1\\\
        return \\\
    end    \\\
\\\
    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 \\\
        p = dcsCommon.trim(p)\\\
        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.randomInRange(minVal, maxVal)\\\
    if maxVal < minVal then \\\
        local t = minVal\\\
        minVal = maxVal \\\
        maxVal = t\\\
    end\\\
    return cfxZones.randomDelayFromPositiveRange(minVal, maxVal)\\\
end\\\
\\\
function cfxZones.randomDelayFromPositiveRange(minVal, maxVal) \\\
    if not maxVal then return minVal end \\\
    if not minVal then return maxVal end \\\
    local delay = maxVal\\\
    if minVal > 0 and minVal < delay then \\\
        -- we want a randomized from time from minTime .. delay\\\
        local varPart = delay - minVal + 1\\\
        varPart = dcsCommon.smallRandom(varPart) - 1\\\
        delay = minVal + varPart\\\
    end\\\
    return delay \\\
end\\\
\\\
function cfxZones.getPositiveRangeFromZoneProperty(theZone, theProperty, default, defaultmax)\\\
    -- reads property as string, and interprets as range 'a-b'. \\\
    -- if not a range but single number, returns both for upper and lower \\\
    --trigger.action.outText(\\\"***Zne: enter with <\\\" .. theZone.name .. \\\">: range for property <\\\" .. theProperty .. \\\">!\\\", 30)\\\
    if not default then default = 0 end \\\
    if not defaultmax then defaultmax = default end \\\
    \\\
    local lowerBound = default\\\
    local upperBound = defaultmax \\\
    \\\
    local rangeString = cfxZones.getStringFromZoneProperty(theZone, theProperty, \\\"\\\")\\\
    if dcsCommon.containsString(rangeString, \\\"-\\\") then \\\
        local theRange = dcsCommon.splitString(rangeString, \\\"-\\\")\\\
        lowerBound = theRange[1]\\\
        lowerBound = tonumber(lowerBound)\\\
        upperBound = theRange[2]\\\
        upperBound = tonumber(upperBound)\\\
        if lowerBound and upperBound then\\\
            -- swap if wrong order\\\
            if lowerBound > upperBound then \\\
                local temp = upperBound\\\
                upperBound = lowerBound\\\
                lowerBound = temp \\\
            end\\\
\\\
        else\\\
            -- bounds illegal\\\
            trigger.action.outText(\\\"+++Zne: illegal range  <\\\" .. rangeString .. \\\">, using \\\" .. default .. \\\"-\\\" .. defaultmax, 30)\\\
            lowerBound = default\\\
            upperBound = defaultmax \\\
        end\\\
    else \\\
        upperBound = cfxZones.getNumberFromZoneProperty(theZone, theProperty, defaultmax) -- between pulses \\\
        lowerBound = upperBound\\\
    end\\\
\\\
    return lowerBound, upperBound\\\
end\\\
\\\
function cfxZones.hasProperty(theZone, theProperty) \\\
    if not theProperty then \\\
        trigger.action.outText(\\\"+++zne: WARNING - hasProperty called with nil theProperty for zone <\\\" .. theZone.name .. \\\">\\\", 30)\\\
        return false \\\
    end \\\
    local foundIt = cfxZones.getZoneProperty(theZone, theProperty)\\\
    if not foundIt then \\\
        -- check for possible forgotten or exchanged IO flags \\\
        if string.sub(theProperty, -1) == \\\"?\\\" then\\\
            local lessOp = theProperty:sub(1,-2)\\\
            if cfxZones.getZoneProperty(theZone, lessOp) ~= nil then \\\
                trigger.action.outText(\\\"*** NOTE: \\\" .. theZone.name .. \\\"'s property <\\\" .. lessOp .. \\\"> may be missing a Query ('?') symbol\\\", 30)\\\
            end\\\
            local lessPlus = lessOp .. \\\"!\\\"\\\
            if cfxZones.getZoneProperty(theZone, lessPlus) ~= nil then \\\
                trigger.action.outText(\\\"*** NOTE: \\\" .. theZone.name .. \\\"'s property <\\\" .. lessOp .. \\\"> may be using '!' instead of '?' for input\\\", 30)\\\
            end\\\
            return false \\\
        end\\\
        \\\
        if string.sub(theProperty, -1) == \\\"!\\\" then \\\
            local lessOp = theProperty:sub(1,-2)\\\
            if cfxZones.getZoneProperty(theZone, lessOp) ~= nil then \\\
                trigger.action.outText(\\\"*** NOTE: \\\" .. theZone.name .. \\\"'s property <\\\" .. lessOp .. \\\"> may be missing a Bang! ('!') symbol\\\", 30)\\\
            end\\\
            local lessPlus = lessOp .. \\\"?\\\"\\\
            if cfxZones.getZoneProperty(theZone, lessPlus) ~= nil then \\\
                trigger.action.outText(\\\"*** NOTE: \\\" .. theZone.name .. \\\"'s property <\\\" .. lessOp .. \\\"> may be using '!' instead of '?' for input\\\", 30)\\\
            end\\\
            return false \\\
        end\\\
        \\\
        if string.sub(theProperty, -1) == \\\":\\\" then \\\
            local lessOp = theProperty:sub(1,-2)\\\
            if cfxZones.getZoneProperty(theZone, lessOp) ~= nil then \\\
                trigger.action.outText(\\\"*** NOTE: \\\" .. theZone.name .. \\\"'s property <\\\" .. lessOp .. \\\"> may be missing a colon (':') at end\\\", 30)\\\
            end\\\
            return false \\\
        end\\\
        \\\
        return false \\\
    end\\\
    return true \\\
--    return foundIt ~= 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() \\\
    p = dcsCommon.trim(p) \\\
    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\\\
\\\
function cfxZones.getRGBVectorFromZoneProperty(theZone, theProperty, defaultVal)\\\
    if not defaultVal then defaultVal = {1.0, 1.0, 1.0} end \\\
    if #defaultVal ~=3 then defaultVal = {1.0, 1.0, 1.0} end\\\
    local s = cfxZones.getStringFromZoneProperty(theZone, theProperty, \\\"\\\")\\\
    local sVec = dcsCommon.splitString(s, \\\",\\\")\\\
    local nVec = {}\\\
    for i = 1, 3 do \\\
        n = sVec[i]\\\
        if n then n = tonumber(n) end \\\
        if not n then n = defaultVal[i] end \\\
        if n > 1.0 then n = 1.0 end\\\
        if n < 0 then n = 0 end \\\
        nVec[i] = n\\\
    end\\\
        \\\
    return nVec \\\
end\\\
\\\
function cfxZones.getRGBAVectorFromZoneProperty(theZone, theProperty, defaultVal)\\\
    if not defaultVal then defaultVal = {1.0, 1.0, 1.0, 1.0} end \\\
    if #defaultVal ~=4 then defaultVal = {1.0, 1.0, 1.0, 1.0} end\\\
    local s = cfxZones.getStringFromZoneProperty(theZone, theProperty, \\\"\\\")\\\
    s = dcsCommon.trim(s)\\\
    if s:sub(1,1) == \\\"#\\\" then \\\
        -- it's probably a \\\"#RRGGBBAA\\\" format hex string \\\
        local hVec = dcsCommon.hexString2RGBA(s)\\\
        if hVec then return hVec end \\\
    end\\\
\\\
    local sVec = dcsCommon.splitString(s, \\\",\\\")\\\
    local nVec = {}\\\
    for i = 1, 4 do \\\
        n = sVec[i]\\\
        if n then n = tonumber(n) end \\\
        if not n then n = defaultVal[i] end \\\
        if n > 1.0 then n = 1.0 end\\\
        if n < 0 then n = 0 end \\\
        nVec[i] = n\\\
    end\\\
        \\\
    return nVec \\\
end\\\
\\\
function cfxZones.getRGBFromZoneProperty(theZone, theProperty, default)\\\
    --if not default then default = {1.0, 1.0, 1.0} end -- white \\\
    local rawRGB = cfxZones.getVectorFromZoneProperty(theZone, theProperty, 3, 1.0)\\\
    local retVal = {}\\\
    for i = 1, 3 do \\\
        local cp = rawRGB[i]\\\
        if cp > 1.0 then cp = 1.0 end\\\
        if cp < 0 then cp = 0 end \\\
        retVal[i] = cp\\\
    end\\\
    return retVal\\\
end\\\
\\\
\\\
function cfxZones.getSmokeColorStringFromZoneProperty(theZone, theProperty, default) -- smoke as 'red', 'green', or 1..5\\\
    if not default then default = \\\"red\\\" end \\\
    local s = cfxZones.getStringFromZoneProperty(theZone, theProperty, default)\\\
    s = s:lower()\\\
    s = dcsCommon.trim(s)\\\
    -- check numbers \\\
    if (s == \\\"0\\\") then return \\\"green\\\" end\\\
    if (s == \\\"1\\\") then return \\\"red\\\" end\\\
    if (s == \\\"2\\\") then return \\\"white\\\" end\\\
    if (s == \\\"3\\\") then return \\\"orange\\\" end\\\
    if (s == \\\"4\\\") then return \\\"blue\\\" end\\\
    \\\
    if s == \\\"green\\\" or\\\
       s == \\\"red\\\" or\\\
       s == \\\"white\\\" or\\\
       s == \\\"orange\\\" or\\\
       s == \\\"blue\\\" then return s end\\\
\\\
    return default \\\
end\\\
\\\
function cfxZones.getFlareColorStringFromZoneProperty(theZone, theProperty, default) -- smoke as 'red', 'green', or 1..5\\\
    if not default then default = \\\"red\\\" end \\\
    local s = cfxZones.getStringFromZoneProperty(theZone, theProperty, default)\\\
    s = s:lower()\\\
    s = dcsCommon.trim(s)\\\
    -- check numbers \\\
    if (s == \\\"rnd\\\") then return \\\"random\\\" end \\\
    if (s == \\\"0\\\") then return \\\"green\\\" end\\\
    if (s == \\\"1\\\") then return \\\"red\\\" end\\\
    if (s == \\\"2\\\") then return \\\"white\\\" end\\\
    if (s == \\\"3\\\") then return \\\"yellow\\\" end\\\
    if (s == \\\"-1\\\") then return \\\"random\\\" end  \\\
    \\\
    if s == \\\"green\\\" or\\\
       s == \\\"red\\\" or\\\
       s == \\\"white\\\" or\\\
       s == \\\"yellow\\\" or \\\
       s == \\\"random\\\" then\\\
    return s end\\\
\\\
    return default \\\
end\\\
\\\
\\\
--\\\
-- Zone-based wildcard processing\\\
-- \\\
\\\
-- process <z>\\\
function cfxZones.processZoneStatics(inMsg, theZone)\\\
    if theZone then \\\
        inMsg = inMsg:gsub(\\\"<z>\\\", theZone.name)\\\
    end\\\
    return inMsg \\\
end\\\
\\\
-- process <t>, <lat>, <lon>, <ele>, <mgrs> \\\
function cfxZones.processSimpleZoneDynamics(inMsg, theZone, timeFormat, imperialUnits)\\\
    if not inMsg then return \\\"<nil inMsg>\\\" end\\\
    -- replace <t> with current mission time HMS\\\
    local absSecs = timer.getAbsTime()-- + env.mission.start_time\\\
    while absSecs > 86400 do \\\
        absSecs = absSecs - 86400 -- subtract out all days \\\
    end\\\
    if not timeFormat then timeFormat = \\\"<:h>:<:m>:<:s>\\\" end \\\
    local timeString  = dcsCommon.processHMS(timeFormat, absSecs)\\\
    local outMsg = inMsg:gsub(\\\"<t>\\\", timeString)\\\
    \\\
    -- replace <lat> with lat of zone point and <lon> with lon of zone point \\\
    -- and <mgrs> with mgrs coords of zone point \\\
    local currPoint = cfxZones.getPoint(theZone)\\\
    local lat, lon = coord.LOtoLL(currPoint)\\\
    lat, lon = dcsCommon.latLon2Text(lat, lon)\\\
    local alt = land.getHeight({x = currPoint.x, y = currPoint.z})\\\
    if imperialUnits then \\\
        alt = math.floor(alt * 3.28084) -- feet \\\
    else \\\
        alt = math.floor(alt) -- meters \\\
    end \\\
    outMsg = outMsg:gsub(\\\"<lat>\\\", lat)\\\
    outMsg = outMsg:gsub(\\\"<lon>\\\", lon)\\\
    outMsg = outMsg:gsub(\\\"<ele>\\\", alt)\\\
    local grid = coord.LLtoMGRS(coord.LOtoLL(currPoint))\\\
    local mgrs = grid.UTMZone .. ' ' .. grid.MGRSDigraph .. ' ' .. grid.Easting .. ' ' .. grid.Northing\\\
    outMsg = outMsg:gsub(\\\"<mgrs>\\\", mgrs)\\\
    return outMsg\\\
end \\\
\\\
-- process <v: flag>, <rsp: flag> <rrnd>\\\
function cfxZones.processDynamicValues(inMsg, theZone, msgResponses)\\\
    -- replace all occurences of <v: flagName> with their values \\\
    local pattern = \\\"<v:%s*[%s%w%*%d%.%-_]+>\\\" -- no list allowed but blanks and * and . and - and _ --> we fail on the other specials to keep this simple \\\
    local outMsg = inMsg\\\
    repeat -- iterate all patterns one by one \\\
        local startLoc, endLoc = string.find(outMsg, pattern)\\\
        if startLoc then \\\
            local theValParam = string.sub(outMsg, startLoc, endLoc)\\\
            -- strip lead and trailer \\\
            local param = string.gsub(theValParam, \\\"<v:%s*\\\", \\\"\\\")\\\
            param = string.gsub(param, \\\">\\\",\\\"\\\")\\\
            -- param = dcsCommon.trim(param) -- trim is called anyway\\\
            -- access flag\\\
            local val = cfxZones.getFlagValue(param, theZone)\\\
            val = tostring(val)\\\
            if not val then val = \\\"NULL\\\" end \\\
            -- replace pattern in original with new val \\\
            outMsg = string.gsub(outMsg, pattern, val, 1) -- only one sub!\\\
        end\\\
    until not startLoc\\\
    \\\
    -- now process rsp \\\
    pattern = \\\"<rsp:%s*[%s%w%*%d%.%-_]+>\\\" -- no list allowed but blanks and * and . and - and _ --> we fail on the other specials to keep this simple \\\
\\\
    if msgResponses and (#msgResponses > 0) then -- only if this zone has an array\\\
        --trigger.action.outText(\\\"enter response proccing\\\", 30)\\\
        repeat -- iterate all patterns one by one \\\
            local startLoc, endLoc = string.find(outMsg, pattern)\\\
            if startLoc then \\\
                --trigger.action.outText(\\\"response: found an occurence\\\", 30)\\\
                local theValParam = string.sub(outMsg, startLoc, endLoc)\\\
                -- strip lead and trailer \\\
                local param = string.gsub(theValParam, \\\"<rsp:%s*\\\", \\\"\\\")\\\
                param = string.gsub(param, \\\">\\\",\\\"\\\")\\\
                \\\
                -- access flag\\\
                local val = cfxZones.getFlagValue(param, theZone)\\\
                if not val or (val < 1) then val = 1 end \\\
                if val > msgResponses then val = msgResponses end \\\
                \\\
                val = msgResponses[val]\\\
                val = dcsCommon.trim(val)\\\
                -- replace pattern in original with new val \\\
                outMsg = string.gsub(outMsg, pattern, val, 1) -- only one sub!\\\
            end\\\
        until not startLoc\\\
        \\\
        -- rnd response \\\
        local rndRsp = dcsCommon.pickRandom(msgResponses)\\\
        outMsg = outMsg:gsub (\\\"<rrnd>\\\", rndRsp)\\\
    end\\\
    \\\
    return outMsg\\\
end\\\
\\\
-- process <t: flag>\\\
function cfxZones.processDynamicTime(inMsg, theZone, timeFormat)\\\
    if not timeFormat then timeFormat = \\\"<:h>:<:m>:<:s>\\\" end\\\
    -- replace all occurences of <t: flagName> with their values \\\
    local pattern = \\\"<t:%s*[%s%w%*%d%.%-_]+>\\\" -- no list allowed but blanks and * and . and - and _ --> we fail on the other specials to keep this simple \\\
    local outMsg = inMsg\\\
    repeat -- iterate all patterns one by one \\\
        local startLoc, endLoc = string.find(outMsg, pattern)\\\
        if startLoc then \\\
            local theValParam = string.sub(outMsg, startLoc, endLoc)\\\
            -- strip lead and trailer \\\
            local param = string.gsub(theValParam, \\\"<t:%s*\\\", \\\"\\\")\\\
            param = string.gsub(param, \\\">\\\",\\\"\\\")\\\
            -- access flag\\\
            local val = cfxZones.getFlagValue(param, theZone)\\\
            -- use this to process as time value \\\
            --trigger.action.outText(\\\"time: accessing <\\\" .. param .. \\\"> and received <\\\" .. val .. \\\">\\\", 30)\\\
            local timeString  = dcsCommon.processHMS(timeFormat, val)\\\
            \\\
            if not timeString then timeString = \\\"NULL\\\" end \\\
            -- replace pattern in original with new val \\\
            outMsg = string.gsub(outMsg, pattern, timeString, 1) -- only one sub!\\\
        end\\\
    until not startLoc\\\
    return outMsg\\\
end\\\
\\\
-- process <lat/lon/ele/mgrs/lle/latlon/alt/vel/hdg/rhdg/type/player: zone/unit>\\\
function cfxZones.processDynamicLoc(inMsg, imperialUnits, responses)\\\
    local locales = {\\\"lat\\\", \\\"lon\\\", \\\"ele\\\", \\\"mgrs\\\", \\\"lle\\\", \\\"latlon\\\", \\\"alt\\\", \\\"vel\\\", \\\"hdg\\\", \\\"rhdg\\\", \\\"type\\\", \\\"player\\\"}\\\
    local outMsg = inMsg\\\
    local uHead = 0\\\
    for idx, aLocale in pairs(locales) do \\\
        local pattern = \\\"<\\\" .. aLocale .. \\\":%s*[%s%w%*%d%.%-_]+>\\\"\\\
        repeat -- iterate all patterns one by one \\\
            local startLoc, endLoc = string.find(outMsg, pattern)\\\
            if startLoc then\\\
                local theValParam = string.sub(outMsg, startLoc, endLoc)\\\
                -- strip lead and trailer \\\
                local param = string.gsub(theValParam, \\\"<\\\" .. aLocale .. \\\":%s*\\\", \\\"\\\")\\\
                param = string.gsub(param, \\\">\\\",\\\"\\\")\\\
                -- find zone or unit\\\
                param = dcsCommon.trim(param)\\\
                local thePoint = nil \\\
                local tZone = cfxZones.getZoneByName(param)\\\
                local tUnit = Unit.getByName(param)\\\
                local spd = 0\\\
                local angels = 0 \\\
                local theType = \\\"<errType>\\\"\\\
                local playerName = \\\"Unknown\\\"\\\
                if tZone then\\\
                    theType = \\\"Zone\\\"\\\
                    playerName = \\\"?zone?\\\"\\\
                    thePoint = cfxZones.getPoint(tZone)\\\
                    if tZone.linkedUnit and Unit.isExist(tZone.linkedUnit) then \\\
                        local lU = tZone.linkedUnit\\\
                        local masterPoint = lU:getPoint()\\\
                        thePoint.y = masterPoint.y \\\
                        spd = dcsCommon.getUnitSpeed(lU)\\\
                        spd = math.floor(spd * 3.6)\\\
                        uHead = math.floor(dcsCommon.getUnitHeading(tUnit) * 57.2958) -- to degrees.\\\
                    else \\\
                        -- since zones always have elevation of 0, \\\
                        -- now get the elevation from the map \\\
                        thePoint.y = land.getHeight({x = thePoint.x, y = thePoint.z})\\\
                    end\\\
                elseif tUnit then \\\
                    if Unit.isExist(tUnit) then\\\
                        theType = tUnit:getTypeName()\\\
                        if tUnit.getPlayerName and tUnit:getPlayerName() then\\\
                            playerName = tUnit:getPlayerName()\\\
                        end\\\
                        thePoint = tUnit:getPoint()\\\
                        spd = dcsCommon.getUnitSpeed(tUnit)\\\
                        -- convert m/s to km/h \\\
                        spd = math.floor(spd * 3.6)\\\
                        uHead = math.floor(dcsCommon.getUnitHeading(tUnit) * 57.2958) -- to degrees. \\\
                    end\\\
                else \\\
                    -- nothing to do, remove me.\\\
                end\\\
\\\
                local locString = \\\"err\\\"\\\
                if thePoint then \\\
                    -- now that we have a point, we can do locale-specific\\\
                    -- processing. return result in locString\\\
                    local lat, lon, alt = coord.LOtoLL(thePoint)\\\
                    lat, lon = dcsCommon.latLon2Text(lat, lon)\\\
                    angels = math.floor(thePoint.y) \\\
                    if imperialUnits then \\\
                        alt = math.floor(alt * 3.28084) -- feet\\\
                        spd = math.floor(spd * 0.539957) -- km/h to knots    \\\
                        angels = math.floor(angels * 3.28084)\\\
                    else \\\
                        alt = math.floor(alt) -- meters \\\
                    end \\\
                    \\\
                    if angels > 1000 then \\\
                        angels = math.floor(angels / 100) * 100 \\\
                    end\\\
                    \\\
                    if aLocale == \\\"lat\\\" then locString = lat \\\
                    elseif aLocale == \\\"lon\\\" then locString = lon \\\
                    elseif aLocale == \\\"ele\\\" then locString = tostring(alt)\\\
                    elseif aLocale == \\\"lle\\\" then locString = lat .. \\\" \\\" .. lon .. \\\" ele \\\" .. tostring(alt) \\\
                    elseif aLocale == \\\"latlon\\\" then locString = lat .. \\\" \\\" .. lon \\\
                    elseif aLocale == \\\"alt\\\" then locString = tostring(angels) -- don't confuse alt and angels, bad var naming here\\\
                    elseif aLocale == \\\"vel\\\" then locString = tostring(spd)\\\
                    elseif aLocale == \\\"hdg\\\" then locString = tostring(uHead)\\\
                    elseif aLocale == \\\"type\\\" then locString = theType \\\
                    elseif aLocale == \\\"player\\\" then locString = playerName \\\
                    elseif aLocale == \\\"rhdg\\\" and (responses) then \\\
                        local offset = cfxZones.rspMapper360(uHead, #responses)\\\
                        locString = dcsCommon.trim(responses[offset])\\\
                    else \\\
                        -- we have mgrs\\\
                        local grid = coord.LLtoMGRS(coord.LOtoLL(thePoint))\\\
                        locString = grid.UTMZone .. ' ' .. grid.MGRSDigraph .. ' ' .. grid.Easting .. ' ' .. grid.Northing\\\
                    end\\\
                end\\\
                -- replace pattern in original with new val \\\
                outMsg = string.gsub(outMsg, pattern, locString, 1) -- only one sub!\\\
            end -- if startloc\\\
        until not startLoc\\\
    end -- for all locales \\\
    return outMsg\\\
end\\\
\\\
function cfxZones.rspMapper360(directionInDegrees, numResponses)\\\
    -- maps responses around a clock. Clock has 12 'responses' (12, 1, .., 11), \\\
    -- with the first (12) also mapping to the last half arc \\\
    -- this method dynamically 'winds' the responses around \\\
    -- a clock and returns the index of the message to display \\\
    if numResponses < 1 then numResponses = 1 end \\\
    directionInDegrees = math.floor(directionInDegrees) \\\
    while directionInDegrees < 0 do directionInDegrees = directionInDegrees + 360 end \\\
    while directionInDegrees >= 360 do directionInDegrees = directionInDegrees - 360 end \\\
    -- now we have 0..360 \\\
    -- calculate arc per item \\\
    local arcPerItem = 360 / numResponses\\\
    local halfArc = arcPerItem / 2\\\
\\\
    -- we now map 0..360 to (0-halfArc..360-halfArc) by shifting \\\
    -- direction by half-arc and clipping back 0..360\\\
    -- and now we can directly derive the index of the response \\\
    directionInDegrees = directionInDegrees + halfArc\\\
    if directionInDegrees >= 360 then directionInDegrees = directionInDegrees - 360 end \\\
    \\\
    local index = math.floor(directionInDegrees / arcPerItem) + 1 -- 1 .. numResponses \\\
    \\\
    return index \\\
end\\\
\\\
-- replaces dcsCommon with same name \\\
-- timeFormat is optional, default is \\\"<:h>:<:m>:<:s>\\\"\\\
-- imperialUnits is optional, defaults to meters \\\
-- responses is an array of string, defaults to {}\\\
function cfxZones.processStringWildcards(inMsg, theZone, timeFormat, imperialUnits, responses)\\\
    if not inMsg then return \\\"<nil inMsg>\\\" end\\\
    local formerType = type(inMsg)\\\
    if formerType ~= \\\"string\\\" then inMsg = tostring(inMsg) end\\\
    if not inMsg then inMsg = \\\"<inMsg is incompatible type \\\" .. formerType .. \\\">\\\" end\\\
    local theMsg = inMsg\\\
    -- process common DCS stuff like /n \\\
    theMsg = dcsCommon.processStringWildcards(theMsg) -- call old inherited\\\
    -- process <z>\\\
    theMsg = cfxZones.processZoneStatics(theMsg, theZone)\\\
    -- process <t>, <lat>, <lon>, <ele>, <mgrs>\\\
    theMsg = cfxZones.processSimpleZoneDynamics(theMsg, theZone, timeFormat, imperialUnits)\\\
    -- process <v: flag>, <rsp: flag> <rrnd>\\\
    theMsg = cfxZones.processDynamicValues(theMsg, theZone, responses)\\\
    -- process <t: flag>\\\
    theMsg = cfxZones.processDynamicTime(theMsg, theZone, timeFormat)\\\
    -- process <lat/lon/ele/mgrs/lle/latlon/alt/vel/hdg/rhdg/type/player: zone/unit>\\\
    theMsg = cfxZones.processDynamicLoc(theMsg, imperialUnits, responses)\\\
\\\
    return theMsg\\\
end\\\
\\\
--\\\
-- ============\\\
-- MOVING ZONES \\\
-- ============ \\\
-- \\\
-- Moving zones 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.getDCSOrigin(aZone)\\\
    local o = {}\\\
    o.x = aZone.dcsOrigin.x\\\
    o.y = 0\\\
    o.z = aZone.dcsOrigin.z \\\
    return o\\\
end\\\
\\\
function cfxZones.getLinkedUnit(theZone)\\\
    if not theZone then return nil end \\\
    if not theZone.linkedUnit then return nil end \\\
    if not Unit.isExist(theZone.linkedUnit) then return nil end \\\
    return theZone.linkedUnit \\\
end\\\
\\\
function cfxZones.getPoint(aZone, getHeight) -- always works, even linked, returned point can be reused\\\
-- returned y (when using getHeight) is that of the land, else 0 \\\
    if not getHeight then getHeight = false end \\\
    if aZone.linkedUnit then \\\
        local theUnit = aZone.linkedUnit\\\
        -- has a link. is link existing?\\\
        if Unit.isExist(theUnit) then \\\
            -- updates zone position \\\
            cfxZones.centerZoneOnUnit(aZone, theUnit)\\\
            local dx = aZone.dx\\\
            local dy = aZone.dy\\\
            if aZone.useHeading then \\\
                dx, dy = cfxZones.calcHeadingOffset(aZone, theUnit)\\\
            end\\\
            cfxZones.offsetZone(aZone, dx, dy)\\\
        end\\\
    end\\\
    local thePos = {}\\\
    thePos.x = aZone.point.x\\\
    thePos.z = aZone.point.z\\\
    if not getHeight then \\\
        thePos.y = 0 -- aZone.y \\\
    else \\\
        thePos.y = land.getHeight({x = thePos.x, y = thePos.z})\\\
    end\\\
    \\\
    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 \\\
    theZone.rxy = math.sqrt(dx * dx + dy * dy) -- radius \\\
    local unitHeading = dcsCommon.getUnitHeading(theUnit)\\\
    local bearingOffset = math.atan2(dy, dx) -- rads \\\
    if bearingOffset < 0 then bearingOffset = bearingOffset + 2 * 3.141592 end \\\
\\\
    local dPhi = bearingOffset - unitHeading\\\
    if dPhi < 0 then dPhi = dPhi + 2 * 3.141592 end\\\
    if (theZone.verbose and theZone.useHeading) then \\\
        trigger.action.outText(\\\"Zone is at <\\\" .. math.floor(57.2958 * dPhi) .. \\\"> relative to unit heading\\\", 30)\\\
    end\\\
    theZone.dPhi = dPhi -- constant delta between unit heading and \\\
    -- direction to zone \\\
    theZone.uHdg = unitHeading -- original unit heading to turn other \\\
    -- units if need be \\\
    --trigger.action.outText(\\\"Link setup: dx=<\\\" .. dx .. \\\">, dy=<\\\" .. dy .. \\\"> unit original hdg = <\\\" .. math.floor(57.2958 * unitHeading)  .. \\\">\\\", 30)\\\
end\\\
\\\
function cfxZones.zonesLinkedToUnit(theUnit) -- returns all zones linked to this unit \\\
    if not theUnit then return {} end \\\
    local linkedZones = {}\\\
    for idx, theZone in pairs (cfxZones.zones) do \\\
        if theZone.linkedUnit == theUnit then \\\
            table.insert(linkedZones, theZone)\\\
        end\\\
    end\\\
    return linkedZones\\\
end\\\
\\\
function cfxZones.calcHeadingOffset(aZone, theUnit)\\\
    -- recalc dx and dy based on ry and current heading \\\
    -- since 0 degrees is [0,1] = [0,r] the calculation of \\\
    -- rotated coords can be simplified from \\\
    -- xr = x cos phi - y sin phi = -r sin phi\\\
    -- yr = y cos phi + x sin phi = r cos phi \\\
    local unitHeading = dcsCommon.getUnitHeading(theUnit)\\\
    -- add heading offset \\\
    local zoneBearing = unitHeading + aZone.dPhi \\\
    if zoneBearing > 2 * 3.141592 then zoneBearing = zoneBearing - 2 * 3.141592 end \\\
                    \\\
    -- in DCS, positive x is north (wtf?) and positive z is east \\\
    local dy = (-aZone.rxy) * math.sin(zoneBearing)\\\
    local dx = aZone.rxy * math.cos(zoneBearing)\\\
    \\\
    --trigger.action.outText(\\\"zone bearing is \\\" .. math.floor(zoneBearing * 57.2958) .. \\\" dx = <\\\" .. dx .. \\\"> , dy = <\\\" .. dy .. \\\">\\\", 30)\\\
    return dx, -dy -- note: dy is z coord!!!!\\\
end\\\
\\\
function cfxZones.updateMovingZones()\\\
    cfxZones.updateSchedule = timer.scheduleFunction(cfxZones.updateMovingZones, {}, timer.getTime() + 1/cfxZones.ups)\\\
    -- simply scan all cfx zones for the linkName property, and if present\\\
    -- update the zone's points\\\
    for aName,aZone in pairs(cfxZones.zones) do\\\
        -- only do this if ther is a linkName property, \\\
        -- else this zone isn't linked. link name is harmonized from \\\
        -- both linkUnit non-DML and linedUnit DML        \\\
        if aZone.linkName then \\\
            if aZone.linkBroken then \\\
                -- try to relink \\\
                cfxZones.initLink(aZone)\\\
            else --if aZone.linkName then  \\\
                -- always re-acquire linkedUnit via Unit.getByName()\\\
                -- this way we gloss over any replacements via spawns\\\
                aZone.linkedUnit = Unit.getByName(aZone.linkName)\\\
            end\\\
            \\\
            if aZone.linkedUnit then \\\
                local theUnit = aZone.linkedUnit\\\
                -- has a link. is link existing?\\\
                if theUnit:isExist() then \\\
                    cfxZones.centerZoneOnUnit(aZone, theUnit)\\\
                    local dx = aZone.dx \\\
                    local dy = aZone.dy -- this is actually z \\\
                    if aZone.useHeading then \\\
                        dx, dy = cfxZones.calcHeadingOffset(aZone, theUnit)\\\
                    end\\\
                    cfxZones.offsetZone(aZone, dx, dy)\\\
                else \\\
                    -- we lost link (track level)\\\
                    aZone.linkBroken = true \\\
                    aZone.linkedUnit = nil \\\
                end\\\
            else \\\
                -- we lost link (top level)\\\
                aZone.linkBroken = true \\\
                aZone.linkedUnit = nil \\\
            end\\\
        else \\\
            -- this zone isn't linked\\\
        end\\\
    end\\\
end\\\
\\\
function cfxZones.initLink(theZone)\\\
\\\
    theZone.linkBroken = true \\\
    theZone.linkedUnit = nil \\\
    theUnit = Unit.getByName(theZone.linkName)\\\
    if theUnit then\\\
\\\
        local dx = 0\\\
        local dz = 0\\\
        if theZone.useOffset or theZone.useHeading then \\\
            local A = cfxZones.getDCSOrigin(theZone)\\\
            local B = theUnit:getPoint()\\\
            local delta = dcsCommon.vSub(A,B) \\\
            dx = delta.x \\\
            dz = delta.z\\\
        end\\\
        cfxZones.linkUnitToZone(theUnit, theZone, dx, dz) -- also sets theZone.linkedUnit\\\
\\\
        if theZone.verbose then \\\
            trigger.action.outText(\\\"Link established for zone <\\\" .. theZone.name .. \\\"> to unit <\\\" .. theZone.linkName .. \\\">: dx=<\\\" .. math.floor(dx) .. \\\">, dz=<\\\" .. math.floor(dz) .. \\\"> dist = <\\\" .. math.floor(math.sqrt(dx * dx + dz * dz)) .. \\\">\\\" , 30)\\\
        end \\\
        theZone.linkBroken = nil \\\
\\\
    else \\\
        if theZone.verbose then \\\
            trigger.action.outText(\\\"Linked unit: no unit <\\\" .. theZone.linkName .. \\\"> to link <\\\" .. theZone.name .. \\\"> to\\\", 30)\\\
        end\\\
    end\\\
end\\\
\\\
function cfxZones.startMovingZones()\\\
    -- read all zones, and look for a property called 'linkedUnit'\\\
    -- which will make them a linked zone if there is a unit that exists\\\
    -- also suppors 'useOffset' and 'useHeading'\\\
    for aName,aZone in pairs(cfxZones.zones) do\\\
        \\\
        local lU = nil \\\
        -- check if DCS zone has the linkUnit new attribute introduced in \\\
        -- late 2022 with 2.8\\\
        if aZone.dcsZone.linkUnit then \\\
            local theID = aZone.dcsZone.linkUnit \\\
            lU = dcsCommon.getUnitNameByID(theID)\\\
            if not lU then \\\
                trigger.action.outText(\\\"WARNING: Zone <\\\" .. aZone.name .. \\\">: cannot resolve linked unit ID <\\\" .. theID .. \\\">\\\", 30)\\\
                lU = \\\"***DML link err***\\\"\\\
            end\\\
        elseif cfxZones.hasProperty(aZone, \\\"linkedUnit\\\") then \\\
            lU = cfxZones.getZoneProperty(aZone, \\\"linkedUnit\\\")\\\
        end\\\
        \\\
        -- sanity check \\\
        if aZone.dcsZone.linkUnit and cfxZones.hasProperty(aZone, \\\"linkedUnit\\\") then \\\
            trigger.action.outText(\\\"WARNING: Zone <\\\" .. aZone.name .. \\\"> has dual unit link definition. Will use link to unit <\\\" .. lU .. \\\">\\\", 30)\\\
        end\\\
        \\\
        if lU then \\\
            aZone.linkName = lU\\\
            aZone.useOffset = cfxZones.getBoolFromZoneProperty(aZone, \\\"useOffset\\\", false)\\\
            aZone.useHeading = cfxZones.getBoolFromZoneProperty(aZone, \\\"useHeading\\\", false)\\\
            \\\
            cfxZones.initLink(aZone)\\\
\\\
        end\\\
        \\\
    end\\\
end\\\
\\\
\\\
--\\\
-- ===========\\\
-- INIT MODULE\\\
-- ===========\\\
--\\\
\\\
function cfxZones.initZoneVerbosity()\\\
    for aName,aZone in pairs(cfxZones.zones) do\\\
        -- support for zone-local verbose flag \\\
        aZone.verbose = cfxZones.getBoolFromZoneProperty(aZone, \\\"verbose\\\", false)\\\
    end\\\
end\\\
\\\
function cfxZones.init()\\\
    -- read all zones into my own db\\\
    cfxZones.readFromDCS(true) -- true: erase old\\\
\\\
    -- pre-read zone owner for all zones\\\
    -- much like verbose, all zones have owner\\\
--    local pZones = cfxZones.zonesWithProperty(\\\"owner\\\")\\\
--    for n, aZone in pairs(pZones) do\\\
    for n, aZone in pairs(cfxZones.zones) do\\\
        aZone.owner = cfxZones.getCoalitionFromZoneProperty(aZone, \\\"owner\\\", 0)\\\
    end\\\
        \\\
    -- enable all zone's verbose flags if present\\\
    -- must be done BEFORE we start the moving zones \\\
    cfxZones.initZoneVerbosity()\\\
    \\\
    -- now initialize moving zones\\\
    cfxZones.startMovingZones()\\\
    cfxZones.updateMovingZones() -- will auto-repeat\\\
    \\\
    trigger.action.outText(\\\"cf/x Zones v\\\".. cfxZones.version .. \\\": loaded, zones:\\\" .. dcsCommon.getSizeOfTable(cfxZones.zones), 30)\\\
\\\
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.1\\\"\\\
--[[-- 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)\\\
- 3.0.1 - isPlayerUnit guard against scenery object or map object \\\
--]]--\\\
\\\
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 \\\
    if not theUnit.getPlayerName then return false end -- map/static object \\\
    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 is 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(\"cfxPlayerScore = {}\\\
cfxPlayerScore.version = \\\"2.2.0\\\"\\\
cfxPlayerScore.name = \\\"cfxPlayerScore\\\" -- compatibility with flag bangers\\\
cfxPlayerScore.badSound = \\\"Death BRASS.wav\\\"\\\
cfxPlayerScore.scoreSound = \\\"Quest Snare 3.wav\\\"\\\
cfxPlayerScore.announcer = true \\\
cfxPlayerScore.firstSave = true -- to force overwrite \\\
--[[-- VERSION HISTORY\\\
    1.0.1 - bug fixes to killDetected \\\
    1.0.2 - messaging clean-up, less verbose \\\
    1.1.0 - integrated score base system\\\
          - accepts configZones \\\
          - module validation \\\
          - isNamedUnit(theUnit)\\\
          - notify if named unit killed \\\
          - kill weapon reported \\\
    1.2.0 - score table \\\
          - announcer attribute \\\
          - badSound name \\\
          - scoreSound name \\\
    1.3.0 - object2score \\\
          - static objects also can score \\\
          - can now also score members of group by adding group name \\\
          - scenery objects are now supported. use the \\\
            number that is given under OBJECT ID when \\\
            using assign as...\\\
    1.3.1 - isStaticObject() to better detect buildings after Match 22 patch\\\
    1.3.2 - corrected ground default score \\\
          - removed dependency to cfxPlayer \\\
    1.4.0 - persistence support \\\
          - better unit-->static switch support for generic type kill\\\
    1.5.0 - added feats to score\\\
          - feats API \\\
          - logFeatForPlayer(playerName, theFeat, coa)\\\
    1.5.1 - init feats before reading \\\
    2.0.0 - sound name for good and bad corrected \\\
          - scoreOnly option \\\
          - saveScore? input in config\\\
          - incremental option in config for save \\\
          - preProcessor() added land and birth for players \\\
          - addSafeZone()\\\
          - landing score possible as feat \\\
          - also detect landing and birth events for players \\\
          - birth zeroes deferred scores and feats\\\
          - delayAfterLanding property \\\
          - delayBetweenLandings to filter landings and \\\
            space them properly from take offs \\\
          - ranking option \\\
          - scoreOnly option \\\
          - scoreFileName option \\\
          - update() loop \\\
          - read \\\"scoreSafe\\\" zones \\\
          - scoreaccu in playerScore \\\
          - landing feat added, enabled with landing > 0 score attribute\\\
          - delayed awards after landing \\\
          - save score to file \\\
          - show score to all \\\
          - feat zones \\\
          - awardLimit - feats can be limited in number total\\\
          - wildcard support for feature \\\
          - kill zones - limit kill score awards to inside zones \\\
          - feats can be limited to once per player\\\
          - persistence: featNum \\\
          - persistence: awardedTo\\\
          - always schedule\\\
          - hasAward logic \\\
          - unit2player\\\
          - detect player plane death \\\
          - ffMod attribute\\\
          - pkMod attribute\\\
          - pvp feat \\\
          - immediate awarding of all negative scores, even if deferred\\\
    2.0.1 - corrected access to nowString()\\\
          - more robust config reading \\\
    2.1.0 - coalition score \\\
          - reportCoalition switch \\\
          - persist coalition score \\\
          - add score to coalition when scoring player \\\
    2.1.1 - check ownership of scoreSafe zone upon touch-down \\\
          - new scoreSummaryForPlayersOfCoalition()\\\
          - new noGrief option in config \\\
          - improved guards when checking ownership (nil zone owner)\\\
    2.0.0 - score flags for red and blue \\\
    \\\
--]]--\\\
\\\
cfxPlayerScore.requiredLibs = {\\\
    \\\"dcsCommon\\\", -- this is doing score keeping\\\
    \\\"cfxZones\\\", -- zones for config \\\
}\\\
cfxPlayerScore.playerScore = {} -- indexed by playerName\\\
cfxPlayerScore.coalitionScore = {} -- score per coalition\\\
cfxPlayerScore.coalitionScore[1] = 0 -- init red\\\
cfxPlayerScore.coalitionScore[2] = 0 -- init blue\\\
cfxPlayerScore.deferred = false -- on deferred, we only award after landing, and erase on any form of re-slot\\\
cfxPlayerScore.delayAfterLanding = 10 -- seconds after landing \\\
cfxPlayerScore.safeZones = {} -- safe zones to land in  \\\
cfxPlayerScore.featZones = {} -- zones that define feats \\\
cfxPlayerScore.killZones = {} -- when set, kills only count here \\\
\\\
-- typeScore: dictionary sorted by typeString for score \\\
-- extend to add more types. It is used by unitType2score to \\\
-- determine the base unit score  \\\
cfxPlayerScore.typeScore = {}\\\
cfxPlayerScore.lastPlayerLanding = {} -- timestamp, by player name  \\\
cfxPlayerScore.delayBetweenLandings = 30 -- seconds to count as separate landings, also set during take-off to prevent janky t/o to count. \\\
--\\\
-- we subscribe to the kill event. each time a unit \\\
-- is killed, we check if it was killed by a player\\\
-- and if so, that player record is updated and the side\\\
-- whom the player belongs to is informed\\\
--\\\
cfxPlayerScore.aircraft = 50 \\\
cfxPlayerScore.helo = 40 \\\
cfxPlayerScore.ground = 10\\\
cfxPlayerScore.ship = 80 \\\
cfxPlayerScore.train = 5 \\\
cfxPlayerScore.landing = 0 -- if > 0 it scores as feat\\\
\\\
cfxPlayerScore.unit2player = {} -- lookup and reverse look-up \\\
\\\
function cfxPlayerScore.addSafeZone(theZone)\\\
    theZone.scoreSafe = cfxZones.getCoalitionFromZoneProperty(theZone, \\\"scoreSafe\\\", 0)\\\
    table.insert(cfxPlayerScore.safeZones, theZone)\\\
end\\\
\\\
function cfxPlayerScore.addKillZone(theZone)\\\
    theZone.killZone = cfxZones.getCoalitionFromZoneProperty(theZone, \\\"killZone\\\", 0) -- value currently ignored \\\
    theZone.duet = cfxZones.getBoolFromZoneProperty(theZone, \\\"duet\\\", false) -- does killer have to be in zone? \\\
    table.insert(cfxPlayerScore.killZones, theZone)\\\
end\\\
\\\
function cfxPlayerScore.addFeatZone(theZone)\\\
    theZone.coalition = cfxZones.getCoalitionFromZoneProperty(theZone, \\\"feat\\\", 0) -- who can earn, 0 for all sides \\\
    theZone.featType = cfxZones.getStringFromZoneProperty(theZone, \\\"featType\\\", \\\"kill\\\")\\\
    theZone.featType = string.upper(theZone.featType)\\\
    if theZone.featType == \\\"LAND\\\" then theZone.featType = \\\"LANDING\\\" end \\\
    if theZone.featType ~= \\\"KILL\\\" and \\\
       theZone.featType ~= \\\"LANDING\\\" and \\\
       theZone.featType ~= \\\"PVP\\\"\\\
    then\\\
        theZone.featType = \\\"KILL\\\"\\\
    end    \\\
    theZone.featDesc = cfxZones.getStringFromZoneProperty(theZone, \\\"description\\\", \\\"(some feat)\\\")\\\
    theZone.featNum = cfxZones.getNumberFromZoneProperty(theZone, \\\"awardLimit\\\", -1) -- how many times this can be awarded, -1 is infinite \\\
    theZone.ppOnce = cfxZones.getBoolFromZoneProperty(theZone, \\\"awardOnce\\\", false)\\\
    theZone.awardedTo = {} -- by player name: true/false \\\
    table.insert(cfxPlayerScore.featZones, theZone)\\\
    if cfxPlayerScore.verbose then \\\
        trigger.action.outText(\\\"+++ feat zone <\\\" .. theZone.name .. \\\"> read: [\\\" .. theZone.featDesc .. \\\"] for <\\\" .. theZone.featType .. \\\">\\\", 30)\\\
    end \\\
end\\\
\\\
function cfxPlayerScore.getFeatByName(name)\\\
    for idx, theZone in pairs(cfxPlayerScore.featZones) do \\\
        if name == theZone.name then return theZone end \\\
    end\\\
    return nil \\\
end\\\
\\\
function cfxPlayerScore.featsForLocation(name, loc, coa, featType, killer, victim)\\\
    if not loc then return {} end \\\
    -- loc is location of landing unit for landing \\\
    -- and location of victim for kill \\\
    -- coa is coalition of landing unit \\\
    -- and coalition of killer for kill \\\
\\\
    if not coa then coa = 0 end \\\
    if not featType then featType = \\\"KILL\\\" end \\\
    featType = string.upper(featType)\\\
    local theFeats = {}\\\
    for idx, theZone in pairs(cfxPlayerScore.featZones) do \\\
        local canAward = true \\\
                   \\\
        -- check if it can be awarded \\\
        if theZone.featNum == 0 then \\\
            canAward = false \\\
        end \\\
        \\\
        if theZone.featType ~= featType then \\\
            canAward = false\\\
        end\\\
        \\\
        if not (theZone.coalition == 0 or theZone.coalition == coa) then \\\
            canAward = false \\\
        end            \\\
        \\\
        if featType == \\\"PVP\\\" then \\\
            -- make sure kill is pvp kill \\\
            if not victim then canAward = false \\\
            elseif not victim.getPlayerName then \\\
                canAward = false \\\
            elseif not victim:getPlayerName() then\\\
                canAward = false \\\
            end\\\
        end\\\
        \\\
        if not cfxZones.pointInZone(loc, theZone) then \\\
            canAward = false \\\
        end\\\
        \\\
        if theZone.ppOnce then \\\
            if theZone.awardedTo[name] then \\\
                canAward = false\\\
            end\\\
        end\\\
        \\\
        if canAward then \\\
            table.insert(theFeats, theZone) -- jupp, add it\\\
        else \\\
        end \\\
\\\
    end\\\
    return theFeats\\\
end\\\
\\\
function cfxPlayerScore.preprocessWildcards(inMsg, aUnit, aVictim)\\\
    local theMsg = inMsg\\\
    if not aVictim then aVictim = aUnit end \\\
    local pName = \\\"Unknown\\\"\\\
    if aUnit then \\\
        if aUnit.getPlayerName then \\\
            pN = aUnit:getPlayerName()\\\
            if pN then pName = pN end \\\
        end\\\
        theMsg = theMsg:gsub(\\\"<punit>\\\", aUnit:getName())\\\
        theMsg = theMsg:gsub(\\\"<ptype>\\\", aUnit:getTypeName())\\\
        theMsg = theMsg:gsub(\\\"<pgroup>\\\", aUnit:getGroup():getName())\\\
    end\\\
    theMsg = theMsg:gsub(\\\"<player>\\\", pName)\\\
    if aVictim then \\\
        -- if player killed, get killed player's name else use unknown AI\\\
        if aVictim.getPlayerName then \\\
            pkName = aVictim:getPlayerName()\\\
            if pkName then \\\
                theMsg = theMsg:gsub(\\\"<kplayer>\\\", pkName)\\\
            else \\\
                theMsg = theMsg:gsub(\\\"<kplayer>\\\", \\\"unknown AI\\\")\\\
            end\\\
        end\\\
        theMsg = theMsg:gsub(\\\"<unit>\\\", aVictim:getName())\\\
        theMsg = theMsg:gsub(\\\"<type>\\\", aVictim:getTypeName())\\\
        -- victim may not have group. guard against that \\\
        -- happens if unit 'cooks off'\\\
        local aGroup = nil \\\
        if aVictim.getGroup then \\\
            aVictim:getGroup()\\\
        end \\\
        if aGroup and aGroup.getName then \\\
            theMsg = theMsg:gsub(\\\"<group>\\\", aGroup:getName())\\\
        else \\\
            theMsg = theMsg:gsub(\\\"<group>\\\", \\\"(Unknown)\\\")\\\
        end \\\
    end \\\
    return theMsg\\\
end\\\
\\\
function cfxPlayerScore.evalFeatDescription(name, theZone, playerUnit, victim) \\\
    local msg = theZone.featDesc \\\
    if not victim then victim = playerUnit end \\\
    -- eval wildcards \\\
    msg = cfxPlayerScore.preprocessWildcards(msg, playerUnit, victim)\\\
    msg = cfxZones.processStringWildcards(msg, theZone) -- nil time format, nil imperial, nil responses\\\
        \\\
    -- update featNum since it's been 'used' \\\
    if theZone.featNum > 0 then \\\
        theZone.featNum = theZone.featNum -1 \\\
    end\\\
    -- mark this feat awarded to player, only relevant for ppOnce \\\
    theZone.awardedTo[name] = true \\\
    return msg \\\
end\\\
\\\
function cfxPlayerScore.cat2BaseScore(inCat)\\\
    if inCat == 0 then return cfxPlayerScore.aircraft end -- airplane\\\
    if inCat == 1 then return cfxPlayerScore.helo end -- helo \\\
    if inCat == 2 then return cfxPlayerScore.ground end -- ground \\\
    if inCat == 3 then return cfxPlayerScore.ship end -- ship \\\
    if inCat == 4 then return cfxPlayerScore.train end -- train \\\
    \\\
    trigger.action.outText(\\\"+++scr c2bs: unknown category for lookup: <\\\" .. inCat .. \\\">, returning 1\\\", 30)\\\
    \\\
    return 1 \\\
end\\\
\\\
function cfxPlayerScore.object2score(inVictim) -- does not have group\\\
    if not inVictim then return end \\\
    local inName = inVictim:getName()\\\
    if not inName then return 0 end \\\
    if type(inName) == \\\"number\\\" then \\\
        inName = tostring(inName)\\\
    end\\\
    \\\
    -- since 2.7x DCS turns units into static objects for \\\
    -- cooking off, so first thing we need to do is do a name check \\\
    local objectScore = cfxPlayerScore.typeScore[inName]\\\
    if not objectScore then \\\
        -- try the type desc \\\
        local theType = inVictim:getTypeName()\\\
        objectScore = cfxPlayerScore.typeScore[theType]\\\
    end\\\
    \\\
    if type(objectScore) == \\\"string\\\" then \\\
        objectScore = tonumber(objectScore)\\\
    end\\\
    \\\
    if objectScore then return objectScore end\\\
    \\\
    -- we now try and get the general type of the killed object\\\
    local desc = inVictim:getDesc() -- Object.getDesc(inVictim)\\\
    local attributes = desc.attributes \\\
    if attributes then \\\
        if attributes[\\\"Vehicles\\\"] or attributes[\\\"Ground vehicles\\\"] or attributes[\\\"Ground Units\\\"] then return cfxPlayerScore.ground end \\\
        if attributes[\\\"Helicopters\\\"] then return cfxPlayerScore.helo end\\\
        if attributes[\\\"Planes\\\"] then return cfxPlayerScore.aircraft end \\\
        if attributes[\\\"Ships\\\"] then return cfxPlayerScore.ship end \\\
        -- trains can't be detected\\\
    end \\\
    \\\
    if not objectScore then return 0 end \\\
    return objectScore \\\
end\\\
\\\
function cfxPlayerScore.unit2score(inUnit)\\\
    local vicGroup = inUnit:getGroup()\\\
    local vicCat = vicGroup:getCategory()\\\
    local vicType = inUnit:getTypeName()\\\
    local vicName = inUnit:getName() \\\
    if type(vicName) == \\\"number\\\" then vicName = tostring(vicName) end \\\
    \\\
    -- simply extend by adding items to the typescore table.concat\\\
    -- we first try by unit name. This allows individual\\\
    -- named hi-value targets to have individual scores \\\
    local uScore = cfxPlayerScore.typeScore[vicName]\\\
\\\
    -- see if all members of group score \\\
    if not uScore then \\\
        local grpName = vicGroup:getName()\\\
        uScore = cfxPlayerScore.typeScore[grpName]\\\
    end\\\
    \\\
    if uScore == nil then \\\
        -- WE NOW TRY TO ACCESS BY VICTIM'S TYPE STRING        \\\
        uScore = cfxPlayerScore.typeScore[vicType]\\\
    else \\\
\\\
    end \\\
    if type(uScore) == \\\"string\\\" then \\\
        -- convert string to number \\\
        uScore = tonumber(uScore)\\\
    end\\\
\\\
    if uScore == nil then uScore = 0 end \\\
    if uScore > 0 then return uScore end \\\
    \\\
    -- only apply base scores when the lookup did not give a result\\\
    uScore = cfxPlayerScore.cat2BaseScore(vicCat)\\\
    return uScore \\\
end\\\
\\\
function cfxPlayerScore.getPlayerScore(playerName)\\\
    local thePlayerScore = cfxPlayerScore.playerScore[playerName]\\\
    if thePlayerScore == nil then \\\
        thePlayerScore = {}\\\
        thePlayerScore.name = playerName\\\
        thePlayerScore.score = 0 -- score\\\
        thePlayerScore.scoreaccu = 0 -- for deferred \\\
        thePlayerScore.killTypes = {} -- the type strings killed, dict <typename> <numkilla>\\\
        thePlayerScore.killQueue = {} -- when using deferred\\\
        thePlayerScore.totalKills = 0 -- number of kills total \\\
        thePlayerScore.featTypes = {} -- dict <featname> <number> of other things player did \\\
        thePlayerScore.featQueue = {} -- when using deferred \\\
        thePlayerScore.totalFeats = 0        \\\
    end\\\
    return thePlayerScore\\\
end\\\
\\\
function cfxPlayerScore.setPlayerScore(playerName, thePlayerScore)\\\
    cfxPlayerScore.playerScore[playerName] = thePlayerScore\\\
end\\\
\\\
-- will never defer \\\
function cfxPlayerScore.updateScoreForPlayerImmediate(playerName, score)\\\
    local thePlayerScore = cfxPlayerScore.getPlayerScore(playerName)\\\
    thePlayerScore.score = thePlayerScore.score + score\\\
    cfxPlayerScore.setPlayerScore(playerName, thePlayerScore)\\\
    -- if coalitionScore is active, trace player back to their current \\\
    -- coalition and add points to that coalition if positive \\\
    -- or always if noGrief is true \\\
    local pFaction = dcsCommon.playerName2Coalition(playerName)\\\
    if cfxPlayerScore.noGrief then  \\\
        -- only on positive score\\\
        if (score > 0) and pFaction > 0 then \\\
            cfxPlayerScore.coalitionScore[pFaction] = cfxPlayerScore.coalitionScore[pFaction] + score \\\
        end\\\
    else \\\
        if pFaction > 0 then \\\
            cfxPlayerScore.coalitionScore[pFaction] = cfxPlayerScore.coalitionScore[pFaction] + score \\\
        end\\\
    end\\\
    return thePlayerScore.score \\\
end\\\
\\\
function cfxPlayerScore.updateScoreForPlayer(playerName, score)\\\
    -- main update score \\\
    if cfxPlayerScore.deferred then -- just queue it\\\
        local thePlayerScore = cfxPlayerScore.getPlayerScore(playerName) \\\
        thePlayerScore.scoreaccu = thePlayerScore.scoreaccu + score\\\
        cfxPlayerScore.setPlayerScore(playerName, thePlayerScore) -- write-through. why? because it may be a new entry.\\\
        return thePlayerScore.score -- this is the old score!!! \\\
    end\\\
    -- now write immediately \\\
    return cfxPlayerScore.updateScoreForPlayerImmediate(playerName, score)\\\
end\\\
\\\
function cfxPlayerScore.doLogTypeKill(playerName, thePlayerScore, theType)\\\
    local killCount = thePlayerScore.killTypes[theType]    \\\
    if killCount == nil then \\\
        killCount = 0\\\
    end\\\
    killCount = killCount + 1\\\
    thePlayerScore.totalKills = thePlayerScore.totalKills + 1\\\
    thePlayerScore.killTypes[theType] = killCount\\\
    \\\
    cfxPlayerScore.setPlayerScore(playerName, thePlayerScore)\\\
end \\\
\\\
function cfxPlayerScore.logKillForPlayer(playerName, theUnit)\\\
    -- main kill type /total count logging, can be deferred \\\
    -- no score change here \\\
    if not theUnit then return end\\\
    if not playerName then return end \\\
    local thePlayerScore = cfxPlayerScore.getPlayerScore(playerName)    \\\
    local theType = theUnit:getTypeName()\\\
    \\\
    if cfxPlayerScore.deferred then \\\
        -- just queue it \\\
        table.insert(thePlayerScore.killQueue, theType)\\\
        cfxPlayerScore.setPlayerScore(playerName, thePlayerScore) -- write-through. why? because it may be a new entry.\\\
        return \\\
    end\\\
    \\\
    cfxPlayerScore.doLogTypeKill(playerName, thePlayerScore, theType)\\\
end\\\
\\\
function cfxPlayerScore.doLogFeat(playerName, thePlayerScore, theFeat)\\\
    if not thePlayerScore.featTypes then thePlayerScore.featTypes = {} end\\\
    local featCount = thePlayerScore.featTypes[theFeat]\\\
    if featCount == nil then \\\
        featCount = 0\\\
    end\\\
    featCount = featCount + 1\\\
    thePlayerScore.totalFeats = thePlayerScore.totalFeats + 1\\\
    thePlayerScore.featTypes[theFeat] = featCount\\\
    \\\
    cfxPlayerScore.setPlayerScore(playerName, thePlayerScore)\\\
\\\
end\\\
\\\
function cfxPlayerScore.logFeatForPlayer(playerName, theFeat, coa)\\\
    -- usually called externally with theFeat being a string. no \\\
    -- scoring is passed \\\
    if not theFeat then return end\\\
    if not playerName then return end \\\
    -- access player's record. will alloc if new by itself\\\
\\\
    if coa then \\\
        local disclaim = \\\"\\\"\\\
        if cfxPlayerScore.deferred then disclaim = \\\" (award pending)\\\" end \\\
        trigger.action.outTextForCoalition(coa, playerName .. \\\" achieved \\\" .. theFeat .. disclaim, 30)\\\
        trigger.action.outSoundForCoalition(coa, cfxPlayerScore.scoreSound)\\\
    end\\\
    \\\
    local thePlayerScore = cfxPlayerScore.getPlayerScore(playerName)\\\
    if cfxPlayerScore.deferred then \\\
        table.insert(thePlayerScore.featQueue, theFeat)\\\
        cfxPlayerScore.setPlayerScore(playerName, thePlayerScore)\\\
        return \\\
    end\\\
    \\\
    cfxPlayerScore.doLogFeat(playerName, thePlayerScore, theFeat)\\\
end\\\
\\\
function cfxPlayerScore.playerScore2text(thePlayerScore, scoreOnly)\\\
    if not scoreOnly then scoreOnly = false end \\\
    local desc = thePlayerScore.name .. \\\" statistics:\\\\n\\\"\\\
\\\
    if cfxPlayerScore.reportScore then     \\\
        desc = desc .. \\\" - score: \\\".. thePlayerScore.score .. \\\" - total kills: \\\" .. thePlayerScore.totalKills .. \\\"\\\\n\\\"\\\
        if scoreOnly then \\\
            return desc \\\
        end \\\
        \\\
        -- now go through all kills\\\
        desc = desc .. \\\"\\\\nKills by type:\\\\n\\\"\\\
        if dcsCommon.getSizeOfTable(thePlayerScore.killTypes)  < 1 then \\\
            desc = desc .. \\\"    - NONE -\\\\n\\\"\\\
        end\\\
        for theType, quantity in pairs(thePlayerScore.killTypes) do \\\
            desc = desc .. \\\"  - \\\" .. theType .. \\\": \\\" .. quantity .. \\\"\\\\n\\\"\\\
        end\\\
    end \\\
    \\\
    -- now enumerate all feats\\\
    if not thePlayerScore.featTypes then thePlayerScore.featTypes = {} end\\\
    if cfxPlayerScore.reportFeats then \\\
        desc = desc .. \\\"\\\\n Accomplishments:\\\\n\\\"\\\
        if dcsCommon.getSizeOfTable(thePlayerScore.featTypes) < 1 then \\\
            desc = desc .. \\\"    - NONE -\\\\n\\\"\\\
        end\\\
        for theFeat, quantity in pairs(thePlayerScore.featTypes) do \\\
            desc = desc .. \\\"  - \\\" .. theFeat\\\
            if quantity > 1 then \\\
                desc = desc .. \\\" (x\\\" .. quantity .. \\\")\\\"\\\
            end \\\
            desc = desc .. \\\"\\\\n\\\"\\\
        end\\\
    end \\\
    \\\
    if cfxPlayerScore.reportScore and thePlayerScore.scoreaccu > 0 then \\\
        desc = desc .. \\\"\\\\n - unclaimed score: \\\" .. thePlayerScore.scoreaccu ..\\\"\\\\n\\\"\\\
    end\\\
    \\\
    local featCount = dcsCommon.getSizeOfTable(thePlayerScore.featQueue)\\\
    if cfxPlayerScore.reportFeats and featCount > 0 then \\\
        desc = desc .. \\\" - unclaimed feats: \\\" .. featCount ..\\\"\\\\n\\\"\\\
    end\\\
    \\\
    return desc\\\
end\\\
\\\
function cfxPlayerScore.scoreTextForPlayerNamed(playerName)\\\
    local thePlayerScore = cfxPlayerScore.getPlayerScore(playerName)\\\
    return cfxPlayerScore.playerScore2text(thePlayerScore)\\\
end\\\
\\\
function cfxPlayerScore.scoreSummaryForPlayersOfCoalition(side)\\\
    -- only list players who are in the coalition RIGHT NOW\\\
    -- only list their score \\\
    if not side then side = -1 end \\\
    local desc = \\\"\\\\nCurrent score for players in \\\" .. dcsCommon.coalition2Text(side) ..\\\" coalition:\\\\n\\\"\\\
    local count = 0 \\\
    for pName, pScore in pairs(cfxPlayerScore.playerScore) do \\\
        local coa = dcsCommon.playerName2Coalition(pName)\\\
        if coa == side then \\\
            desc = desc .. pName ..\\\": \\\" .. pScore.score .. \\\"\\\\n\\\"\\\
            count = count + 1\\\
        end\\\
    end\\\
    if count < 1 then \\\
        desc = desc .. \\\"  (No score yet)\\\"\\\
    end\\\
    \\\
    desc = desc .. \\\"\\\\n\\\"\\\
    return desc\\\
end\\\
\\\
function cfxPlayerScore.scoreTextForAllPlayers(ranked) \\\
    if not ranked then ranked = false end \\\
    local theText = \\\"\\\"\\\
    local isFirst = true \\\
    local theScores = cfxPlayerScore.playerScore\\\
    if cfxPlayerScore.verbose then \\\
        trigger.action.outText(\\\"+++pScr: Generating score - <\\\" .. dcsCommon.getSizeOfTable(theScores) .. \\\"> entries.\\\", 30)\\\
    end \\\
    if ranked then \\\
        table.sort(theScores, function(left, right) return left.score < right.score end )\\\
    end\\\
    local rank = 1\\\
    for name, score in pairs(theScores) do \\\
        if not isFirst then \\\
            theText = theText .. \\\"\\\\n\\\"\\\
        end\\\
        if ranked then \\\
            if rank < 10 then theText = theText .. \\\" \\\" end\\\
            theText = theText .. rank .. \\\". \\\"\\\
        end\\\
        theText = theText .. cfxPlayerScore.playerScore2text(score, cfxPlayerScore.scoreOnly)  \\\
        isFirst = false\\\
        rank = rank + 1\\\
    end\\\
    \\\
    if dcsCommon.getSizeOfTable(theScores) < 1 then \\\
        theText = theText .. \\\"  (No score yet)\\\\n\\\"\\\
    end\\\
    \\\
    if cfxPlayerScore.reportCoalition then \\\
        --theText = theText .. \\\"\\\\n\\\"\\\
        theText = theText .. \\\"\\\\nRED  total: \\\" .. cfxPlayerScore.coalitionScore[1]\\\
        theText = theText .. \\\"\\\\nBLUE total: \\\" .. cfxPlayerScore.coalitionScore[2]\\\
    end\\\
    \\\
    return theText\\\
end\\\
\\\
\\\
function cfxPlayerScore.isNamedUnit(theUnit) \\\
    if not theUnit then return false end \\\
    local theName = \\\"(cfx_none)\\\"\\\
    if type(theUnit) == \\\"string\\\" then \\\
        theName = theUnit -- direct name assignment\\\
        -- WARNING: NO EXIST CHECK DONE!\\\
    else \\\
        -- after kill, unit is dead, so will no longer exist!\\\
        theName = theUnit:getName() \\\
        if not theName then return false end \\\
    end\\\
    if cfxPlayerScore.typeScore[theName] then \\\
        return true\\\
    end\\\
    return false \\\
end\\\
\\\
function cfxPlayerScore.awardScoreTo(killSide, theScore, killerName)\\\
    local playerScore \\\
    if theScore < 0 then \\\
        playerScore = cfxPlayerScore.updateScoreForPlayerImmediate(killerName, theScore)\\\
    else \\\
        playerScore = cfxPlayerScore.updateScoreForPlayer(killerName, theScore)\\\
    end\\\
    \\\
    if not cfxPlayerScore.reportScore then return end \\\
    \\\
    if cfxPlayerScore.announcer then\\\
        if (theScore > 0) and cfxPlayerScore.deferred then \\\
            thePlayerRecord = cfxPlayerScore.getPlayerScore(killerName) -- re-read after write\\\
            trigger.action.outTextForCoalition(killSide, \\\"Killscore:  \\\" .. theScore .. \\\", now \\\" .. thePlayerRecord.scoreaccu .. \\\" waiting for \\\" .. killerName .. \\\", awarded after landing\\\", 30)\\\
        else -- negative score or not deferred \\\
            trigger.action.outTextForCoalition(killSide, \\\"Killscore:  \\\" .. theScore .. \\\" for a total of \\\" .. playerScore .. \\\" for \\\" .. killerName, 30)\\\
            \\\
            if cfxPlayerScore.reportCoalition then \\\
                trigger.action.outTextForCoalition(killSide, \\\"\\\\nCoalition Total:  \\\" .. cfxPlayerScore.coalitionScore[killSide], 30)\\\
            end \\\
        end\\\
    end \\\
end\\\
\\\
--\\\
-- EVENT HANDLING\\\
--\\\
function cfxPlayerScore.linkUnitWithPlayer(theUnit)\\\
    -- create the entries for lookup and reverseLooup tables\\\
    local uName = theUnit:getName()\\\
    local pName = theUnit:getPlayerName()\\\
    cfxPlayerScore.unit2player[uName] = pName \\\
    --cfxPlayerScore.player2unit[pName] = uName -- is this needed?\\\
end\\\
\\\
function cfxPlayerScore.unlinkUnit(theUnit)\\\
    local uName = theUnit:getName()\\\
    cfxPlayerScore.unit2player[uName] = nil     \\\
end\\\
\\\
function cfxPlayerScore.preProcessor(theEvent)\\\
    -- return true if the event should be processed\\\
    -- by us\\\
    if theEvent.initiator  == nil then \\\
        return false \\\
    end \\\
\\\
    -- check if this was FORMERLY a player plane \\\
    local theUnit = theEvent.initiator \\\
    local uName = theUnit:getName()\\\
    if cfxPlayerScore.unit2player[uName] then \\\
        -- this requires special IMMEDIATE handling when event is\\\
        -- one of the below         \\\
        if theEvent.id == 5 or -- crash \\\
           theEvent.id == 8 or -- dead \\\
           theEvent.id == 9 or -- pilot_dead\\\
           theEvent.id == 30 or -- unit loss \\\
           theEvent.id == 6 then -- eject \\\
            -- these can lead to a pilot demerit\\\
            --trigger.action.outText(\\\"PREPROC plane player extra event - possible death\\\", 30)\\\
            -- event does NOT have a player\\\
            cfxPlayerScore.handlePlayerDeath(theEvent)\\\
            return false \\\
        end \\\
    end\\\
    \\\
    -- initiator must be player \\\
    if not theUnit.getPlayerName or  \\\
       not theUnit:getPlayerName() then \\\
       return false \\\
    end \\\
    \\\
    if theEvent.id == 28 then\\\
        -- we only are interested in kill events where \\\
        -- there is a target  \\\
        local killer = theEvent.initiator \\\
        if theEvent.target == nil then \\\
            if cfxPlayerScore.verbose then \\\
                trigger.action.outText(\\\"+++scr pre: nil TARGET\\\", 30) \\\
            end \\\
            return false \\\
        end \\\
        \\\
        -- if there are kill zones, we filter all kills that happen outside of kill zones \\\
        if #cfxPlayerScore.killZones > 0 then\\\
            local pLoc = theUnit:getPoint() \\\
            local tLoc = theEvent.target:getPoint()\\\
            local isIn, percent, dist, theZone = cfxZones.pointInOneOfZones(tLoc, cfxPlayerScore.killZones)\\\
        \\\
            if not isIn then \\\
                if cfxPlayerScore.verbose then \\\
                    trigger.action.outText(\\\"+++pScr: kill detected, but target <\\\" .. theEvent.target:getName() .. \\\"> was outside of any kill zones\\\", 30)\\\
                end\\\
                return false \\\
            end\\\
        \\\
            if theZone.duet and not cfxZones.pointInZone(pLoc, theZone) then \\\
                -- player must be in same zone but was not\\\
                if cfxPlayerScore.verbose then \\\
                    trigger.action.outText(\\\"+++pScr: kill detected, but player <\\\" .. theUnit:getPlayerName() .. \\\"> was outside of kill zone <\\\" .. theZone.name .. \\\">\\\", 30)\\\
                end\\\
                return false\\\
            end            \\\
        end\\\
        return true \\\
    end\\\
    \\\
    -- birth event for players initializes score if \\\
    -- not existed, and nils the queue \\\
    if theEvent.id == 15 then \\\
        -- player birth\\\
        -- link player and unit\\\
        cfxPlayerScore.linkUnitWithPlayer(theUnit)\\\
        return true \\\
    end\\\
    \\\
    -- take off. overwrites timestamp for last landing \\\
    -- so a blipping t/o does nor count. Pre-proc only \\\
    if theEvent.id == 3 then \\\
        local now = timer.getTime()\\\
        local playerName = theUnit:getPlayerName() \\\
        cfxPlayerScore.lastPlayerLanding[playerName] = now -- overwrite \\\
        return false \\\
    end\\\
    \\\
    -- landing can score. but only the first landing in x seconds\\\
    -- landing in safe zone promotes any queued scores to \\\
    -- permanent if enabled, then nils queue\\\
    if theEvent.id == 4 then \\\
        -- player landed. filter multiple landed events\\\
        local now = timer.getTime()\\\
        local playerName = theUnit:getPlayerName() \\\
        local lastLanding = cfxPlayerScore.lastPlayerLanding[playerName]\\\
        cfxPlayerScore.lastPlayerLanding[playerName] = now -- overwrite \\\
        if lastLanding and lastLanding + cfxPlayerScore.delayBetweenLandings > now then \\\
            if cfxPlayerScore.verbose then \\\
                trigger.action.outText(\\\"+++pScr: Player <\\\" .. playerName .. \\\"> touch-down ignored: too soon.\\\", 30)\\\
                trigger.action.outText(\\\"now is <\\\" .. now .. \\\">, between is <\\\" .. cfxPlayerScore.delayBetweenLandings .. \\\">, last + between is <\\\" .. lastLanding + cfxPlayerScore.delayBetweenLandings .. \\\">\\\", 30)\\\
            end \\\
            -- filter this event \\\
            return false \\\
        end\\\
        return true \\\
    end\\\
    \\\
    return false \\\
end\\\
\\\
function cfxPlayerScore.postProcessor(theEvent)\\\
    -- don't do anything\\\
end\\\
\\\
function cfxPlayerScore.isStaticObject(theUnit) \\\
    if not theUnit.getGroup then return true end \\\
    local aGroup = theUnit:getGroup()\\\
    if aGroup then return false end \\\
    return true \\\
end\\\
\\\
function cfxPlayerScore.checkKillFeat(name, killer, victim, fratricide)\\\
    if not fratricide then fratricide = false end \\\
    local theLoc = victim:getPoint() -- vic's loc is relevant for zone check\\\
    local coa = killer:getCoalition() \\\
    \\\
    local killFeats = cfxPlayerScore.featsForLocation(name, theLoc, coa,\\\"KILL\\\", killer, victim)\\\
    \\\
    if (not fratricide) and #killFeats > 0 then \\\
\\\
        -- use the feat description\\\
        -- we may want to use closest, currently simply the first \\\
        theFeatZone = killFeats[1]\\\
        local desc = cfxPlayerScore.evalFeatDescription(name, theFeatZone, killer, victim)  -- updates awardedTo\\\
                    \\\
        cfxPlayerScore.logFeatForPlayer(name, desc, playerSide)\\\
        theScore = cfxPlayerScore.getPlayerScore(name) -- re-read after write\\\
        \\\
        if cfxPlayerScore.verbose then \\\
            trigger.action.outText(\\\"Kill feat awarded/queued for <\\\" .. name .. \\\">\\\", 30)\\\
        end\\\
    end\\\
\\\
end\\\
\\\
function cfxPlayerScore.killDetected(theEvent)\\\
    -- we are only getting called when and if \\\
    -- a kill occured and killer was a player \\\
    -- and target exists\\\
    local killer = theEvent.initiator\\\
    local killerName = killer:getPlayerName()\\\
    if not killerName then killerName = \\\"<nil>\\\" end\\\
    local killSide = killer:getCoalition()\\\
    local killVehicle = killer:getTypeName()\\\
    if not killVehicle then killVehicle = \\\"<nil>\\\" end \\\
    local victim = theEvent.target\\\
\\\
    -- was it a player kill?\\\
    local pk = dcsCommon.isPlayerUnit(victim)\\\
\\\
    -- was it a scenery object? \\\
    local wasBuilding = dcsCommon.isSceneryObject(victim)\\\
    if wasBuilding then \\\
        -- these objects have no coalition; we simply award the score if \\\
        -- it exists in look-up table. \\\
        --trigger.action.outText(\\\"KILL SCENERY\\\", 30)\\\
        local staticScore = cfxPlayerScore.object2score(victim)\\\
        if staticScore > 0 then \\\
            trigger.action.outSoundForCoalition(killSide, cfxPlayerScore.scoreSound)\\\
            cfxPlayerScore.awardScoreTo(killSide, staticScore, killerName)\\\
            cfxPlayerScore.checkKillFeat(killerName, killer, victim, false)\\\
        end\\\
        return \\\
    end\\\
\\\
    -- was it fratricide?\\\
    local vicSide = victim:getCoalition()\\\
    local fraternicide = killSide == vicSide\\\
    local vicDesc = victim:getTypeName()\\\
    local scoreMod = 1 -- start at one \\\
\\\
    -- see what kind of unit (category) we killed\\\
    -- and look up base score \\\
    local isStO = cfxPlayerScore.isStaticObject(victim) \\\
    --if not victim.getGroup then\\\
    if isStO then \\\
        -- static objects have no group \\\
        \\\
        local staticName = victim:getName() -- on statics, this returns \\\
                                            -- name as entered in TOP LINE\\\
        local staticScore = cfxPlayerScore.object2score(victim)\\\
\\\
        if staticScore > 0 then \\\
            -- this was a named static, return the score - unless our own\\\
            if fraternicide then \\\
                scoreMod = cfxPlayerScore.ffMod * scoreMod -- blue on blue static kill\\\
                trigger.action.outSoundForCoalition(killSide, cfxPlayerScore.badSound)\\\
            else \\\
                trigger.action.outSoundForCoalition(killSide, cfxPlayerScore.scoreSound)\\\
            end\\\
            staticScore = scoreMod * staticScore\\\
            cfxPlayerScore.logKillForPlayer(killerName, victim)\\\
            cfxPlayerScore.awardScoreTo(killSide, staticScore, killerName)\\\
        else \\\
            -- no score, no mentions\\\
        end\\\
        \\\
        if not fraternicide then \\\
            cfxPlayerScore.checkKillFeat(killerName, killer, victim, false)\\\
        end \\\
        \\\
        \\\
        return \\\
    end \\\
    \\\
    local vicGroup = victim:getGroup()\\\
    if not vicGroup then \\\
        trigger.action.outText(\\\"+++scr: strange stuff:group, outta here\\\", 30)\\\
        return \\\
    end \\\
    local vicCat = vicGroup:getCategory()\\\
        if not vicCat then \\\
        trigger.action.outText(\\\"+++scr: strange stuff:cat, outta here\\\", 30)\\\
        return \\\
    end\\\
    local unitScore = cfxPlayerScore.unit2score(victim)\\\
\\\
    -- see which weapon was used. gun kills score 2x \\\
    local killMeth = \\\"\\\"\\\
    local killWeap = theEvent.weapon\\\
    --[[--\\\
    if killWeap then \\\
        local killWeapType = killWeap:getCategory()\\\
        if killWeapType == 0 then \\\
            killMeth = \\\" with GUNS\\\" \\\
            scoreMod = scoreMod * 2\\\
        else \\\
            local kWeapon = killWeap:getTypeName()\\\
            killMeth = \\\" with \\\" .. kWeapon\\\
        end        \\\
    end\\\
    --]]--\\\
    if pk then \\\
        vicDesc = victim:getPlayerName() .. \\\" in \\\" .. vicDesc \\\
        scoreMod = scoreMod * cfxPlayerScore.pkMod\\\
    end \\\
\\\
    \\\
    -- if fratricide, times ffMod (friedlyFire) \\\
    if fraternicide then\\\
        scoreMod = scoreMod * cfxPlayerScore.ffMod ---2\\\
        if cfxPlayerScore.announcer then \\\
            trigger.action.outTextForCoalition(killSide, killerName .. \\\" in \\\" .. killVehicle .. \\\" killed FRIENDLY \\\" .. vicDesc .. killMeth .. \\\"!\\\", 30)\\\
            trigger.action.outSoundForCoalition(killSide, cfxPlayerScore.badSound)\\\
        end \\\
    else \\\
        if cfxPlayerScore.announcer then \\\
            trigger.action.outText(killerName .. \\\" in \\\" .. killVehicle ..\\\" killed \\\" .. vicDesc .. killMeth ..\\\"!\\\", 30)\\\
            trigger.action.outSoundForCoalition(vicSide, cfxPlayerScore.badSound)\\\
            trigger.action.outSoundForCoalition(killSide, cfxPlayerScore.scoreSound)\\\
         end \\\
         -- since not fraticide, log this kill\\\
         -- logging kills does not impact score\\\
         cfxPlayerScore.logKillForPlayer(killerName, victim)\\\
    end\\\
    \\\
    -- see if it was a named target \\\
    if cfxPlayerScore.isNamedUnit(victim) then \\\
        if cfxPlayerScore.announcer then \\\
            trigger.action.outTextForCoalition(killSide, killerName .. \\\" reports killing strategic unit '\\\" .. victim:getName() .. \\\"'\\\", 30)\\\
        end \\\
    end\\\
    \\\
    local totalScore = unitScore * scoreMod\\\
    -- if the score is negative, awardScoreTo will automatically\\\
    -- make it immediate, else depending on deferred \\\
    cfxPlayerScore.awardScoreTo(killSide, totalScore, killerName)\\\
\\\
    if not fraternicide then \\\
        -- only award kill feats for kills of the enemy\\\
        cfxPlayerScore.checkKillFeat(killerName, killer, victim, false)\\\
    end \\\
\\\
end\\\
\\\
function cfxPlayerScore.handlePlayerLanding(theEvent)\\\
    local thePlayerUnit = theEvent.initiator\\\
    local theLoc = thePlayerUnit:getPoint()     \\\
    local playerSide = thePlayerUnit:getCoalition()\\\
    local playerName = thePlayerUnit:getPlayerName()\\\
    if cfxPlayerScore.verbose then \\\
        trigger.action.outText(\\\"+++pScr: Player <\\\" .. playerName .. \\\"> landed\\\", 30)\\\
    end\\\
    \\\
    local theScore = cfxPlayerScore.getPlayerScore(playerName)\\\
    \\\
    -- see if a feat is available for this landing \\\
    local landingFeats = cfxPlayerScore.featsForLocation(playerName, theLoc, playerSide,\\\"LANDING\\\")\\\
    \\\
    -- first, scheck if landing is awardable, and if so, \\\
    -- award the landing \\\
    if cfxPlayerScore.landing > 0 or #landingFeats > 0 then \\\
        -- yes, landings are awarded a score. do before \\\
        -- resolving any queues \\\
        desc = \\\"Landed\\\"\\\
        if #landingFeats > 0 then \\\
            -- use the feat description\\\
            -- we may want to use closest, currently simply the first \\\
            theFeatZone = landingFeats[1]\\\
            desc = cfxPlayerScore.evalFeatDescription(playerName, theFeatZone, thePlayerUnit) -- nil victim, defaults to player \\\
            \\\
        else \\\
            if theEvent.place then \\\
                desc = desc .. \\\" successfully (\\\" .. theEvent.place:getName() .. \\\")\\\"\\\
            else \\\
                desc = desc .. \\\" aircraft\\\"\\\
            end\\\
        end \\\
        \\\
        cfxPlayerScore.updateScoreForPlayer(playerName, cfxPlayerScore.landing)\\\
        cfxPlayerScore.logFeatForPlayer(playerName, desc, playerSide)\\\
        theScore = cfxPlayerScore.getPlayerScore(playerName) -- re-read after write\\\
        if cfxPlayerScore.verbose then \\\
            trigger.action.outText(\\\"Landing feat awarded/queued for <\\\" .. playerName .. \\\">\\\", 30)\\\
        end\\\
    end\\\
    \\\
    -- see if we are using deferred scoring, else can end right now \\\
    if not cfxPlayerScore.deferred then \\\
        return \\\
    end\\\
    -- only continue if there is anything to award \\\
    local killSize = dcsCommon.getSizeOfTable(theScore.killQueue)\\\
    local featSize = dcsCommon.getSizeOfTable(theScore.featQueue)\\\
    \\\
    if cfxPlayerScore.verbose then \\\
        trigger.action.outText(\\\"+++pScr: prepping deferred score for <\\\" .. playerName ..\\\">\\\", 30)\\\
    end\\\
    \\\
    -- see if player landed in a scoreSafe zone \\\
    local theUnit = thePlayerUnit\\\
    local loc = theUnit:getPoint()\\\
    local uid = theUnit:getID()\\\
    local coa = theUnit:getCoalition()\\\
    local isSafe = false \\\
    for idx, theZone in pairs(cfxPlayerScore.safeZones) do \\\
        if theZone.scoreSafe == 0 or theZone.scoreSafe == coa then \\\
            -- make sure that this zone doesn't belong to the \\\
            -- wrong faction (if owned zone) \\\
            if (theZone.owner == coa) or (theZone.owner == 0) or (theZone.owner == nil) then \\\
                if cfxZones.pointInZone(loc, theZone) then \\\
                    isSafe = true\\\
                end\\\
            else \\\
                if cfxPlayerScore.verbose then \\\
                    trigger.action.outText(\\\"+++pSc: Zone <\\\" .. theZone.name .. \\\">: owner=<\\\" .. theZone.owner .. \\\">, my coa=<\\\" .. coa .. \\\">, no owner match\\\")\\\
                end\\\
            end\\\
        end \\\
    end\\\
    \\\
    if not isSafe then \\\
        if cfxPlayerScore.verbose then \\\
            trigger.action.outText(\\\"+++pScr: deferred, but not inside score safe zone.\\\", 30)\\\
        end\\\
        return \\\
    end \\\
    \\\
    trigger.action.outTextForUnit(uid, playerName .. \\\", please wait in safe zone to claim pending score/feats (\\\" .. cfxPlayerScore.delayAfterLanding .. \\\" seconds).\\\", 30)\\\
\\\
    local unitName = theUnit:getName()\\\
    local args = {playerName, unitName}\\\
    timer.scheduleFunction(cfxPlayerScore.scheduledAward, args, timer.getTime() + cfxPlayerScore.delayAfterLanding)\\\
end\\\
\\\
function cfxPlayerScore.scheduledAward(args)\\\
    -- called with player name and unit name in args \\\
    local playerName = args[1]\\\
    local unitName = args[2]\\\
    \\\
    local theUnit = Unit.getByName(unitName)\\\
    if not theUnit or \\\
       not Unit.isExist(theUnit) \\\
    then \\\
        -- unit is gone\\\
        trigger.action.outText(\\\"Player <\\\" .. playerName .. \\\"> lost score.\\\", 30)\\\
        return \\\
    end\\\
    \\\
    local uid = theUnit:getID()\\\
    if theUnit:inAir() then \\\
        trigger.action.outTextForUnit(uid, \\\"Can't award score to <\\\" .. playerName .. \\\">: unit not on the ground.\\\", 30)\\\
        return \\\
    end\\\
    \\\
    if theUnit:getLife() < 1 then \\\
        trigger.action.outTextForUnit(uid, \\\"Can't award score to <\\\" .. playerName .. \\\">: unit did not survive landing.\\\", 30)\\\
        return  -- needs to reslot, don't have to nil player score\\\
    end\\\
    \\\
    -- see if player is *still* within a scoreSafe zone \\\
    local loc = theUnit:getPoint()\\\
    local coa = theUnit:getCoalition()\\\
    local isSafe = false \\\
    for idx, theZone in pairs(cfxPlayerScore.safeZones) do \\\
        if theZone.scoreSafe == 0 or theZone.scoreSafe == coa then\\\
            -- we no longer check ownership of zone, we did that when we landed\\\
            if cfxZones.pointInZone(loc, theZone) then \\\
                isSafe = true\\\
            end\\\
        end \\\
    end\\\
    \\\
    if not isSafe then \\\
        trigger.action.outTextForUnit(uid, \\\"Can't award score for <\\\" .. playerName .. \\\">, not in safe zone.\\\", 30)\\\
        return \\\
    end \\\
    \\\
    \\\
    local theScore = cfxPlayerScore.getPlayerScore(playerName)\\\
    local playerSide = dcsCommon.playerName2Coalition(playerName)\\\
    if playerSide < 1 then\\\
        trigger.action.outText(\\\"+++pScr: WARNING - unaffiliated player <\\\" .. playerName .. \\\">, score award ignored\\\", 30)\\\
        return \\\
    end \\\
    if dcsCommon.getSizeOfTable(theScore.killQueue) < 1 and \\\
       dcsCommon.getSizeOfTable(theScore.featQueue) < 1 and \\\
       theScore.scoreaccu < 1 then \\\
        -- player changed planes or \\\
        -- there was nothing to award \\\
        trigger.action.outTextForUnit(uid, \\\"Thank you, \\\" .. playerName .. \\\", no scores or feats pending.\\\", 30)\\\
        return \\\
    end\\\
    \\\
    local hasAward = false \\\
    \\\
    -- when we get here we award all scores, kills, and feats \\\
    local desc = \\\"\\\\nPlayer \\\" .. playerName .. \\\" is awarded:\\\\n\\\"\\\
    -- score and total score \\\
    if theScore.scoreaccu > 0 then -- remember: negatives are immediate \\\
        theScore.score = theScore.score + theScore.scoreaccu\\\
        desc = desc .. \\\"  score: \\\" .. theScore.scoreaccu .. \\\" for a new total of \\\" .. theScore.score .. \\\"\\\\n\\\"\\\
        cfxPlayerScore.coalitionScore[playerSide] = cfxPlayerScore.coalitionScore[playerSide] + theScore.scoreaccu\\\
        theScore.scoreaccu = 0 \\\
        hasAward = true \\\
    end \\\
    \\\
    if cfxPlayerScore.verbose then \\\
        trigger.action.outText(\\\"Iterating kill q <\\\" .. dcsCommon.getSizeOfTable(theScore.killQueue) .. \\\"> and feat q <\\\" .. dcsCommon.getSizeOfTable(theScore.featQueue) .. \\\">\\\", 30)\\\
    end\\\
    -- iterate kill type list \\\
    if dcsCommon.getSizeOfTable(theScore.killQueue) > 0 then \\\
        desc = desc .. \\\"  confirmed kills in order:\\\\n\\\"\\\
        for idx, theType in pairs(theScore.killQueue) do \\\
            desc = desc .. \\\"    \\\" .. theType .. \\\"\\\\n\\\"\\\
            cfxPlayerScore.doLogTypeKill(playerName, theScore, theType)\\\
        end\\\
        hasAward = true \\\
    end\\\
    theScore.killQueue = {}\\\
    \\\
    -- iterate feats \\\
    if dcsCommon.getSizeOfTable(theScore.featQueue) > 0 then \\\
        desc = desc .. \\\"  confirmed feats:\\\\n\\\"\\\
        for idx, theFeat in pairs(theScore.featQueue) do \\\
            desc = desc .. \\\"    \\\" .. theFeat .. \\\"\\\\n\\\"\\\
            cfxPlayerScore.doLogFeat(playerName, theScore, theFeat)\\\
        end\\\
        hasAward = true \\\
    end\\\
    theScore.featQueue = {}\\\
    \\\
    if cfxPlayerScore.reportCoalition then \\\
        desc = desc .. \\\"\\\\nCoalition Total: \\\" .. cfxPlayerScore.coalitionScore[playerSide]\\\
    end\\\
    \\\
    -- output score \\\
    desc = desc .. \\\"\\\\n\\\"\\\
    if hasAward then \\\
        trigger.action.outTextForCoalition(coa, desc, 30)\\\
    end \\\
end\\\
\\\
function cfxPlayerScore.handlePlayerDeath(theEvent)\\\
    -- multiple of these events can occur per player \\\
    -- so we use the unit2player link to see player \\\
    -- is affected, and if so, erase the link so it \\\
    -- only counts once \\\
    local theUnit = theEvent.initiator \\\
    local uName = theUnit:getName()\\\
    \\\
    if cfxPlayerScore.verbose then \\\
        trigger.action.outText(\\\"+++pScr: LOA/player death handler entry for <\\\" .. uName .. \\\">\\\", 30)\\\
    end\\\
    \\\
    local pName = cfxPlayerScore.unit2player[uName] \\\
    if pName then \\\
        -- this was a player name with link still live.\\\
        if cfxPlayerScore.planeLoss ~= 0 then \\\
            -- plane loss has IMMEDIATE consequences \\\
            cfxPlayerScore.updateScoreForPlayerImmediate(pName, cfxPlayerScore.planeLoss)\\\
            if cfxPlayerScore.announcer then \\\
                local uid = theUnit:getID()\\\
                local thePlayerRecord = cfxPlayerScore.getPlayerScore(pName)\\\
                trigger.action.outTextForUnit(uid, \\\"Loss of aircraft detected: \\\" .. cfxPlayerScore.planeLoss .. \\\" awarded immediately, for new total of \\\" .. thePlayerRecord.score, 30)\\\
            end\\\
        end\\\
        -- always clear the link.\\\
        cfxPlayerScore.unit2player[uName] = nil\\\
    else \\\
        if cfxPlayerScore.verbose then \\\
            trigger.action.outText(\\\"+++pScr - no action for LOA\\\", 30)\\\
        end\\\
    end\\\
\\\
end\\\
\\\
function cfxPlayerScore.handlePlayerEvent(theEvent)\\\
    if theEvent.id == 28 then \\\
        -- kill from player detected.\\\
        cfxPlayerScore.killDetected(theEvent)    \\\
        \\\
    elseif theEvent.id == 15 then -- birth \\\
        -- access player score for player. this will \\\
        -- allocate if doesn't exist. Any player ever \\\
        -- birthed will be in db\\\
        local thePlayerUnit = theEvent.initiator \\\
        local playerSide = thePlayerUnit:getCoalition()\\\
        local playerName = thePlayerUnit:getPlayerName()\\\
        local theScore = cfxPlayerScore.getPlayerScore(playerName)\\\
        -- now re-init feat and score queues \\\
        \\\
        if theScore.scoreaccu and theScore.scoreaccu > 0 then \\\
            trigger.action.outTextForCoalition(playerSide, \\\"Player \\\" .. playerName .. \\\", score of <\\\" .. theScore.scoreaccu .. \\\"> points discarded.\\\", 30)\\\
        end \\\
        theScore.scoreaccu = 0 \\\
        if dcsCommon.getSizeOfTable(theScore.killQueue) > 0 then \\\
            trigger.action.outTextForCoalition(playerSide, \\\"Player \\\" .. playerName .. \\\", <\\\" .. dcsCommon.getSizeOfTable(theScore.killQueue) .. \\\"> kills discarded.\\\", 30)\\\
        end\\\
        theScore.killQueue = {}\\\
        if dcsCommon.getSizeOfTable(theScore.featQueue) > 0 then \\\
            trigger.action.outTextForCoalition(playerSide, \\\"Player \\\" .. playerName .. \\\", <\\\" .. dcsCommon.getSizeOfTable(theScore.featQueue) .. \\\"> feats discarded.\\\", 30)\\\
        end        \\\
        theScore.featQueue = {}\\\
        -- write back\\\
        cfxPlayerScore.setPlayerScore(playerName, theScore)\\\
        \\\
    elseif theEvent.id == 4 then -- land \\\
        -- see if plane is still connected to player \\\
        local theUnit = theEvent.initiator\\\
        local uName = theUnit:getName() \\\
        if cfxPlayerScore.unit2player[uName] then \\\
        -- is filtered if too soon after last take-off/landing \\\
        cfxPlayerScore.handlePlayerLanding(theEvent)\\\
        else \\\
            if verbose then \\\
                trigger.action.outText(\\\"+++pScr: filtered landing for <\\\" .. uName .. \\\">: player no longer linked to unit\\\", 30)\\\
            end\\\
        end    \\\
\\\
    end\\\
end\\\
\\\
function cfxPlayerScore.readConfigZone(theZone)\\\
    cfxPlayerScore.verbose = cfxZones.getBoolFromZoneProperty(theZone, \\\"verbose\\\", false)\\\
    -- default scores \\\
    cfxPlayerScore.aircraft = cfxZones.getNumberFromZoneProperty(theZone, \\\"aircraft\\\", 50) \\\
    cfxPlayerScore.helo = cfxZones.getNumberFromZoneProperty(theZone, \\\"helo\\\", 40)  \\\
    cfxPlayerScore.ground = cfxZones.getNumberFromZoneProperty(theZone, \\\"ground\\\", 10)  \\\
    cfxPlayerScore.ship = cfxZones.getNumberFromZoneProperty(theZone, \\\"ship\\\", 80)   \\\
    cfxPlayerScore.train = cfxZones.getNumberFromZoneProperty(theZone, \\\"train\\\", 5)\\\
    cfxPlayerScore.landing = cfxZones.getNumberFromZoneProperty(theZone, \\\"landing\\\", 0) -- if > 0 then feat \\\
    \\\
    cfxPlayerScore.pkMod = cfxZones.getNumberFromZoneProperty(theZone, \\\"pkMod\\\", 1) -- factor for killing a player\\\
    cfxPlayerScore.ffMod = cfxZones.getNumberFromZoneProperty(theZone, \\\"ffMod\\\", -2) -- factor for friendly fire \\\
    cfxPlayerScore.planeLoss = cfxZones.getNumberFromZoneProperty(theZone, \\\"planeLoss\\\", -10) -- points added when player's plane crashes\\\
    \\\
    cfxPlayerScore.announcer = cfxZones.getBoolFromZoneProperty(theZone, \\\"announcer\\\", true)\\\
    \\\
    if cfxZones.hasProperty(theZone, \\\"badSound\\\") then \\\
        cfxPlayerScore.badSound = cfxZones.getStringFromZoneProperty(theZone, \\\"badSound\\\", \\\"<nosound>\\\")\\\
    end\\\
    if cfxZones.hasProperty(theZone, \\\"scoreSound\\\") then \\\
        cfxPlayerScore.scoreSound = cfxZones.getStringFromZoneProperty(theZone, \\\"scoreSound\\\", \\\"<nosound>\\\")\\\
    end\\\
    \\\
    -- triggering saving scores\\\
    if cfxZones.hasProperty(theZone, \\\"saveScore?\\\") then \\\
        cfxPlayerScore.saveScore = cfxZones.getStringFromZoneProperty(theZone, \\\"saveScore?\\\", \\\"none\\\")\\\
        cfxPlayerScore.lastSaveScore = trigger.misc.getUserFlag(cfxPlayerScore.saveScore)\\\
        cfxPlayerScore.incremental = cfxZones.getBoolFromZoneProperty(theZone, \\\"incremental\\\", false) -- incremental saves \\\
    end\\\
    \\\
    -- triggering show all scores\\\
    if cfxZones.hasProperty(theZone, \\\"showScore?\\\") then \\\
        cfxPlayerScore.showScore = cfxZones.getStringFromZoneProperty(theZone, \\\"showScore?\\\", \\\"none\\\")\\\
        cfxPlayerScore.lastShowScore = trigger.misc.getUserFlag(cfxPlayerScore.showScore)\\\
    end\\\
    \\\
    cfxPlayerScore.rankPlayers = cfxZones.getBoolFromZoneProperty(theZone, \\\"rankPlayers\\\", false)\\\
    \\\
    cfxPlayerScore.scoreOnly = cfxZones.getBoolFromZoneProperty(theZone, \\\"scoreOnly\\\", true)\\\
    \\\
    cfxPlayerScore.deferred = cfxZones.getBoolFromZoneProperty(theZone, \\\"deferred\\\", false)\\\
    \\\
    cfxPlayerScore.delayAfterLanding = cfxZones.getNumberFromZoneProperty(theZone, \\\"delayAfterLanding\\\", 10)\\\
    \\\
    cfxPlayerScore.scoreFileName = cfxZones.getStringFromZoneProperty(theZone, \\\"scoreFileName\\\", \\\"Player Scores\\\")\\\
\\\
    cfxPlayerScore.reportScore = cfxZones.getBoolFromZoneProperty(theZone, \\\"reportScore\\\", true)\\\
    \\\
    cfxPlayerScore.reportFeats = cfxZones.getBoolFromZoneProperty(theZone, \\\"reportFeats\\\", true)\\\
    \\\
    cfxPlayerScore.reportCoalition = cfxZones.getBoolFromZoneProperty(\\\
    theZone, \\\"reportCoalition\\\", false) -- also show coalition score \\\
    \\\
    cfxPlayerScore.noGrief = cfxZones.getBoolFromZoneProperty(theZone, \\\"noGrief\\\", true) -- noGrief = only add positive score \\\
end\\\
\\\
--\\\
-- load / save (game data)\\\
--\\\
function cfxPlayerScore.saveData()\\\
    local theData = {}\\\
    -- save current score list. simple clone \\\
    local theScore = dcsCommon.clone(cfxPlayerScore.playerScore)\\\
    theData.theScore = theScore\\\
    -- build feat zone list \\\
    theData.coalitionScore = dcsCommon.clone(cfxPlayerScore.coalitionScore)\\\
    local featZones = {}\\\
    for idx, theZone in pairs(cfxPlayerScore.featZones) do \\\
        local theFeat = {}\\\
        theFeat.awardedTo = theZone.awardedTo \\\
        theFeat.featNum = theZone.featNum \\\
        featZones[theZone.name] = theFeat\\\
    end\\\
    theData.featData = featZones \\\
    return theData\\\
end\\\
\\\
function cfxPlayerScore.loadData()\\\
    if not persistence then return end \\\
    local theData = persistence.getSavedDataForModule(\\\"cfxPlayerScore\\\")\\\
    if not theData then \\\
        if cfxPlayerScore.verbose then \\\
            trigger.action.outText(\\\"+++playerscore: no save date received, skipping.\\\", 30)\\\
        end\\\
        return\\\
    end\\\
    \\\
    local theScore = theData.theScore\\\
    cfxPlayerScore.playerScore = theScore \\\
    if theData.coalitionScore then \\\
        cfxPlayerScore.coalitionScore = theData.coalitionScore\\\
    end\\\
    local featData = theData.featData \\\
    if featData then \\\
        for name, data in pairs(featData) do \\\
            local theZone = cfxPlayerScore.getFeatByName(name)\\\
            if theZone then \\\
                theZone.awardedTo = data.awardedTo\\\
                theZone.featNum = data.featNum\\\
            end\\\
        end        \\\
    end \\\
end\\\
\\\
--\\\
-- save scores (text file)\\\
--\\\
\\\
function cfxPlayerScore.saveScores(theText, name)\\\
    if not _G[\\\"persistence\\\"] then \\\
        trigger.action.outText(\\\"+++pScr: persistence module required to save scores. Here are the scores that I would have saved to <\\\" .. name .. \\\">:\\\\n\\\", 30)\\\
        trigger.action.outText(theText, 30)\\\
        return\\\
    end\\\
    \\\
    if not persistence.active then \\\
        trigger.action.outText(\\\"+++pScr: persistence module can't write. Please ensure that you have desanitized lfs and io for DCS\\\", 30)\\\
        return \\\
    end\\\
    \\\
    local append = cfxPlayerScore.incremental\\\
    local shared = false -- currently not supported\\\
\\\
    if cfxPlayerScore.incremental then \\\
        if cfxPlayerScore.firstSave then \\\
            theText = \\\"\\\\n*** NEW MISSION started.\\\\n\\\" .. theText\\\
        end\\\
        \\\
        -- prepend time for score \\\
        theText = \\\"\\\\n\\\\n====== Mission Time: \\\" .. dcsCommon.nowString() .. \\\"\\\\n\\\" .. theText\\\
    end \\\
    \\\
    if persistence.saveText(theText, name, shared, append) then \\\
        if cfxPlayerScore.verbose then \\\
            trigger.action.outText(\\\"+++pScr: scores saved to <\\\" .. persistence.missionDir .. name .. \\\">\\\", 30)\\\
        end\\\
    else \\\
        trigger.action.outText(\\\"+++pScr: unable to save scores to <\\\" .. persistence.missionDir .. name .. \\\">\\\")\\\
    end\\\
    \\\
    cfxPlayerScore.firstSave  = false \\\
end\\\
\\\
function cfxPlayerScore.saveScoreToFile()\\\
    -- local built score table \\\
    local ranked = cfxPlayerScore.rankPlayers\\\
    local theText = cfxPlayerScore.scoreTextForAllPlayers(ranked) \\\
    \\\
    -- save to disk \\\
    cfxPlayerScore.saveScores(theText, cfxPlayerScore.scoreFileName)\\\
end\\\
\\\
function cfxPlayerScore.showScoreToAll()\\\
    local ranked = cfxPlayerScore.rankPlayers\\\
    local theText = cfxPlayerScore.scoreTextForAllPlayers(ranked) \\\
    trigger.action.outText(theText, 30)\\\
end\\\
\\\
--\\\
-- Update\\\
--\\\
function cfxPlayerScore.update()\\\
    -- re-invoke in 1 second\\\
    timer.scheduleFunction(cfxPlayerScore.update, {}, timer.getTime() + 1)\\\
    \\\
    -- see if someone banged on saveScore\\\
    if cfxPlayerScore.saveScore then \\\
        if cfxZones.testZoneFlag(cfxPlayerScore, cfxPlayerScore.saveScore, \\\"change\\\", \\\"lastSaveScore\\\") then \\\
            if cfxPlayerScore.verbose then \\\
                trigger.action.outText(\\\"+++pScr: saving scores...\\\", 30)\\\
            end\\\
            cfxPlayerScore.saveScoreToFile()\\\
        end\\\
    end\\\
    \\\
    -- showScore perhaps?\\\
    if cfxPlayerScore.showScore then \\\
        if cfxZones.testZoneFlag(cfxPlayerScore, cfxPlayerScore.showScore, \\\"change\\\", \\\"lastShowScore\\\") then \\\
            if cfxPlayerScore.verbose then \\\
                trigger.action.outText(\\\"+++pScr: showing scores...\\\", 30)\\\
            end\\\
            cfxPlayerScore.showScoreToAll()\\\
        end\\\
    end\\\
    \\\
    -- check score flags \\\
    if cfxPlayerScore.blueTriggerFlags then \\\
        local coa = 2\\\
        for tName, tVal in pairs(cfxPlayerScore.blueTriggerFlags) do \\\
            local newVal = trigger.misc.getUserFlag(tName)\\\
            if tVal ~= newVal then \\\
                -- score!\\\
                cfxPlayerScore.coalitionScore[coa] = cfxPlayerScore.coalitionScore[coa] + cfxPlayerScore.blueTriggerScore[tName]\\\
                cfxPlayerScore.blueTriggerFlags[tName] = newVal\\\
                if cfxPlayerScore.announcer then\\\
                    trigger.action.outTextForCoalition(coa, \\\"BLUE goal [\\\" .. tName .. \\\"] achieved, new BLUE coalition score is \\\" .. cfxPlayerScore.coalitionScore[coa], 30)\\\
                    trigger.action.outSoundForCoalition(coa, cfxPlayerScore.scoreSound)\\\
                end\\\
            end\\\
        end\\\
    end\\\
    if cfxPlayerScore.redTriggerFlags then \\\
        local coa = 1\\\
        for tName, tVal in pairs(cfxPlayerScore.redTriggerFlags) do \\\
            local newVal = trigger.misc.getUserFlag(tName)\\\
--                trigger.action.outText(\\\"checking RED flag <\\\" .. tName .. \\\">\\\", 30)\\\
                if tVal ~= newVal then \\\
                -- score!\\\
\\\
                cfxPlayerScore.coalitionScore[coa] = cfxPlayerScore.coalitionScore[coa] + cfxPlayerScore.redTriggerScore[tName]\\\
                cfxPlayerScore.redTriggerFlags[tName] = newVal\\\
                if cfxPlayerScore.announcer then\\\
                    trigger.action.outTextForCoalition(coa, \\\"RED goal [\\\" .. tName .. \\\"] achieved, new RED coalition score is \\\" .. cfxPlayerScore.coalitionScore[coa], 30)\\\
                    trigger.action.outSoundForCoalition(coa, cfxPlayerScore.scoreSound)\\\
                end\\\
            end\\\
        end\\\
    end\\\
end\\\
--\\\
-- start\\\
--\\\
function cfxPlayerScore.start()\\\
    if not dcsCommon.libCheck(\\\"cfx Player Score\\\", \\\
                              cfxPlayerScore.requiredLibs) \\\
    then \\\
        return false \\\
    end\\\
    \\\
    -- read my score table \\\
    -- identify and process a score table zones\\\
    local theZone = cfxZones.getZoneByName(\\\"playerScoreTable\\\") \\\
    if not theZone then \\\
        trigger.action.outText(\\\"+++scr: no score table!\\\", 30) \\\
    else \\\
        -- read all into my types registry, replacing whatever is there\\\
        cfxPlayerScore.typeScore = cfxZones.getAllZoneProperties(theZone)\\\
        trigger.action.outText(\\\"+++scr: read score table\\\", 30) \\\
    end \\\
    \\\
    -- read score tiggers and values\\\
    cfxPlayerScore.redTriggerFlags = nil\\\
    cfxPlayerScore.blueTriggerFlags = nil\\\
    local theZone = cfxZones.getZoneByName(\\\"redScoreFlags\\\") \\\
    if theZone then \\\
        -- read flags into redTriggerScore\\\
        cfxPlayerScore.redTriggerScore = cfxZones.getAllZoneProperties(theZone, false, true) -- use case, all numbers \\\
        -- init their flag handlers \\\
        cfxPlayerScore.redTriggerFlags = {}\\\
        trigger.action.outText(\\\"+++pScr: read RED score table\\\", 30)\\\
        for tName, tScore in pairs(cfxPlayerScore.redTriggerScore) do \\\
            if tScore == 0 then \\\
                trigger.action.outText(\\\"+++pScr: WARNING - RED triggered score <\\\" .. tName .. \\\"> has zero score value!\\\", 30)\\\
            end\\\
            cfxPlayerScore.redTriggerFlags[tName] = trigger.misc.getUserFlag(tName)\\\
--            trigger.action.outText(\\\"+++pScr: RED trigger <\\\" .. tName .. \\\">, score value (\\\" .. tScore .. \\\") inited to <\\\" .. cfxPlayerScore.redTriggerFlags[tName] .. \\\">\\\", 30)\\\
        end\\\
    end \\\
    local theZone = cfxZones.getZoneByName(\\\"blueScoreFlags\\\") \\\
    if theZone then \\\
        -- read flags into redTriggerScore\\\
        cfxPlayerScore.blueTriggerScore = cfxZones.getAllZoneProperties(theZone, false, true) -- case sensitive, numbers only\\\
        -- init their flag handlers \\\
        cfxPlayerScore.blueTriggerFlags = {}\\\
        trigger.action.outText(\\\"+++pScr: read BLUE score table\\\", 30)\\\
        for tName, tScore in pairs(cfxPlayerScore.blueTriggerScore) do\\\
            if tScore == 0 then \\\
                trigger.action.outText(\\\"+++pScr: WARNING - BLUE triggered score <\\\" .. tName .. \\\"> has zero score value!\\\", 30)\\\
            end        \\\
            cfxPlayerScore.blueTriggerFlags[tName] = trigger.misc.getUserFlag(tName)\\\
--            trigger.action.outText(\\\"+++pScr: BLUE trigger <\\\" .. tName .. \\\">, score value (\\\" .. tScore .. \\\") inited to <\\\" .. cfxPlayerScore.blueTriggerFlags[tName] .. \\\">\\\", 30)\\\
        end\\\
    end \\\
    \\\
    -- now read my config zone \\\
    local theZone = cfxZones.getZoneByName(\\\"playerScoreConfig\\\") \\\
    if not theZone then \\\
        trigger.action.outText(\\\"+++pScr: no config!\\\", 30) \\\
        theZone = cfxZones.createSimpleZone(\\\"playerScoreConfig\\\")\\\
    end \\\
    cfxPlayerScore.readConfigZone(theZone)\\\
    --    trigger.action.outText(\\\"+++scr: read config\\\", 30) \\\
     \\\
    \\\
    -- read all scoreSafe zones \\\
    local safeZones = cfxZones.zonesWithProperty(\\\"scoreSafe\\\")\\\
    for k, aZone in pairs(safeZones) do\\\
        cfxPlayerScore.addSafeZone(aZone)\\\
    end\\\
    \\\
    -- read all feat zones \\\
    local featZones = cfxZones.zonesWithProperty(\\\"feat\\\")\\\
    for k, aZone in pairs(featZones) do\\\
        cfxPlayerScore.addFeatZone(aZone)\\\
    end\\\
    \\\
    -- read all kill zones \\\
    local killZones = cfxZones.zonesWithProperty(\\\"killZone\\\")\\\
    for k, aZone in pairs(killZones) do\\\
        cfxPlayerScore.addKillZone(aZone)\\\
    end\\\
    \\\
    -- check that deferred has scoreSafe zones \\\
    if cfxPlayerScore.deferred and dcsCommon.getSizeOfTable(cfxPlayerScore.safeZones) < 1 then \\\
        trigger.action.outText(\\\"+++pScr: WARNING - deferred scoring active but no 'scoreSafe' zones set!\\\", 30)\\\
    end\\\
    \\\
    -- subscribe to events and use dcsCommon's handler structure\\\
    dcsCommon.addEventHandler(cfxPlayerScore.handlePlayerEvent,\\\
                              cfxPlayerScore.preProcessor,\\\
                              cfxPlayerScore.postProcessor)\\\
                              \\\
    -- now load all save data and populate map with troops that\\\
    -- we deployed last save. \\\
    if persistence then \\\
        -- sign up for persistence \\\
        callbacks = {}\\\
        callbacks.persistData = cfxPlayerScore.saveData\\\
        persistence.registerModule(\\\"cfxPlayerScore\\\", callbacks)\\\
        -- now load my data \\\
        cfxPlayerScore.loadData()\\\
    end\\\
    \\\
    -- start update \\\
    cfxPlayerScore.update()\\\
        \\\
    trigger.action.outText(\\\"cfxPlayerScore v\\\" .. cfxPlayerScore.version .. \\\" started\\\", 30)\\\
    return true \\\
end\\\
\\\
\\\
if not cfxPlayerScore.start() then \\\
    trigger.action.outText(\\\"+++ aborted cfxPlayerScore v\\\" .. cfxPlayerScore.version .. \\\"  -- libcheck failed\\\", 30)\\\
    cfxPlayerScore = nil \\\
end\\\
\\\
-- TODO: score mod for weapons type \\\
-- TODO: player kill score \\\
\\\
--[[--\\\
\\\
feat zone\\\
\\\"feat\\\" feat type, default is kill, possible other types \\\
    - landing \\\
score zones \\\
    - zones outside of which no scoring counts, but feats are still ok \\\
    \\\
- add take off feats\\\
\\\
can be extended with other, standalone feat modules that follow the \\\
same pattern, e.g. enter a zone, detect someone \\\
\\\
--]]--\\\
 \");a_do_script(\"radioMenu = {}\\\
radioMenu.version = \\\"2.0.1\\\"\\\
radioMenu.verbose = false \\\
radioMenu.ups = 1 \\\
radioMenu.requiredLibs = {\\\
    \\\"dcsCommon\\\", -- always\\\
    \\\"cfxZones\\\", -- Zones, of course \\\
}\\\
radioMenu.menus = {}\\\
\\\
--[[--\\\
    Version History \\\
    1.0.0 Initial version \\\
    1.0.1 spelling corrections\\\
    1.1.0 removeMenu \\\
          addMenu \\\
          menuVisible \\\
    2.0.0 redesign: handles multiple receivers\\\
          optional MX module \\\
          group option\\\
          type option\\\
          multiple group names \\\
          multiple types \\\
          gereric helo type \\\
          generic plane type \\\
          type works with coalition \\\
    2.0.1 corrections to installMenu(), as suggested by GumidekCZ\\\
\\\
    \\\
--]]--\\\
\\\
function radioMenu.addRadioMenu(theZone)\\\
    table.insert(radioMenu.menus, theZone)\\\
end\\\
\\\
function radioMenu.getRadioMenuByName(aName) \\\
    for idx, aZone in pairs(radioMenu.menus) do \\\
        if aName == aZone.name then return aZone end \\\
    end\\\
    if radioMenu.verbose then \\\
        trigger.action.outText(\\\"+++radioMenu: no radioMenu with name <\\\" .. aName ..\\\">\\\", 30)\\\
    end \\\
    \\\
    return nil \\\
end\\\
\\\
--\\\
-- read zone \\\
-- \\\
function radioMenu.filterPlayerIDForType(theZone)\\\
    -- note: we currently ignore coalition \\\
    local theIDs = {}\\\
    local allTypes = {}\\\
    if dcsCommon.containsString(theZone.menuTypes, \\\",\\\") then \\\
        allTypes = dcsCommon.splitString(theZone.menuTypes, \\\",\\\")\\\
    else \\\
        table.insert(allTypes, theZone.menuTypes)\\\
    end\\\
    \\\
    -- now iterate all types, and include any player that matches\\\
    -- note that a player may match twice, so we use a dict instead of an \\\
    -- array. Since we later iterate ID by idx, that's not an issue\\\
    \\\
    for idx, aType in pairs(allTypes) do \\\
        local theType = dcsCommon.trim(aType)\\\
        local lowerType = string.lower(theType)\\\
        \\\
        for gName, gData in pairs(cfxMX.playerGroupByName) do \\\
            -- get coalition of group \\\
            local coa = cfxMX.groupCoalitionByName[gName]\\\
            if (theZone.coalition == 0 or theZone.coalition == coa) then \\\
                -- do special types first \\\
                if dcsCommon.stringStartsWith(lowerType, \\\"helo\\\") or dcsCommon.stringStartsWith(lowerType, \\\"heli\\\") then \\\
                    -- we look for all helicoperts\\\
                    if cfxMX.groupTypeByName[gName] == \\\"helicopter\\\" then \\\
                        theIDs[gName] = gData.groupId\\\
                        if theZone.verbose or radioMenu.verbose then \\\
                            trigger.action.outText(\\\"+++menu: Player Group <\\\" .. gName .. \\\"> matches gen-type helicopter\\\", 30)\\\
                        end\\\
                    end\\\
                elseif lowerType == \\\"plane\\\" or lowerType == \\\"planes\\\" then \\\
                    -- we look for all planes \\\
                    if cfxMX.groupTypeByName[gName] == \\\"plane\\\" then \\\
                        theIDs[gName] = gData.groupId\\\
                        if theZone.verbose or radioMenu.verbose then \\\
                            trigger.action.outText(\\\"+++menu: Player Group <\\\" .. gName .. \\\"> matches gen-type plane\\\", 30)\\\
                        end\\\
                    end\\\
                else\\\
                    -- we are looking for a particular type, e.g. A-10A\\\
                    -- since groups do not carry the type, but all player\\\
                    -- groups are of the same type, we access the first \\\
                    -- unit. Note that this may later break if ED implement \\\
                    -- player groups of mixed type \\\
                    if gData.units and gData.units[1] and gData.units[1].type == theType then \\\
                        theIDs[gName] = gData.groupId\\\
                        if theZone.verbose or radioMenu.verbose then \\\
                            trigger.action.outText(\\\"+++menu: Player Group <\\\" .. gName .. \\\"> matches type <\\\" .. theType .. \\\">\\\", 30)\\\
                        end\\\
                    else \\\
                        \\\
                    end\\\
                end\\\
            else \\\
                if theZone.verbose or radioMenu.verbose then \\\
                    trigger.action.outText(\\\"+++menu: type check failed coalition for <\\\" .. gName .. \\\">\\\", 30)\\\
                end\\\
            end\\\
        end\\\
    end\\\
    return theIDs\\\
end\\\
\\\
function radioMenu.filterPlayerIDForGroup(theZone)\\\
    -- create an iterable list of groups, separated by commas \\\
    -- note that we could introduce wildcards for groups later\\\
    local theIDs = {}\\\
    local allGroups = {}\\\
    if dcsCommon.containsString(theZone.menuGroup, \\\",\\\") then \\\
        allGroups = dcsCommon.splitString(theZone.menuGroup, \\\",\\\")\\\
    else \\\
        table.insert(allGroups, theZone.menuGroup)\\\
    end\\\
\\\
    for idx, gName in pairs(allGroups) do \\\
        gName = dcsCommon.trim(gName)\\\
        local theGroup = cfxMX.playerGroupByName[gName]\\\
        if theGroup then \\\
            local gID = theGroup.groupId\\\
            table.insert(theIDs, gID)\\\
            if theZone.verbose or radioMenu.verbose then \\\
                trigger.action.outText(\\\"+++menu: Player Group <\\\" .. gName .. \\\"> found: <\\\" .. gID .. \\\">\\\", 30)\\\
            end\\\
        else \\\
            trigger.action.outText(\\\"+++menu: Player Group <\\\" .. gName .. \\\"> does not exist\\\", 30)\\\
        end\\\
    end\\\
\\\
    return theIDs\\\
end\\\
\\\
function radioMenu.installMenu(theZone)\\\
--    local theGroup = 0 -- was: nil\\\
    local gID = nil \\\
    if theZone.menuGroup then \\\
        if not cfxMX then \\\
            trigger.action.outText(\\\"WARNING: radioMenu's group attribute requires the 'cfxMX' module\\\", 30)\\\
            return \\\
        end\\\
        -- access cfxMX player info for group ID\\\
        gID = radioMenu.filterPlayerIDForGroup(theZone)\\\
    elseif theZone.menuTypes then \\\
        if not cfxMX then \\\
            trigger.action.outText(\\\"WARNING: radioMenu's type attribute requires the 'cfxMX' module\\\", 30)\\\
            return \\\
        end\\\
        -- access cxfMX player infor with type match for ID\\\
        gID = radioMenu.filterPlayerIDForType(theZone)\\\
    end\\\
    \\\
    theZone.rootMenu = {}\\\
    theZone.mcdA = {}\\\
    theZone.mcdB = {}\\\
    theZone.mcdC = {}\\\
    theZone.mcdD = {}\\\
    theZone.mcdA[0] = 0\\\
    theZone.mcdB[0] = 0\\\
    theZone.mcdC[0] = 0\\\
    theZone.mcdD[0] = 0\\\
        \\\
    if theZone.menuGroup or theZone.menuTypes then \\\
        for idx, grp in pairs(gID) do \\\
            local aRoot = missionCommands.addSubMenuForGroup(grp, theZone.rootName, nil) \\\
            theZone.rootMenu[grp] = aRoot\\\
            theZone.mcdA[grp] = 0\\\
            theZone.mcdB[grp] = 0\\\
            theZone.mcdC[grp] = 0\\\
            theZone.mcdD[grp] = 0\\\
        end\\\
    elseif theZone.coalition == 0 then \\\
        theZone.rootMenu[0] = missionCommands.addSubMenu(theZone.rootName, nil) \\\
    else \\\
        theZone.rootMenu[0] = missionCommands.addSubMenuForCoalition(theZone.coalition, theZone.rootName, nil)        \\\
    end\\\
    \\\
    if cfxZones.hasProperty(theZone, \\\"itemA\\\") then \\\
        local menuA = cfxZones.getStringFromZoneProperty(theZone, \\\"itemA\\\", \\\"<no A submenu>\\\")\\\
        if theZone.menuGroup or theZone.menuTypes then\\\
            theZone.menuA = {}\\\
            for idx, grp in  pairs(gID) do  \\\
                theZone.menuA[grp] = missionCommands.addCommandForGroup(grp, menuA, theZone.rootMenu[grp], radioMenu.redirectMenuX, {theZone, \\\"A\\\", grp}) \\\
            end\\\
        elseif theZone.coalition == 0 then \\\
            theZone.menuA = missionCommands.addCommand(menuA, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, \\\"A\\\"})\\\
        else \\\
            theZone.menuA = missionCommands.addCommandForCoalition(theZone.coalition, menuA, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, \\\"A\\\"})\\\
        end \\\
    end \\\
    \\\
    if cfxZones.hasProperty(theZone, \\\"itemB\\\") then \\\
        local menuB = cfxZones.getStringFromZoneProperty(theZone, \\\"itemB\\\", \\\"<no B submenu>\\\")\\\
        if theZone.menuGroup or theZone.menuTypes then \\\
            theZone.menuB = {}\\\
            for idx, grp in  pairs(gID) do \\\
                theZone.menuB[grp] = missionCommands.addCommandForGroup(grp, menuB, theZone.rootMenu[grp], radioMenu.redirectMenuX, {theZone, \\\"B\\\", grp}) \\\
            end\\\
        elseif theZone.coalition == 0 then \\\
            theZone.menuB = missionCommands.addCommand(menuB, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, \\\"B\\\"})\\\
        else \\\
            theZone.menuB = missionCommands.addCommandForCoalition(theZone.coalition, menuB, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, \\\"B\\\"})\\\
        end\\\
    end\\\
\\\
    if cfxZones.hasProperty(theZone, \\\"itemC\\\") then \\\
        local menuC = cfxZones.getStringFromZoneProperty(theZone, \\\"itemC\\\", \\\"<no C submenu>\\\")\\\
        if theZone.menuGroup or theZone.menuTypes then \\\
            theZone.menuC = {}\\\
            for idx, grp in  pairs(gID) do \\\
                theZone.menuC[grp] = missionCommands.addCommandForGroup(grp, menuC, theZone.rootMenu[grp], radioMenu.redirectMenuX, {theZone, \\\"C\\\", grp}) \\\
            end\\\
        elseif theZone.coalition == 0 then \\\
            theZone.menuC = missionCommands.addCommand(menuC, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, \\\"C\\\"})\\\
        else \\\
            theZone.menuC = missionCommands.addCommandForCoalition(theZone.coalition, menuC, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, \\\"C\\\"})\\\
        end\\\
    end\\\
    \\\
    if cfxZones.hasProperty(theZone, \\\"itemD\\\") then \\\
        local menuD = cfxZones.getStringFromZoneProperty(theZone, \\\"itemD\\\", \\\"<no D submenu>\\\")\\\
        if theZone.menuGroup or theZone.menuTypes then \\\
            theZone.menuD = {}\\\
            for idx, grp in  pairs(gID) do \\\
                theZone.menuD[grp] = missionCommands.addCommandForGroup(grp, menuD, theZone.rootMenu[grp], radioMenu.redirectMenuX, {theZone, \\\"D\\\", grp}) \\\
            end\\\
        elseif theZone.coalition == 0 then \\\
            theZone.menuD = missionCommands.addCommand(menuD, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, \\\"D\\\"})\\\
        else \\\
            theZone.menuD = missionCommands.addCommandForCoalition(theZone.coalition, menuD, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, \\\"D\\\"})\\\
        end\\\
    end\\\
end\\\
\\\
function radioMenu.createRadioMenuWithZone(theZone)\\\
    theZone.rootName = cfxZones.getStringFromZoneProperty(theZone, \\\"radioMenu\\\", \\\"<No Name>\\\")\\\
    \\\
    theZone.coalition = cfxZones.getCoalitionFromZoneProperty(theZone, \\\"coalition\\\", 0)\\\
    -- groups / types \\\
    if cfxZones.hasProperty(theZone, \\\"group\\\") then \\\
        theZone.menuGroup = cfxZones.getStringFromZoneProperty(theZone, \\\"group\\\", \\\"<none>\\\")\\\
        theZone.menuGroup = dcsCommon.trim(theZone.menuGroup)\\\
    elseif cfxZones.hasProperty(theZone, \\\"groups\\\") then \\\
        theZone.menuGroup = cfxZones.getStringFromZoneProperty(theZone, \\\"groups\\\", \\\"<none>\\\")\\\
        theZone.menuGroup = dcsCommon.trim(theZone.menuGroup)\\\
    elseif cfxZones.hasProperty(theZone, \\\"type\\\") then \\\
        theZone.menuTypes = cfxZones.getStringFromZoneProperty(theZone, \\\"type\\\", \\\"none\\\")\\\
    elseif cfxZones.hasProperty(theZone, \\\"types\\\") then\\\
        theZone.menuTypes = cfxZones.getStringFromZoneProperty(theZone, \\\"types\\\", \\\"none\\\")\\\
    end    \\\
    \\\
    theZone.menuVisible = cfxZones.getBoolFromZoneProperty(theZone, \\\"menuVisible\\\", true)\\\
    \\\
    -- install menu if not hidden\\\
    if theZone.menuVisible then \\\
        radioMenu.installMenu(theZone)\\\
    end\\\
\\\
    -- get the triggers & methods here \\\
    theZone.radioMethod = cfxZones.getStringFromZoneProperty(theZone, \\\"method\\\", \\\"inc\\\")\\\
    if cfxZones.hasProperty(theZone, \\\"radioMethod\\\") then \\\
        theZone.radioMethod = cfxZones.getStringFromZoneProperty(theZone, \\\"radioMethod\\\", \\\"inc\\\")\\\
    end\\\
    \\\
    theZone.radioTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, \\\"radioTriggerMethod\\\", \\\"change\\\")\\\
    \\\
    theZone.itemAChosen = cfxZones.getStringFromZoneProperty(theZone, \\\"A!\\\", \\\"*<none>\\\")\\\
    theZone.cooldownA = cfxZones.getNumberFromZoneProperty(theZone, \\\"cooldownA\\\", 0)\\\
    --theZone.mcdA = 0\\\
    theZone.busyA = cfxZones.getStringFromZoneProperty(theZone, \\\"busyA\\\", \\\"Please stand by (<s> seconds)\\\")\\\
    \\\
    theZone.itemBChosen = cfxZones.getStringFromZoneProperty(theZone, \\\"B!\\\", \\\"*<none>\\\")\\\
    theZone.cooldownB = cfxZones.getNumberFromZoneProperty(theZone, \\\"cooldownB\\\", 0)\\\
    --theZone.mcdB = 0\\\
    theZone.busyB = cfxZones.getStringFromZoneProperty(theZone, \\\"busyB\\\", \\\"Please stand by (<s> seconds)\\\")\\\
    \\\
    theZone.itemCChosen = cfxZones.getStringFromZoneProperty(theZone, \\\"C!\\\", \\\"*<none>\\\")\\\
    theZone.cooldownC = cfxZones.getNumberFromZoneProperty(theZone, \\\"cooldownC\\\", 0)\\\
    --theZone.mcdC = 0\\\
    theZone.busyC = cfxZones.getStringFromZoneProperty(theZone, \\\"busyC\\\", \\\"Please stand by (<s> seconds)\\\")\\\
\\\
    theZone.itemDChosen = cfxZones.getStringFromZoneProperty(theZone, \\\"D!\\\", \\\"*<none>\\\")\\\
    theZone.cooldownD = cfxZones.getNumberFromZoneProperty(theZone, \\\"cooldownD\\\", 0)\\\
    --theZone.mcdD = 0\\\
    theZone.busyD = cfxZones.getStringFromZoneProperty(theZone, \\\"busyD\\\", \\\"Please stand by (<s> seconds)\\\")\\\
    \\\
    if cfxZones.hasProperty(theZone, \\\"removeMenu?\\\") then \\\
        theZone.removeMenu = cfxZones.getStringFromZoneProperty(theZone, \\\"removeMenu?\\\", \\\"*<none>\\\")\\\
        theZone.lastRemoveMenu = cfxZones.getFlagValue(theZone.removeMenu, theZone)\\\
    end\\\
    \\\
    if cfxZones.hasProperty(theZone, \\\"addMenu?\\\") then \\\
        theZone.addMenu = cfxZones.getStringFromZoneProperty(theZone, \\\"addMenu?\\\", \\\"*<none>\\\")\\\
        theZone.lastAddMenu = cfxZones.getFlagValue(theZone.addMenu, theZone)\\\
    end\\\
    \\\
    if radioMenu.verbose or theZone.verbose then \\\
        trigger.action.outText(\\\"+++radioMenu: new radioMenu zone <\\\".. theZone.name ..\\\">\\\", 30)\\\
    end\\\
    \\\
end\\\
\\\
--\\\
-- Output processing \\\
--\\\
function radioMenu.radioOutMessage(theMessage, theZone)\\\
    if not theZone then return end \\\
    c = theZone.coalition\\\
    if c > 0 then \\\
        trigger.action.outTextForCoalition(c, theMessage, 30)\\\
    else\\\
        trigger.action.outText(theMessage, 30)\\\
    end\\\
end\\\
\\\
function radioMenu.processHMS(msg, delta)\\\
    -- moved to dcsCommon \\\
    return dcsCommon.processHMS(msg, delta)\\\
end\\\
\\\
\\\
--\\\
-- Menu Branching\\\
--\\\
function radioMenu.redirectMenuX(args)\\\
    -- we use indirection to be able to debug code better\\\
    timer.scheduleFunction(radioMenu.doMenuX, args, timer.getTime() + 0.1)\\\
end\\\
\\\
function radioMenu.cdByGID(cd, theZone, gID)\\\
    if not gID then gID = 0 end \\\
    --if not gID then return cd[0] end \\\
    return cd[gID]\\\
end\\\
\\\
function radioMenu.setCDByGID(cd, theZone, gID, newVal)\\\
    if not gID then gID = 0 end\\\
        --theZone[cd] = newVal \\\
        -- \\\
    --end\\\
    local allCD = theZone[cd]\\\
    allCD[gID] = newVal\\\
    theZone[cd] = allCD\\\
end\\\
\\\
function radioMenu.doMenuX(args)\\\
    theZone = args[1]\\\
    theItemIndex = args[2] -- A, B , C .. ?\\\
    theGroup = args[3] -- can be nil or groupID \\\
    if not theGroup then theGroup = 0 end \\\
    \\\
    local cd = radioMenu.cdByGID(theZone.mcdA, theZone, theGroup) --theZone.mcdA\\\
    local busy = theZone.busyA \\\
    local theFlag = theZone.itemAChosen\\\
    \\\
    -- decode A..X\\\
    if theItemIndex == \\\"B\\\"then \\\
        cd = radioMenu.cdByGID(theZone.mcdB, theZone, theGroup) -- theZone.mcdB\\\
        busy = theZone.busyB \\\
        theFlag = theZone.itemBChosen\\\
    elseif theItemIndex == \\\"C\\\" then \\\
        cd = radioMenu.cdByGID(theZone.mcdC, theZone, theGroup) -- theZone.mcdC\\\
        busy = theZone.busyC \\\
        theFlag = theZone.itemCChosen\\\
    elseif theItemIndex == \\\"D\\\" then \\\
        cd = radioMenu.cdByGID(theZone.mcdD, theZone, theGroup) -- theZone.mcdD\\\
        busy = theZone.busyD \\\
        theFlag = theZone.itemDChosen\\\
    end\\\
    \\\
    -- see if we are on cooldown \\\
    local now = timer.getTime()\\\
    if now < cd then \\\
        -- we are on cooldown.\\\
        local msg = radioMenu.processHMS(busy, cd - now)\\\
        radioMenu.radioOutMessage(msg, theZone)\\\
        return \\\
    end\\\
    \\\
    -- set new cooldown -- needs own decoder A..X\\\
    if theItemIndex == \\\"A\\\" then\\\
        radioMenu.setCDByGID(\\\"mcdA\\\", theZone, theGroup, now + theZone.cooldownA)\\\
    elseif theItemIndex == \\\"B\\\" then\\\
        radioMenu.setCDByGID(\\\"mcdB\\\", theZone, theGroup, now + theZone.cooldownB)\\\
    elseif theItemIndex == \\\"C\\\" then \\\
        radioMenu.setCDByGID(\\\"mcdC\\\", theZone, theGroup, now + theZone.cooldownC)\\\
    else \\\
        radioMenu.setCDByGID(\\\"mcdC\\\", theZone, theGroup, now + theZone.cooldownC)\\\
    end\\\
    \\\
    cfxZones.pollFlag(theFlag, theZone.radioMethod, theZone)\\\
    if theZone.verbose or radioMenu.verbose then \\\
        trigger.action.outText(\\\"+++menu: banging with <\\\" .. theZone.radioMethod .. \\\"> on <\\\" .. theFlag .. \\\"> for \\\" .. theZone.name, 30)\\\
    end\\\
\\\
end\\\
\\\
--\\\
-- Update -- required when we can enable/disable a zone's menu\\\
--\\\
function radioMenu.update()\\\
    -- call me in a second to poll triggers\\\
    timer.scheduleFunction(radioMenu.update, {}, timer.getTime() + 1/radioMenu.ups)\\\
    \\\
    -- iterate all menus\\\
    for idx, theZone in pairs(radioMenu.menus) do \\\
        if theZone.removeMenu \\\
        and cfxZones.testZoneFlag(theZone, theZone.removeMenu, theZone.radioTriggerMethod, \\\"lastRemoveMenu\\\") \\\
        and theZone.menuVisible\\\
        then             \\\
            if theZone.menuGroup or theZone.menuTypes then \\\
                for gID, aRoot in pairs(theZone.rootMenu) do \\\
                    missionCommands.removeItemForGroup(gID, aRoot) \\\
                end\\\
            elseif theZone.coalition == 0 then \\\
                missionCommands.removeItem(theZone.rootMenu[0]) \\\
            else \\\
                missionCommands.removeItemForCoalition(theZone.coalition, theZone.rootMenu[0]) \\\
            end\\\
            \\\
            theZone.menuVisible = false \\\
        end\\\
        \\\
        if theZone.addMenu \\\
        and cfxZones.testZoneFlag(theZone, theZone.addMenu, theZone.radioTriggerMethod, \\\"lastAddMenu\\\") \\\
        and (not theZone.menuVisible)\\\
        then \\\
            if theZone.verbose or radioMenu.verbose then \\\
                trigger.action.outText(\\\"+++menu: adding menu from <\\\" .. theZone.name .. \\\">\\\", 30)\\\
            end \\\
            \\\
            radioMenu.installMenu(theZone) -- auto-handles coalition\\\
            theZone.menuVisible = true \\\
        end\\\
    end\\\
end\\\
\\\
\\\
--\\\
-- Config & Start\\\
--\\\
function radioMenu.readConfigZone()\\\
    local theZone = cfxZones.getZoneByName(\\\"radioMenuConfig\\\") \\\
    if not theZone then \\\
        if radioMenu.verbose then \\\
            trigger.action.outText(\\\"+++radioMenu: NO config zone!\\\", 30)\\\
        end \\\
        return \\\
    end \\\
    \\\
    radioMenu.verbose = cfxZones.getBoolFromZoneProperty(theZone, \\\"verbose\\\", false)\\\
    \\\
    if radioMenu.verbose then \\\
        trigger.action.outText(\\\"+++radioMenu: read config\\\", 30)\\\
    end \\\
end\\\
\\\
function radioMenu.start()\\\
    -- lib check\\\
    if not dcsCommon.libCheck then \\\
        trigger.action.outText(\\\"cfx radioMenu requires dcsCommon\\\", 30)\\\
        return false \\\
    end \\\
    if not dcsCommon.libCheck(\\\"cfx radioMenu\\\", radioMenu.requiredLibs) then\\\
        return false \\\
    end\\\
    \\\
    -- read config \\\
    radioMenu.readConfigZone()\\\
    \\\
    -- process radioMenu Zones \\\
    -- old style\\\
    local attrZones = cfxZones.getZonesWithAttributeNamed(\\\"radioMenu\\\")\\\
    for k, aZone in pairs(attrZones) do \\\
        radioMenu.createRadioMenuWithZone(aZone) -- process attributes\\\
        radioMenu.addRadioMenu(aZone) -- add to list\\\
    end\\\
    \\\
    -- start update \\\
    radioMenu.update()\\\
    \\\
    trigger.action.outText(\\\"cfx radioMenu v\\\" .. radioMenu.version .. \\\" started.\\\", 30)\\\
    return true \\\
end\\\
\\\
-- let's go!\\\
if not radioMenu.start() then \\\
    trigger.action.outText(\\\"cfx radioMenu aborted: missing libraries\\\", 30)\\\
    radioMenu = nil \\\
end\\\
\\\
--[[--\\\
    callbacks for the menus  \\\
    check CD/standby code for multiple groups \\\
--]]--\");a_do_script(\"cfxPlayerScoreUI = {}\\\
cfxPlayerScoreUI.version = \\\"2.1.0\\\"\\\
cfxPlayerScoreUI.verbose = false \\\
\\\
--[[-- VERSION HISTORY\\\
 - 1.0.2 - initial version \\\
 - 1.0.3 - module check\\\
 - 2.0.0 - removed cfxPlayer dependency, handles own commands\\\
 - 2.0.1 - late start capability \\\
 - 2.1.0 - soundfile cleanup \\\
         - score summary for side \\\
         - allowAll\\\
         \\\
--]]--\\\
cfxPlayerScoreUI.requiredLibs = {\\\
    \\\"dcsCommon\\\", -- this is doing score keeping\\\
    \\\"cfxZones\\\", -- zones for config \\\
    \\\"cfxPlayerScore\\\",\\\
}\\\
cfxPlayerScoreUI.soundFile = \\\"Quest Snare 3.wav\\\"\\\
cfxPlayerScoreUI.rootCommands = {} -- by unit's GROUP name, for player aircraft\\\
cfxPlayerScoreUI.allowAll = true \\\
cfxPlayerScoreUI.ranked = true \\\
\\\
-- redirect: avoid the debug environ of missionCommands\\\
function cfxPlayerScoreUI.redirectCommandX(args)\\\
    timer.scheduleFunction(cfxPlayerScoreUI.doCommandX, args, timer.getTime() + 0.1)\\\
end\\\
\\\
function cfxPlayerScoreUI.doCommandX(args)\\\
    local groupName = args[1] \\\
    local playerName = args[2]\\\
    local what = args[3] -- \\\"score\\\" or other commands\\\
    local theGroup = Group.getByName(groupName)\\\
    local gid = theGroup:getID()\\\
    local coa = theGroup:getCoalition()\\\
    \\\
    if not cfxPlayerScore.scoreTextForPlayerNamed then \\\
        trigger.action.outText(\\\"***pSGUI: CANNOT FIND PlayerScore MODULE\\\", 30)\\\
        return \\\
    end\\\
    local desc = \\\"\\\"\\\
    if what == \\\"score\\\" then \\\
        desc = cfxPlayerScore.scoreTextForPlayerNamed(playerName)\\\
    elseif what == \\\"allMySide\\\" then \\\
        desc = cfxPlayerScore.scoreSummaryForPlayersOfCoalition(coa)\\\
    elseif what == \\\"all\\\" then \\\
        desc = \\\"Score Table For All Players:\\\\n\\\" .. cfxPlayerScore.scoreTextForAllPlayers(cfxPlayerScoreUI.ranked) \\\
    else \\\
        desc = \\\"PlayerScore UI: unknown command <\\\" .. what .. \\\">\\\"\\\
    end \\\
    trigger.action.outTextForGroup(gid, desc, 30)\\\
    trigger.action.outSoundForGroup(gid, cfxPlayerScoreUI.soundFile)\\\
end\\\
\\\
--\\\
-- event handling: we are only interested in birth events\\\
-- for player aircraft \\\
--\\\
function cfxPlayerScore.processPlayerUnit(theUnit)\\\
    if not theUnit.getPlayerName then return end -- no player name, bye!\\\
    local playerName = theUnit:getPlayerName()\\\
    if not playerName then return end \\\
    \\\
    -- so now we know it's a player plane. get group name \\\
    local theGroup = theUnit:getGroup()\\\
    local groupName = theGroup:getName() \\\
    local gid = theGroup:getID()\\\
    \\\
    -- see if this group already has a score command \\\
    if cfxPlayerScoreUI.rootCommands[groupName] then \\\
        -- need re-init to store new pilot name \\\
        if cfxPlayerScoreUI.verbose then \\\
            trigger.action.outText(\\\"++pSGui: group <\\\" .. groupName .. \\\"> already has score menu, removing.\\\", 30)\\\
        end\\\
        missionCommands.removeItemForGroup(gid, cfxPlayerScoreUI.rootCommands[groupName]) \\\
        cfxPlayerScoreUI.rootCommands[groupName] = nil \\\
    end\\\
    \\\
    -- we need to install a group menu item for scores. \\\
    -- will persist through death\\\
    local commandTxt = \\\"Show Score / Kills\\\"\\\
    local theMenu = missionCommands.addSubMenuForGroup(gid, \\\"Show Score\\\", nil)\\\
    local theCommand =  missionCommands.addCommandForGroup(gid, commandTxt, theMenu, cfxPlayerScoreUI.redirectCommandX,    {groupName, playerName, \\\"score\\\"})\\\
    \\\
    commandTxt = \\\"Show my Side Score / Kills\\\"\\\
    theCommand =  missionCommands.addCommandForGroup(gid, commandTxt, theMenu, cfxPlayerScoreUI.redirectCommandX, {groupName, playerName, \\\"allMySide\\\"})\\\
\\\
    if cfxPlayerScoreUI.allowAll then \\\
        commandTxt = \\\"Show All Player Scores\\\"\\\
        theCommand =  missionCommands.addCommandForGroup(gid, commandTxt, theMenu, cfxPlayerScoreUI.redirectCommandX, {groupName, playerName, \\\"all\\\"})\\\
    end\\\
\\\
    cfxPlayerScoreUI.rootCommands[groupName] = theMenu \\\
    \\\
    if cfxPlayerScoreUI.verbose then \\\
        trigger.action.outText(\\\"++pSGui: installed player score menu for group <\\\" .. groupName .. \\\">\\\", 30)\\\
    end\\\
end\\\
\\\
function cfxPlayerScoreUI:onEvent(event)\\\
    if event.id ~= 15 then return end -- only birth \\\
    if not event.initiator then return end -- no initiator, no joy \\\
    local theUnit = event.initiator \\\
    cfxPlayerScore.processPlayerUnit(theUnit)\\\
end\\\
\\\
--\\\
-- Start \\\
--\\\
function cfxPlayerScoreUI.start()    \\\
    if not dcsCommon.libCheck(\\\"cfx Player Score UI\\\", \\\
                              cfxPlayerScoreUI.requiredLibs) \\\
    then return false end\\\
    -- install the event handler for new player planes\\\
    world.addEventHandler(cfxPlayerScoreUI)\\\
    -- process all existing players (late start)\\\
    dcsCommon.iteratePlayers(cfxPlayerScore.processPlayerUnit)\\\
    trigger.action.outText(\\\"cf/x cfxPlayerScoreUI v\\\" .. cfxPlayerScoreUI.version .. \\\" started\\\", 30)\\\
    return true \\\
end\\\
\\\
--\\\
-- GO GO GO \\\
--\\\
if not cfxPlayerScoreUI.start() then \\\
    cfxPlayerScoreUI = nil\\\
    trigger.action.outText(\\\"cf/x PlayerScore UI aborted: missing libraries\\\", 30)\\\
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"]
    ["pictureFileNameN"] = 
    {
    }, -- end of ["pictureFileNameN"]
    ["drawings"] = 
    {
        ["options"] = 
        {
            ["hiddenOnF10Map"] = 
            {
                ["Observer"] = 
                {
                    ["Neutral"] = false,
                    ["Blue"] = false,
                    ["Red"] = false,
                }, -- end of ["Observer"]
                ["Instructor"] = 
                {
                    ["Neutral"] = false,
                    ["Blue"] = false,
                    ["Red"] = false,
                }, -- end of ["Instructor"]
                ["ForwardObserver"] = 
                {
                    ["Neutral"] = false,
                    ["Blue"] = false,
                    ["Red"] = false,
                }, -- end of ["ForwardObserver"]
                ["Pilot"] = 
                {
                    ["Neutral"] = false,
                    ["Blue"] = false,
                    ["Red"] = false,
                }, -- end of ["Pilot"]
                ["Spectrator"] = 
                {
                    ["Neutral"] = false,
                    ["Blue"] = false,
                    ["Red"] = false,
                }, -- end of ["Spectrator"]
                ["ArtilleryCommander"] = 
                {
                    ["Neutral"] = false,
                    ["Blue"] = false,
                    ["Red"] = false,
                }, -- end of ["ArtilleryCommander"]
            }, -- end of ["hiddenOnF10Map"]
        }, -- end of ["options"]
        ["layers"] = 
        {
            [2] = 
            {
                ["visible"] = true,
                ["name"] = "Blue",
                ["objects"] = 
                {
                }, -- end of ["objects"]
            }, -- end of [2]
            [3] = 
            {
                ["visible"] = true,
                ["name"] = "Neutral",
                ["objects"] = 
                {
                }, -- end of ["objects"]
            }, -- end of [3]
            [1] = 
            {
                ["visible"] = true,
                ["name"] = "Red",
                ["objects"] = 
                {
                }, -- end of ["objects"]
            }, -- end of [1]
            [4] = 
            {
                ["visible"] = true,
                ["name"] = "Common",
                ["objects"] = 
                {
                    [1] = 
                    {
                        ["visible"] = true,
                        ["radius"] = 302.71043845024,
                        ["mapY"] = 631232.76451904,
                        ["primitiveType"] = "Polygon",
                        ["thickness"] = 2,
                        ["colorString"] = "0xff0000ff",
                        ["style"] = "solid",
                        ["layerName"] = "Common",
                        ["name"] = "Polygon-1",
                        ["fillColorString"] = "0xff000011",
                        ["mapX"] = -328280.50216533,
                        ["polygonMode"] = "circle",
                    }, -- end of [1]
                    [2] = 
                    {
                        ["visible"] = true,
                        ["borderThickness"] = 4,
                        ["mapY"] = 630549.69178705,
                        ["layerName"] = "Common",
                        ["colorString"] = "0xffffffff",
                        ["font"] = "DejaVuLGCSansCondensed.ttf",
                        ["mapX"] = -327870.22120899,
                        ["name"] = "Text Box-1",
                        ["angle"] = 0,
                        ["text"] = "Kill Zone",
                        ["fillColorString"] = "0xff000080",
                        ["primitiveType"] = "TextBox",
                        ["fontSize"] = 24,
                    }, -- end of [2]
                }, -- end of ["objects"]
            }, -- end of [4]
            [5] = 
            {
                ["visible"] = true,
                ["name"] = "Author",
                ["objects"] = 
                {
                }, -- end of ["objects"]
            }, -- end of [5]
        }, -- end of ["layers"]
    }, -- end of ["drawings"]
    ["groundControl"] = 
    {
        ["passwords"] = 
        {
            ["artillery_commander"] = 
            {
            }, -- end of ["artillery_commander"]
            ["instructor"] = 
            {
            }, -- end of ["instructor"]
            ["observer"] = 
            {
            }, -- end of ["observer"]
            ["forward_observer"] = 
            {
            }, -- end of ["forward_observer"]
        }, -- end of ["passwords"]
        ["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"]
        ["isPilotControlVehicles"] = false,
    }, -- end of ["groundControl"]
    ["descriptionBlueTask"] = "DictKey_descriptionBlueTask_3",
    ["weather"] = 
    {
        ["atmosphere_type"] = 0,
        ["wind"] = 
        {
            ["at8000"] = 
            {
                ["speed"] = 0,
                ["dir"] = 0,
            }, -- end of ["at8000"]
            ["atGround"] = 
            {
                ["speed"] = 0,
                ["dir"] = 0,
            }, -- end of ["atGround"]
            ["at2000"] = 
            {
                ["speed"] = 0,
                ["dir"] = 0,
            }, -- end of ["at2000"]
        }, -- end of ["wind"]
        ["enable_fog"] = false,
        ["fog"] = 
        {
            ["thickness"] = 0,
            ["visibility"] = 0,
        }, -- end of ["fog"]
        ["halo"] = 
        {
            ["preset"] = "auto",
        }, -- end of ["halo"]
        ["visibility"] = 
        {
            ["distance"] = 80000,
        }, -- end of ["visibility"]
        ["season"] = 
        {
            ["temperature"] = 20,
        }, -- end of ["season"]
        ["type_weather"] = 0,
        ["qnh"] = 760,
        ["cyclones"] = 
        {
        }, -- end of ["cyclones"]
        ["name"] = "Winter, clean sky",
        ["dust_density"] = 0,
        ["modifiedTime"] = false,
        ["groundTurbulence"] = 0,
        ["enable_dust"] = false,
        ["clouds"] = 
        {
            ["thickness"] = 200,
            ["density"] = 0,
            ["preset"] = "Preset2",
            ["base"] = 2500,
            ["iprecptns"] = 0,
        }, -- end of ["clouds"]
    }, -- end of ["weather"]
    ["theatre"] = "Caucasus",
    ["triggers"] = 
    {
        ["zones"] = 
        {
            [1] = 
            {
                ["radius"] = 304.8,
                ["zoneId"] = 165,
                ["color"] = 
                {
                    [1] = 1,
                    [2] = 1,
                    [3] = 0,
                    [4] = 0.14901960784314,
                }, -- end of ["color"]
                ["properties"] = 
                {
                    [1] = 
                    {
                        ["key"] = "verbose",
                        ["value"] = "no",
                    }, -- end of [1]
                    [2] = 
                    {
                        ["key"] = "landing",
                        ["value"] = "50",
                    }, -- end of [2]
                    [3] = 
                    {
                        ["key"] = "saveScore?",
                        ["value"] = "saveScore",
                    }, -- end of [3]
                    [4] = 
                    {
                        ["key"] = "deferred",
                        ["value"] = "yes",
                    }, -- end of [4]
                    [5] = 
                    {
                        ["key"] = "rankPlayers",
                        ["value"] = "yes",
                    }, -- end of [5]
                    [6] = 
                    {
                        ["key"] = "reportCoalition",
                        ["value"] = "yes",
                    }, -- end of [6]
                    [7] = 
                    {
                        ["key"] = "unGrief",
                        ["value"] = "no",
                    }, -- end of [7]
                }, -- end of ["properties"]
                ["hidden"] = false,
                ["y"] = 637184.71496491,
                ["x"] = -319727.11529818,
                ["name"] = "playerScoreConfig",
                ["heading"] = 0,
                ["type"] = 0,
            }, -- end of [1]
            [2] = 
            {
                ["radius"] = 1524,
                ["zoneId"] = 330,
                ["color"] = 
                {
                    [1] = 0,
                    [2] = 0,
                    [3] = 1,
                    [4] = 0.14901960784314,
                }, -- end of ["color"]
                ["properties"] = 
                {
                    [1] = 
                    {
                        ["key"] = "scoreSafe",
                        ["value"] = "",
                    }, -- end of [1]
                }, -- end of ["properties"]
                ["hidden"] = false,
                ["y"] = 635676.11470179,
                ["x"] = -317896.95774362,
                ["name"] = "Score Here",
                ["type"] = 2,
                ["heading"] = 0,
                ["verticies"] = 
                {
                    [1] = 
                    {
                        ["y"] = 634593.45935917,
                        ["x"] = -318686.67437009,
                    }, -- end of [1]
                    [2] = 
                    {
                        ["y"] = 637016.45355402,
                        ["x"] = -317871.31759341,
                    }, -- end of [2]
                    [3] = 
                    {
                        ["y"] = 636752.36000686,
                        ["x"] = -317122.62520728,
                    }, -- end of [3]
                    [4] = 
                    {
                        ["y"] = 634342.18588711,
                        ["x"] = -317907.21380371,
                    }, -- end of [4]
                }, -- end of ["verticies"]
            }, -- end of [2]
            [3] = 
            {
                ["radius"] = 304.8,
                ["zoneId"] = 825,
                ["color"] = 
                {
                    [1] = 1,
                    [2] = 0,
                    [3] = 0,
                    [4] = 0.14901960784314,
                }, -- end of ["color"]
                ["properties"] = 
                {
                    [1] = 
                    {
                        ["key"] = "killZone",
                        ["value"] = "",
                    }, -- end of [1]
                    [2] = 
                    {
                        ["key"] = "duet",
                        ["value"] = "no",
                    }, -- end of [2]
                }, -- end of ["properties"]
                ["hidden"] = false,
                ["y"] = 631231.33506439,
                ["x"] = -328281.93161998,
                ["name"] = "Kill Zone",
                ["heading"] = 0,
                ["type"] = 0,
            }, -- end of [3]
            [4] = 
            {
                ["radius"] = 304.8,
                ["zoneId"] = 990,
                ["color"] = 
                {
                    [1] = 1,
                    [2] = 1,
                    [3] = 0,
                    [4] = 0.14901960784314,
                }, -- end of ["color"]
                ["properties"] = 
                {
                    [1] = 
                    {
                        ["key"] = "radioMenu",
                        ["value"] = "ADD Score to Faction",
                    }, -- end of [1]
                    [2] = 
                    {
                        ["key"] = "itemA",
                        ["value"] = "Score for Blue",
                    }, -- end of [2]
                    [3] = 
                    {
                        ["key"] = "A!",
                        ["value"] = "blueOne",
                    }, -- end of [3]
                    [4] = 
                    {
                        ["key"] = "itemB",
                        ["value"] = "RED scores!",
                    }, -- end of [4]
                    [5] = 
                    {
                        ["key"] = "B!",
                        ["value"] = "redOne",
                    }, -- end of [5]
                    [6] = 
                    {
                        ["key"] = "itemC",
                        ["value"] = "Try Force Error",
                    }, -- end of [6]
                    [7] = 
                    {
                        ["key"] = "C!",
                        ["value"] = "noNum",
                    }, -- end of [7]
                }, -- end of ["properties"]
                ["hidden"] = false,
                ["y"] = 635150.47120284,
                ["x"] = -320529.30753493,
                ["name"] = "Score Menu",
                ["heading"] = 0,
                ["type"] = 0,
            }, -- end of [4]
            [5] = 
            {
                ["radius"] = 304.8,
                ["zoneId"] = 991,
                ["color"] = 
                {
                    [1] = 1,
                    [2] = 0,
                    [3] = 1,
                    [4] = 0.14901960784314,
                }, -- end of ["color"]
                ["properties"] = 
                {
                    [1] = 
                    {
                        ["key"] = "blueOne",
                        ["value"] = "500",
                    }, -- end of [1]
                    [2] = 
                    {
                        ["key"] = "noNum",
                        ["value"] = "lala",
                    }, -- end of [2]
                }, -- end of ["properties"]
                ["hidden"] = false,
                ["y"] = 636832.20302313,
                ["x"] = -320816.78305977,
                ["name"] = "blueScoreFlags",
                ["heading"] = 0,
                ["type"] = 0,
            }, -- end of [5]
            [6] = 
            {
                ["radius"] = 304.8,
                ["zoneId"] = 1156,
                ["color"] = 
                {
                    [1] = 1,
                    [2] = 0,
                    [3] = 1,
                    [4] = 0.14901960784314,
                }, -- end of ["color"]
                ["properties"] = 
                {
                    [1] = 
                    {
                        ["key"] = "redOne",
                        ["value"] = "2000",
                    }, -- end of [1]
                }, -- end of ["properties"]
                ["hidden"] = false,
                ["y"] = 636760.33414192,
                ["x"] = -321679.20963428,
                ["name"] = "redScoreFlags",
                ["heading"] = 0,
                ["type"] = 0,
            }, -- end of [6]
        }, -- end of ["zones"]
    }, -- end of ["triggers"]
    ["map"] = 
    {
        ["centerY"] = 638147.82003204,
        ["zoom"] = 53739.477180397,
        ["centerX"] = -320887.84076527,
    }, -- 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] = 90,
            [12] = 29,
            [13] = 62,
            [14] = 30,
            [15] = 78,
            [16] = 87,
            [17] = 31,
            [18] = 61,
            [19] = 32,
            [20] = 33,
            [21] = 60,
            [22] = 17,
            [23] = 35,
            [24] = 69,
            [25] = 36,
            [26] = 59,
            [27] = 71,
            [28] = 79,
            [29] = 58,
            [30] = 57,
            [31] = 56,
            [32] = 55,
            [33] = 88,
            [34] = 73,
            [35] = 39,
            [36] = 89,
            [37] = 54,
            [38] = 77,
            [39] = 72,
            [40] = 41,
            [41] = 42,
            [42] = 44,
            [43] = 85,
            [44] = 75,
            [45] = 53,
            [46] = 22,
            [47] = 52,
            [48] = 66,
            [49] = 51,
            [50] = 74,
            [51] = 82,
            [52] = 7,
            [53] = 68,
            [54] = 50,
            [55] = 49,
            [56] = 48,
            [57] = 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"]
    ["goals"] = 
    {
    }, -- end of ["goals"]
    ["descriptionNeutralsTask"] = "DictKey_descriptionNeutralsTask_4",
    ["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] = 
                {
                    ["helicopter"] = 
                    {
                        ["group"] = 
                        {
                            [1] = 
                            {
                                ["modulation"] = 0,
                                ["tasks"] = 
                                {
                                }, -- end of ["tasks"]
                                ["radioSet"] = false,
                                ["task"] = "Transport",
                                ["uncontrolled"] = false,
                                ["route"] = 
                                {
                                    ["points"] = 
                                    {
                                        [1] = 
                                        {
                                            ["alt"] = 500,
                                            ["action"] = "From Ground Area Hot",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 46.25,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                    }, -- end of ["tasks"]
                                                }, -- end of ["params"]
                                            }, -- end of ["task"]
                                            ["type"] = "TakeOffGroundHot",
                                            ["ETA"] = 0,
                                            ["ETA_locked"] = true,
                                            ["y"] = 635196.25897256,
                                            ["x"] = -318328.20147567,
                                            ["formation_template"] = "",
                                            ["speed_locked"] = true,
                                        }, -- end of [1]
                                    }, -- end of ["points"]
                                }, -- end of ["route"]
                                ["groupId"] = 2,
                                ["hidden"] = false,
                                ["units"] = 
                                {
                                    [1] = 
                                    {
                                        ["alt"] = 500,
                                        ["hardpoint_racks"] = true,
                                        ["alt_type"] = "BARO",
                                        ["livery_id"] = "army 4abn_a1_1969",
                                        ["skill"] = "Client",
                                        ["ropeLength"] = 15,
                                        ["speed"] = 46.25,
                                        ["AddPropAircraft"] = 
                                        {
                                            ["SoloFlight"] = false,
                                            ["ExhaustScreen"] = true,
                                            ["GunnersAISkill"] = 90,
                                            ["NetCrewControlPriority"] = 0,
                                            ["EngineResource"] = 90,
                                        }, -- end of ["AddPropAircraft"]
                                        ["type"] = "UH-1H",
                                        ["Radio"] = 
                                        {
                                            [1] = 
                                            {
                                                ["modulations"] = 
                                                {
                                                }, -- end of ["modulations"]
                                                ["channels"] = 
                                                {
                                                    [1] = 251,
                                                    [2] = 264,
                                                    [4] = 256,
                                                    [8] = 257,
                                                    [16] = 261,
                                                    [17] = 267,
                                                    [9] = 255,
                                                    [18] = 251,
                                                    [5] = 254,
                                                    [10] = 262,
                                                    [20] = 266,
                                                    [11] = 259,
                                                    [3] = 265,
                                                    [6] = 250,
                                                    [12] = 268,
                                                    [13] = 269,
                                                    [7] = 270,
                                                    [14] = 260,
                                                    [15] = 263,
                                                    [19] = 253,
                                                }, -- end of ["channels"]
                                            }, -- end of [1]
                                        }, -- end of ["Radio"]
                                        ["unitId"] = 12,
                                        ["psi"] = -6.0039326268605,
                                        ["y"] = 635196.25897256,
                                        ["x"] = -318328.20147567,
                                        ["name"] = "Hooi One",
                                        ["payload"] = 
                                        {
                                            ["pylons"] = 
                                            {
                                            }, -- end of ["pylons"]
                                            ["fuel"] = "631",
                                            ["flare"] = 60,
                                            ["chaff"] = 0,
                                            ["gun"] = 100,
                                        }, -- end of ["payload"]
                                        ["heading"] = 6.0039326268605,
                                        ["callsign"] = 
                                        {
                                            [1] = 1,
                                            [2] = 1,
                                            ["name"] = "Enfield11",
                                            [3] = 1,
                                        }, -- end of ["callsign"]
                                        ["onboard_num"] = "010",
                                    }, -- end of [1]
                                }, -- end of ["units"]
                                ["y"] = 635196.25897256,
                                ["x"] = -318328.20147567,
                                ["name"] = "Hooi Kobu",
                                ["communication"] = true,
                                ["start_time"] = 0,
                                ["uncontrollable"] = false,
                                ["frequency"] = 251,
                            }, -- end of [1]
                            [2] = 
                            {
                                ["modulation"] = 0,
                                ["tasks"] = 
                                {
                                }, -- end of ["tasks"]
                                ["radioSet"] = false,
                                ["task"] = "Transport",
                                ["uncontrolled"] = false,
                                ["route"] = 
                                {
                                    ["points"] = 
                                    {
                                        [1] = 
                                        {
                                            ["alt"] = 500,
                                            ["action"] = "From Ground Area Hot",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 46.25,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                    }, -- end of ["tasks"]
                                                }, -- end of ["params"]
                                            }, -- end of ["task"]
                                            ["type"] = "TakeOffGroundHot",
                                            ["ETA"] = 0,
                                            ["ETA_locked"] = true,
                                            ["y"] = 646617.37684972,
                                            ["x"] = -281489.01908404,
                                            ["formation_template"] = "",
                                            ["speed_locked"] = true,
                                        }, -- end of [1]
                                    }, -- end of ["points"]
                                }, -- end of ["route"]
                                ["groupId"] = 7,
                                ["hidden"] = false,
                                ["units"] = 
                                {
                                    [1] = 
                                    {
                                        ["alt"] = 500,
                                        ["hardpoint_racks"] = true,
                                        ["alt_type"] = "BARO",
                                        ["livery_id"] = "army 4abn_a1_1969",
                                        ["skill"] = "Client",
                                        ["ropeLength"] = 15,
                                        ["speed"] = 46.25,
                                        ["AddPropAircraft"] = 
                                        {
                                            ["SoloFlight"] = false,
                                            ["ExhaustScreen"] = true,
                                            ["GunnersAISkill"] = 90,
                                            ["NetCrewControlPriority"] = 0,
                                            ["EngineResource"] = 90,
                                        }, -- end of ["AddPropAircraft"]
                                        ["type"] = "UH-1H",
                                        ["Radio"] = 
                                        {
                                            [1] = 
                                            {
                                                ["modulations"] = 
                                                {
                                                }, -- end of ["modulations"]
                                                ["channels"] = 
                                                {
                                                    [1] = 251,
                                                    [2] = 264,
                                                    [4] = 256,
                                                    [8] = 257,
                                                    [16] = 261,
                                                    [17] = 267,
                                                    [9] = 255,
                                                    [18] = 251,
                                                    [5] = 254,
                                                    [10] = 262,
                                                    [20] = 266,
                                                    [11] = 259,
                                                    [3] = 265,
                                                    [6] = 250,
                                                    [12] = 268,
                                                    [13] = 269,
                                                    [7] = 270,
                                                    [14] = 260,
                                                    [15] = 263,
                                                    [19] = 253,
                                                }, -- end of ["channels"]
                                            }, -- end of [1]
                                        }, -- end of ["Radio"]
                                        ["unitId"] = 21,
                                        ["psi"] = -6.0039326268605,
                                        ["y"] = 646617.37684972,
                                        ["x"] = -281489.01908404,
                                        ["name"] = "Hooi Senaki",
                                        ["payload"] = 
                                        {
                                            ["pylons"] = 
                                            {
                                            }, -- end of ["pylons"]
                                            ["fuel"] = "631",
                                            ["flare"] = 60,
                                            ["chaff"] = 0,
                                            ["gun"] = 100,
                                        }, -- end of ["payload"]
                                        ["heading"] = 6.0039326268605,
                                        ["callsign"] = 
                                        {
                                            [1] = 5,
                                            [2] = 1,
                                            ["name"] = "Dodge11",
                                            [3] = 1,
                                        }, -- end of ["callsign"]
                                        ["onboard_num"] = "014",
                                    }, -- end of [1]
                                }, -- end of ["units"]
                                ["y"] = 646617.37684972,
                                ["x"] = -281489.01908404,
                                ["name"] = "Hooi Senaki",
                                ["communication"] = true,
                                ["start_time"] = 0,
                                ["uncontrollable"] = false,
                                ["frequency"] = 251,
                            }, -- end of [2]
                        }, -- end of ["group"]
                    }, -- end of ["helicopter"]
                    ["name"] = "USA",
                    ["id"] = 2,
                    ["plane"] = 
                    {
                        ["group"] = 
                        {
                            [1] = 
                            {
                                ["modulation"] = 0,
                                ["tasks"] = 
                                {
                                }, -- end of ["tasks"]
                                ["radioSet"] = false,
                                ["task"] = "Nothing",
                                ["uncontrolled"] = false,
                                ["taskSelected"] = true,
                                ["route"] = 
                                {
                                    ["points"] = 
                                    {
                                        [1] = 
                                        {
                                            ["alt"] = 457.2,
                                            ["action"] = "Turning Point",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 92.5,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                    }, -- end of ["tasks"]
                                                }, -- end of ["params"]
                                            }, -- end of ["task"]
                                            ["type"] = "Turning Point",
                                            ["ETA"] = 0,
                                            ["ETA_locked"] = true,
                                            ["y"] = 629741.69027553,
                                            ["x"] = -321696.19957317,
                                            ["formation_template"] = "",
                                            ["speed_locked"] = true,
                                        }, -- end of [1]
                                        [2] = 
                                        {
                                            ["alt"] = 10.0584,
                                            ["action"] = "Turning Point",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 77.083333333333,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                    }, -- end of ["tasks"]
                                                }, -- end of ["params"]
                                            }, -- end of ["task"]
                                            ["type"] = "Turning Point",
                                            ["ETA"] = 87.663946396461,
                                            ["ETA_locked"] = false,
                                            ["y"] = 631221.6325066,
                                            ["x"] = -328289.57658382,
                                            ["formation_template"] = "",
                                            ["speed_locked"] = true,
                                        }, -- end of [2]
                                    }, -- end of ["points"]
                                }, -- end of ["route"]
                                ["groupId"] = 3,
                                ["hidden"] = false,
                                ["units"] = 
                                {
                                    [1] = 
                                    {
                                        ["alt"] = 457.2,
                                        ["hardpoint_racks"] = true,
                                        ["alt_type"] = "BARO",
                                        ["livery_id"] = "104th fs maryland ang, baltimore (md)",
                                        ["skill"] = "Client",
                                        ["speed"] = 92.5,
                                        ["AddPropAircraft"] = 
                                        {
                                        }, -- end of ["AddPropAircraft"]
                                        ["type"] = "A-10A",
                                        ["unitId"] = 13,
                                        ["psi"] = -2.9207932861073,
                                        ["y"] = 629741.69027553,
                                        ["x"] = -321696.19957317,
                                        ["name"] = "Shooter 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"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
                                                }, -- end of [4]
                                                [5] = 
                                                {
                                                    ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
                                                }, -- end of [5]
                                                [6] = 
                                                {
                                                    ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
                                                }, -- end of [6]
                                                [7] = 
                                                {
                                                    ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
                                                }, -- end of [7]
                                                [8] = 
                                                {
                                                    ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
                                                }, -- 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"] = 2414,
                                            ["flare"] = 120,
                                            ["ammo_type"] = 1,
                                            ["chaff"] = 240,
                                            ["gun"] = 100,
                                        }, -- end of ["payload"]
                                        ["heading"] = 2.9207932861073,
                                        ["callsign"] = 
                                        {
                                            [1] = 2,
                                            [2] = 1,
                                            ["name"] = "Springfield11",
                                            [3] = 1,
                                        }, -- end of ["callsign"]
                                        ["onboard_num"] = "011",
                                    }, -- end of [1]
                                }, -- end of ["units"]
                                ["y"] = 629741.69027553,
                                ["x"] = -321696.19957317,
                                ["name"] = "Shooter",
                                ["communication"] = true,
                                ["start_time"] = 0,
                                ["uncontrollable"] = false,
                                ["frequency"] = 124,
                            }, -- end of [1]
                            [2] = 
                            {
                                ["modulation"] = 0,
                                ["tasks"] = 
                                {
                                }, -- end of ["tasks"]
                                ["radioSet"] = false,
                                ["task"] = "CAS",
                                ["uncontrolled"] = false,
                                ["route"] = 
                                {
                                    ["points"] = 
                                    {
                                        [1] = 
                                        {
                                            ["alt"] = 457.2,
                                            ["action"] = "Turning Point",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 77.083333333333,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                        [1] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["key"] = "CAS",
                                                            ["id"] = "EngageTargets",
                                                            ["number"] = 1,
                                                            ["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] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 2,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["value"] = 2,
                                                                        ["name"] = 1,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [2]
                                                        [3] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 3,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["value"] = 1,
                                                                        ["name"] = 3,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [3]
                                                        [4] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 4,
                                                            ["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] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 5,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["value"] = true,
                                                                        ["name"] = 15,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [5]
                                                        [6] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 6,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["targetTypes"] = 
                                                                        {
                                                                        }, -- end of ["targetTypes"]
                                                                        ["name"] = 21,
                                                                        ["value"] = "none;",
                                                                        ["noTargetTypes"] = 
                                                                        {
                                                                            [1] = "Fighters",
                                                                            [2] = "Multirole fighters",
                                                                            [3] = "Bombers",
                                                                            [4] = "Helicopters",
                                                                            [5] = "UAVs",
                                                                            [6] = "Infantry",
                                                                            [7] = "Fortifications",
                                                                            [8] = "Tanks",
                                                                            [9] = "IFV",
                                                                            [10] = "APC",
                                                                            [11] = "Artillery",
                                                                            [12] = "Unarmed vehicles",
                                                                            [13] = "AAA",
                                                                            [14] = "SR SAM",
                                                                            [15] = "MR SAM",
                                                                            [16] = "LR SAM",
                                                                            [17] = "Aircraft Carriers",
                                                                            [18] = "Cruisers",
                                                                            [19] = "Destroyers",
                                                                            [20] = "Frigates",
                                                                            [21] = "Corvettes",
                                                                            [22] = "Light armed ships",
                                                                            [23] = "Unarmed ships",
                                                                            [24] = "Submarines",
                                                                            [25] = "Cruise missiles",
                                                                            [26] = "Antiship Missiles",
                                                                            [27] = "AA Missiles",
                                                                            [28] = "AG Missiles",
                                                                            [29] = "SA Missiles",
                                                                        }, -- end of ["noTargetTypes"]
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [6]
                                                        [7] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 7,
                                                            ["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"] = 641575.12847305,
                                            ["x"] = -281312.63685753,
                                            ["formation_template"] = "",
                                            ["speed_locked"] = true,
                                        }, -- end of [1]
                                        [2] = 
                                        {
                                            ["alt"] = 13,
                                            ["action"] = "Landing",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 138.88888888889,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                    }, -- end of ["tasks"]
                                                }, -- end of ["params"]
                                            }, -- end of ["task"]
                                            ["type"] = "Land",
                                            ["ETA"] = 27.915328003958,
                                            ["ETA_locked"] = false,
                                            ["y"] = 647279.46875,
                                            ["x"] = -281782.46875,
                                            ["formation_template"] = "",
                                            ["airdromeId"] = 23,
                                            ["speed_locked"] = true,
                                        }, -- end of [2]
                                    }, -- end of ["points"]
                                }, -- end of ["route"]
                                ["groupId"] = 5,
                                ["hidden"] = false,
                                ["units"] = 
                                {
                                    [1] = 
                                    {
                                        ["alt"] = 457.2,
                                        ["alt_type"] = "BARO",
                                        ["livery_id"] = "104th fs maryland ang, baltimore (md)",
                                        ["skill"] = "Client",
                                        ["speed"] = 77.083333333333,
                                        ["AddPropAircraft"] = 
                                        {
                                        }, -- end of ["AddPropAircraft"]
                                        ["type"] = "A-10A",
                                        ["unitId"] = 15,
                                        ["psi"] = -1.6529747655486,
                                        ["y"] = 641575.12847305,
                                        ["x"] = -281312.63685753,
                                        ["name"] = "Lander Senaki One",
                                        ["payload"] = 
                                        {
                                            ["pylons"] = 
                                            {
                                            }, -- end of ["pylons"]
                                            ["fuel"] = 5029,
                                            ["flare"] = 120,
                                            ["ammo_type"] = 1,
                                            ["chaff"] = 240,
                                            ["gun"] = 100,
                                        }, -- end of ["payload"]
                                        ["heading"] = 1.6529747655486,
                                        ["callsign"] = 
                                        {
                                            [1] = 4,
                                            [2] = 1,
                                            ["name"] = "Colt11",
                                            [3] = 1,
                                        }, -- end of ["callsign"]
                                        ["onboard_num"] = "013",
                                    }, -- end of [1]
                                }, -- end of ["units"]
                                ["y"] = 641575.12847305,
                                ["x"] = -281312.63685753,
                                ["name"] = "Lander Senaki",
                                ["communication"] = true,
                                ["start_time"] = 0,
                                ["uncontrollable"] = false,
                                ["frequency"] = 124,
                            }, -- end of [2]
                            [3] = 
                            {
                                ["modulation"] = 0,
                                ["tasks"] = 
                                {
                                }, -- end of ["tasks"]
                                ["radioSet"] = false,
                                ["task"] = "CAS",
                                ["uncontrolled"] = false,
                                ["route"] = 
                                {
                                    ["points"] = 
                                    {
                                        [1] = 
                                        {
                                            ["alt"] = 457.2,
                                            ["action"] = "Turning Point",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 77.083333333333,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                        [1] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["key"] = "CAS",
                                                            ["id"] = "EngageTargets",
                                                            ["number"] = 1,
                                                            ["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] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 2,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["value"] = 2,
                                                                        ["name"] = 1,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [2]
                                                        [3] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 3,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["value"] = 1,
                                                                        ["name"] = 3,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [3]
                                                        [4] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 4,
                                                            ["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] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 5,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["value"] = true,
                                                                        ["name"] = 15,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [5]
                                                        [6] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 6,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["targetTypes"] = 
                                                                        {
                                                                        }, -- end of ["targetTypes"]
                                                                        ["name"] = 21,
                                                                        ["value"] = "none;",
                                                                        ["noTargetTypes"] = 
                                                                        {
                                                                            [1] = "Fighters",
                                                                            [2] = "Multirole fighters",
                                                                            [3] = "Bombers",
                                                                            [4] = "Helicopters",
                                                                            [5] = "UAVs",
                                                                            [6] = "Infantry",
                                                                            [7] = "Fortifications",
                                                                            [8] = "Tanks",
                                                                            [9] = "IFV",
                                                                            [10] = "APC",
                                                                            [11] = "Artillery",
                                                                            [12] = "Unarmed vehicles",
                                                                            [13] = "AAA",
                                                                            [14] = "SR SAM",
                                                                            [15] = "MR SAM",
                                                                            [16] = "LR SAM",
                                                                            [17] = "Aircraft Carriers",
                                                                            [18] = "Cruisers",
                                                                            [19] = "Destroyers",
                                                                            [20] = "Frigates",
                                                                            [21] = "Corvettes",
                                                                            [22] = "Light armed ships",
                                                                            [23] = "Unarmed ships",
                                                                            [24] = "Submarines",
                                                                            [25] = "Cruise missiles",
                                                                            [26] = "Antiship Missiles",
                                                                            [27] = "AA Missiles",
                                                                            [28] = "AG Missiles",
                                                                            [29] = "SA Missiles",
                                                                        }, -- end of ["noTargetTypes"]
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [6]
                                                        [7] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 7,
                                                            ["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"] = 630265.00768008,
                                            ["x"] = -319915.88013014,
                                            ["formation_template"] = "",
                                            ["speed_locked"] = true,
                                        }, -- end of [1]
                                        [2] = 
                                        {
                                            ["alt"] = 18,
                                            ["action"] = "Landing",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 138.88888888889,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                    }, -- end of ["tasks"]
                                                }, -- end of ["params"]
                                            }, -- end of ["task"]
                                            ["type"] = "Land",
                                            ["ETA"] = 27.915328003958,
                                            ["ETA_locked"] = false,
                                            ["y"] = 635632.96875,
                                            ["x"] = -317962.296875,
                                            ["formation_template"] = "",
                                            ["airdromeId"] = 24,
                                            ["speed_locked"] = true,
                                        }, -- end of [2]
                                    }, -- end of ["points"]
                                }, -- end of ["route"]
                                ["groupId"] = 6,
                                ["hidden"] = false,
                                ["units"] = 
                                {
                                    [1] = 
                                    {
                                        ["alt"] = 457.2,
                                        ["alt_type"] = "BARO",
                                        ["livery_id"] = "104th fs maryland ang, baltimore (md)",
                                        ["skill"] = "Client",
                                        ["speed"] = 77.083333333333,
                                        ["AddPropAircraft"] = 
                                        {
                                        }, -- end of ["AddPropAircraft"]
                                        ["type"] = "A-10A",
                                        ["unitId"] = 20,
                                        ["psi"] = -1.2217625199524,
                                        ["y"] = 630265.00768008,
                                        ["x"] = -319915.88013014,
                                        ["name"] = "Lander Kobuleti",
                                        ["payload"] = 
                                        {
                                            ["pylons"] = 
                                            {
                                            }, -- end of ["pylons"]
                                            ["fuel"] = 5029,
                                            ["flare"] = 120,
                                            ["ammo_type"] = 1,
                                            ["chaff"] = 240,
                                            ["gun"] = 100,
                                        }, -- end of ["payload"]
                                        ["heading"] = 1.2217625199524,
                                        ["callsign"] = 
                                        {
                                            [1] = 3,
                                            [2] = 1,
                                            ["name"] = "Uzi11",
                                            [3] = 1,
                                        }, -- end of ["callsign"]
                                        ["onboard_num"] = "012",
                                    }, -- end of [1]
                                }, -- end of ["units"]
                                ["y"] = 630265.00768008,
                                ["x"] = -319915.88013014,
                                ["name"] = "Lander Kobuleti",
                                ["communication"] = true,
                                ["start_time"] = 0,
                                ["uncontrollable"] = false,
                                ["frequency"] = 124,
                            }, -- end of [3]
                            [4] = 
                            {
                                ["modulation"] = 0,
                                ["tasks"] = 
                                {
                                }, -- end of ["tasks"]
                                ["radioSet"] = false,
                                ["task"] = "CAS",
                                ["uncontrolled"] = false,
                                ["route"] = 
                                {
                                    ["points"] = 
                                    {
                                        [1] = 
                                        {
                                            ["alt"] = 457.2,
                                            ["action"] = "Turning Point",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 77.083333333333,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                        [1] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["key"] = "CAS",
                                                            ["id"] = "EngageTargets",
                                                            ["number"] = 1,
                                                            ["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] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 2,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["value"] = 2,
                                                                        ["name"] = 1,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [2]
                                                        [3] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 3,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["value"] = 1,
                                                                        ["name"] = 3,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [3]
                                                        [4] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 4,
                                                            ["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] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 5,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["value"] = true,
                                                                        ["name"] = 15,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [5]
                                                        [6] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 6,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["targetTypes"] = 
                                                                        {
                                                                        }, -- end of ["targetTypes"]
                                                                        ["name"] = 21,
                                                                        ["value"] = "none;",
                                                                        ["noTargetTypes"] = 
                                                                        {
                                                                            [1] = "Fighters",
                                                                            [2] = "Multirole fighters",
                                                                            [3] = "Bombers",
                                                                            [4] = "Helicopters",
                                                                            [5] = "UAVs",
                                                                            [6] = "Infantry",
                                                                            [7] = "Fortifications",
                                                                            [8] = "Tanks",
                                                                            [9] = "IFV",
                                                                            [10] = "APC",
                                                                            [11] = "Artillery",
                                                                            [12] = "Unarmed vehicles",
                                                                            [13] = "AAA",
                                                                            [14] = "SR SAM",
                                                                            [15] = "MR SAM",
                                                                            [16] = "LR SAM",
                                                                            [17] = "Aircraft Carriers",
                                                                            [18] = "Cruisers",
                                                                            [19] = "Destroyers",
                                                                            [20] = "Frigates",
                                                                            [21] = "Corvettes",
                                                                            [22] = "Light armed ships",
                                                                            [23] = "Unarmed ships",
                                                                            [24] = "Submarines",
                                                                            [25] = "Cruise missiles",
                                                                            [26] = "Antiship Missiles",
                                                                            [27] = "AA Missiles",
                                                                            [28] = "AG Missiles",
                                                                            [29] = "SA Missiles",
                                                                        }, -- end of ["noTargetTypes"]
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [6]
                                                        [7] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 7,
                                                            ["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"] = 629868.02813479,
                                            ["x"] = -320054.36136687,
                                            ["formation_template"] = "",
                                            ["speed_locked"] = true,
                                        }, -- end of [1]
                                        [2] = 
                                        {
                                            ["alt"] = 18,
                                            ["action"] = "Landing",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 138.88888888889,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                    }, -- end of ["tasks"]
                                                }, -- end of ["params"]
                                            }, -- end of ["task"]
                                            ["type"] = "Land",
                                            ["ETA"] = 27.915328003958,
                                            ["ETA_locked"] = false,
                                            ["y"] = 635632.96875,
                                            ["x"] = -317962.296875,
                                            ["formation_template"] = "",
                                            ["airdromeId"] = 24,
                                            ["speed_locked"] = true,
                                        }, -- end of [2]
                                    }, -- end of ["points"]
                                }, -- end of ["route"]
                                ["groupId"] = 9,
                                ["hidden"] = false,
                                ["units"] = 
                                {
                                    [1] = 
                                    {
                                        ["alt"] = 457.2,
                                        ["alt_type"] = "BARO",
                                        ["livery_id"] = "104th fs maryland ang, baltimore (md)",
                                        ["skill"] = "Client",
                                        ["speed"] = 77.083333333333,
                                        ["AddPropAircraft"] = 
                                        {
                                        }, -- end of ["AddPropAircraft"]
                                        ["type"] = "A-10A",
                                        ["unitId"] = 23,
                                        ["psi"] = -1.2226808168881,
                                        ["y"] = 629868.02813479,
                                        ["x"] = -320054.36136687,
                                        ["name"] = "Lander Kobuleti Sue",
                                        ["payload"] = 
                                        {
                                            ["pylons"] = 
                                            {
                                            }, -- end of ["pylons"]
                                            ["fuel"] = 5029,
                                            ["flare"] = 120,
                                            ["ammo_type"] = 1,
                                            ["chaff"] = 240,
                                            ["gun"] = 100,
                                        }, -- end of ["payload"]
                                        ["heading"] = 1.2226808168881,
                                        ["callsign"] = 
                                        {
                                            [1] = 6,
                                            [2] = 1,
                                            ["name"] = "Ford11",
                                            [3] = 1,
                                        }, -- end of ["callsign"]
                                        ["onboard_num"] = "015",
                                    }, -- end of [1]
                                }, -- end of ["units"]
                                ["y"] = 629868.02813479,
                                ["x"] = -320054.36136687,
                                ["name"] = "Lander Kobuleti Sue",
                                ["communication"] = true,
                                ["start_time"] = 0,
                                ["uncontrollable"] = false,
                                ["frequency"] = 124,
                            }, -- end of [4]
                        }, -- end of ["group"]
                    }, -- end of ["plane"]
                }, -- end of [1]
                [2] = 
                {
                    ["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"] = 457.2,
                                            ["action"] = "Turning Point",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 179.86111111111,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                    }, -- end of ["tasks"]
                                                }, -- end of ["params"]
                                            }, -- end of ["task"]
                                            ["type"] = "Turning Point",
                                            ["ETA"] = 0,
                                            ["ETA_locked"] = true,
                                            ["y"] = 629572.60149643,
                                            ["x"] = -321725.36829008,
                                            ["formation_template"] = "",
                                            ["speed_locked"] = true,
                                        }, -- end of [1]
                                        [2] = 
                                        {
                                            ["alt"] = 39.741101469302,
                                            ["action"] = "Turning Point",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 179.86111111111,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                    }, -- end of ["tasks"]
                                                }, -- end of ["params"]
                                            }, -- end of ["task"]
                                            ["type"] = "Turning Point",
                                            ["ETA"] = 87.663946396461,
                                            ["ETA_locked"] = false,
                                            ["y"] = 631052.5437275,
                                            ["x"] = -328318.74530072,
                                            ["formation_template"] = "",
                                            ["speed_locked"] = true,
                                        }, -- end of [2]
                                    }, -- end of ["points"]
                                }, -- end of ["route"]
                                ["groupId"] = 8,
                                ["hidden"] = false,
                                ["units"] = 
                                {
                                    [1] = 
                                    {
                                        ["alt"] = 457.2,
                                        ["hardpoint_racks"] = true,
                                        ["alt_type"] = "BARO",
                                        ["livery_id"] = "Algerian AF Desert KU-03",
                                        ["skill"] = "Client",
                                        ["speed"] = 179.86111111111,
                                        ["type"] = "Su-25T",
                                        ["unitId"] = 22,
                                        ["psi"] = -2.920793286107,
                                        ["y"] = 629572.60149643,
                                        ["x"] = -321725.36829008,
                                        ["name"] = "Shooter Sue",
                                        ["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"] = 2.920793286107,
                                        ["callsign"] = 
                                        {
                                            [1] = 6,
                                            [2] = 1,
                                            ["name"] = "Ford11",
                                            [3] = 1,
                                        }, -- end of ["callsign"]
                                        ["onboard_num"] = "015",
                                    }, -- end of [1]
                                }, -- end of ["units"]
                                ["y"] = 629572.60149643,
                                ["x"] = -321725.36829008,
                                ["name"] = "Shooter Su25",
                                ["communication"] = true,
                                ["start_time"] = 0,
                                ["uncontrollable"] = false,
                                ["frequency"] = 124,
                            }, -- end of [1]
                            [2] = 
                            {
                                ["modulation"] = 0,
                                ["tasks"] = 
                                {
                                }, -- end of ["tasks"]
                                ["radioSet"] = false,
                                ["task"] = "CAS",
                                ["uncontrolled"] = false,
                                ["route"] = 
                                {
                                    ["points"] = 
                                    {
                                        [1] = 
                                        {
                                            ["alt"] = 457.2,
                                            ["action"] = "Turning Point",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 179.86111111111,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                        [1] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["key"] = "CAS",
                                                            ["id"] = "EngageTargets",
                                                            ["number"] = 1,
                                                            ["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] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 2,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["value"] = 2,
                                                                        ["name"] = 1,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [2]
                                                        [3] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 3,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["value"] = 1,
                                                                        ["name"] = 3,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [3]
                                                        [4] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 4,
                                                            ["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] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 5,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["value"] = true,
                                                                        ["name"] = 15,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [5]
                                                        [6] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 6,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["targetTypes"] = 
                                                                        {
                                                                        }, -- end of ["targetTypes"]
                                                                        ["name"] = 21,
                                                                        ["value"] = "none;",
                                                                        ["noTargetTypes"] = 
                                                                        {
                                                                            [1] = "Fighters",
                                                                            [2] = "Multirole fighters",
                                                                            [3] = "Bombers",
                                                                            [4] = "Helicopters",
                                                                            [5] = "UAVs",
                                                                            [6] = "Infantry",
                                                                            [7] = "Fortifications",
                                                                            [8] = "Tanks",
                                                                            [9] = "IFV",
                                                                            [10] = "APC",
                                                                            [11] = "Artillery",
                                                                            [12] = "Unarmed vehicles",
                                                                            [13] = "AAA",
                                                                            [14] = "SR SAM",
                                                                            [15] = "MR SAM",
                                                                            [16] = "LR SAM",
                                                                            [17] = "Aircraft Carriers",
                                                                            [18] = "Cruisers",
                                                                            [19] = "Destroyers",
                                                                            [20] = "Frigates",
                                                                            [21] = "Corvettes",
                                                                            [22] = "Light armed ships",
                                                                            [23] = "Unarmed ships",
                                                                            [24] = "Submarines",
                                                                            [25] = "Cruise missiles",
                                                                            [26] = "Antiship Missiles",
                                                                            [27] = "AA Missiles",
                                                                            [28] = "AG Missiles",
                                                                            [29] = "SA Missiles",
                                                                        }, -- end of ["noTargetTypes"]
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [6]
                                                        [7] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = true,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 7,
                                                            ["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"] = 641478.24186842,
                                            ["x"] = -281295.24037277,
                                            ["formation_template"] = "",
                                            ["speed_locked"] = true,
                                        }, -- end of [1]
                                        [2] = 
                                        {
                                            ["alt"] = 13,
                                            ["action"] = "Landing",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 179.86111111111,
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                    }, -- end of ["tasks"]
                                                }, -- end of ["params"]
                                            }, -- end of ["task"]
                                            ["type"] = "Land",
                                            ["ETA"] = 27.915328003958,
                                            ["ETA_locked"] = false,
                                            ["y"] = 647279.46875,
                                            ["x"] = -281782.46875,
                                            ["formation_template"] = "",
                                            ["airdromeId"] = 23,
                                            ["speed_locked"] = true,
                                        }, -- end of [2]
                                    }, -- end of ["points"]
                                }, -- end of ["route"]
                                ["groupId"] = 10,
                                ["hidden"] = false,
                                ["units"] = 
                                {
                                    [1] = 
                                    {
                                        ["alt"] = 457.2,
                                        ["alt_type"] = "BARO",
                                        ["livery_id"] = "Algerian AF Desert KU-03",
                                        ["skill"] = "Client",
                                        ["speed"] = 179.86111111111,
                                        ["type"] = "Su-25T",
                                        ["unitId"] = 24,
                                        ["psi"] = -1.6545868079291,
                                        ["y"] = 641478.24186842,
                                        ["x"] = -281295.24037277,
                                        ["name"] = "Lander Senaki Sue",
                                        ["payload"] = 
                                        {
                                            ["pylons"] = 
                                            {
                                            }, -- end of ["pylons"]
                                            ["fuel"] = "3790",
                                            ["flare"] = 128,
                                            ["chaff"] = 128,
                                            ["gun"] = 100,
                                        }, -- end of ["payload"]
                                        ["heading"] = 1.6545868079291,
                                        ["callsign"] = 
                                        {
                                            [1] = 7,
                                            [2] = 1,
                                            ["name"] = "Chevy11",
                                            [3] = 1,
                                        }, -- end of ["callsign"]
                                        ["onboard_num"] = "016",
                                    }, -- end of [1]
                                }, -- end of ["units"]
                                ["y"] = 641478.24186842,
                                ["x"] = -281295.24037277,
                                ["name"] = "Lander Senaki Sue",
                                ["communication"] = true,
                                ["start_time"] = 0,
                                ["uncontrollable"] = false,
                                ["frequency"] = 124,
                            }, -- end of [2]
                        }, -- end of ["group"]
                    }, -- end of ["plane"]
                }, -- end of [2]
            }, -- 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"] = 
            {
                [1] = 
                {
                    ["id"] = 0,
                    ["vehicle"] = 
                    {
                        ["group"] = 
                        {
                            [1] = 
                            {
                                ["visible"] = false,
                                ["tasks"] = 
                                {
                                }, -- end of ["tasks"]
                                ["uncontrollable"] = false,
                                ["task"] = "Ground Nothing",
                                ["taskSelected"] = true,
                                ["route"] = 
                                {
                                    ["spans"] = 
                                    {
                                    }, -- end of ["spans"]
                                    ["points"] = 
                                    {
                                        [1] = 
                                        {
                                            ["alt"] = 10,
                                            ["type"] = "Turning Point",
                                            ["ETA"] = 0,
                                            ["alt_type"] = "BARO",
                                            ["formation_template"] = "",
                                            ["y"] = 631218.93221274,
                                            ["x"] = -328275.31005257,
                                            ["ETA_locked"] = true,
                                            ["speed"] = 0,
                                            ["action"] = "Off Road",
                                            ["task"] = 
                                            {
                                                ["id"] = "ComboTask",
                                                ["params"] = 
                                                {
                                                    ["tasks"] = 
                                                    {
                                                        [1] = 
                                                        {
                                                            ["enabled"] = true,
                                                            ["auto"] = false,
                                                            ["id"] = "WrappedAction",
                                                            ["number"] = 1,
                                                            ["params"] = 
                                                            {
                                                                ["action"] = 
                                                                {
                                                                    ["id"] = "Option",
                                                                    ["params"] = 
                                                                    {
                                                                        ["value"] = 4,
                                                                        ["name"] = 0,
                                                                    }, -- end of ["params"]
                                                                }, -- end of ["action"]
                                                            }, -- end of ["params"]
                                                        }, -- end of [1]
                                                    }, -- end of ["tasks"]
                                                }, -- end of ["params"]
                                            }, -- end of ["task"]
                                            ["speed_locked"] = true,
                                        }, -- end of [1]
                                    }, -- end of ["points"]
                                }, -- end of ["route"]
                                ["groupId"] = 1,
                                ["hidden"] = false,
                                ["units"] = 
                                {
                                    [1] = 
                                    {
                                        ["skill"] = "Average",
                                        ["coldAtStart"] = false,
                                        ["type"] = "BTR-80",
                                        ["unitId"] = 11,
                                        ["y"] = 631218.93221274,
                                        ["x"] = -328275.31005257,
                                        ["name"] = "Ground-1-11",
                                        ["heading"] = 0,
                                        ["playerCanDrive"] = true,
                                    }, -- end of [1]
                                    [2] = 
                                    {
                                        ["skill"] = "Average",
                                        ["coldAtStart"] = false,
                                        ["type"] = "BTR-80",
                                        ["unitId"] = 10,
                                        ["y"] = 631826.35292123,
                                        ["x"] = -328492.31521796,
                                        ["name"] = "Ground-1-10",
                                        ["heading"] = 0,
                                        ["playerCanDrive"] = true,
                                    }, -- end of [2]
                                    [3] = 
                                    {
                                        ["skill"] = "Average",
                                        ["coldAtStart"] = false,
                                        ["type"] = "BTR-80",
                                        ["unitId"] = 9,
                                        ["y"] = 631240.24522006,
                                        ["x"] = -328322.7799325,
                                        ["name"] = "Ground-1-9",
                                        ["heading"] = 0,
                                        ["playerCanDrive"] = true,
                                    }, -- end of [3]
                                    [4] = 
                                    {
                                        ["skill"] = "Average",
                                        ["coldAtStart"] = false,
                                        ["type"] = "BTR-80",
                                        ["unitId"] = 8,
                                        ["y"] = 631726.15874757,
                                        ["x"] = -328023.44401234,
                                        ["name"] = "Ground-1-8",
                                        ["heading"] = 0,
                                        ["playerCanDrive"] = true,
                                    }, -- end of [4]
                                    [5] = 
                                    {
                                        ["skill"] = "Average",
                                        ["coldAtStart"] = false,
                                        ["type"] = "BTR-80",
                                        ["unitId"] = 7,
                                        ["y"] = 631245.08908536,
                                        ["x"] = -328218.15244204,
                                        ["name"] = "Ground-1-7",
                                        ["heading"] = 0,
                                        ["playerCanDrive"] = true,
                                    }, -- end of [5]
                                    [6] = 
                                    {
                                        ["skill"] = "Average",
                                        ["coldAtStart"] = false,
                                        ["type"] = "BTR-80",
                                        ["unitId"] = 6,
                                        ["y"] = 631654.88008964,
                                        ["x"] = -328025.36660315,
                                        ["name"] = "Ground-1-6",
                                        ["heading"] = 0,
                                        ["playerCanDrive"] = true,
                                    }, -- end of [6]
                                    [7] = 
                                    {
                                        ["skill"] = "Average",
                                        ["coldAtStart"] = false,
                                        ["type"] = "BTR-80",
                                        ["unitId"] = 5,
                                        ["y"] = 631612.25407501,
                                        ["x"] = -328026.33537621,
                                        ["name"] = "Ground-1-5",
                                        ["heading"] = 0,
                                        ["playerCanDrive"] = true,
                                    }, -- end of [7]
                                    [8] = 
                                    {
                                        ["skill"] = "Average",
                                        ["coldAtStart"] = false,
                                        ["type"] = "BTR-80",
                                        ["unitId"] = 4,
                                        ["y"] = 631669.41168554,
                                        ["x"] = -327991.45954606,
                                        ["name"] = "Ground-1-4",
                                        ["heading"] = 0,
                                        ["playerCanDrive"] = true,
                                    }, -- end of [8]
                                    [9] = 
                                    {
                                        ["skill"] = "Average",
                                        ["coldAtStart"] = false,
                                        ["type"] = "BTR-80",
                                        ["unitId"] = 3,
                                        ["y"] = 631189.86902095,
                                        ["x"] = -328330.53011698,
                                        ["name"] = "Ground-1-3",
                                        ["heading"] = 0,
                                        ["playerCanDrive"] = true,
                                    }, -- end of [9]
                                    [10] = 
                                    {
                                        ["skill"] = "Average",
                                        ["coldAtStart"] = false,
                                        ["type"] = "BTR-80",
                                        ["unitId"] = 2,
                                        ["y"] = 631629.69199009,
                                        ["x"] = -327980.8030424,
                                        ["name"] = "Ground-1-2",
                                        ["heading"] = 0,
                                        ["playerCanDrive"] = true,
                                    }, -- end of [10]
                                    [11] = 
                                    {
                                        ["skill"] = "Average",
                                        ["coldAtStart"] = false,
                                        ["type"] = "BTR-80",
                                        ["unitId"] = 1,
                                        ["y"] = 631192.77534013,
                                        ["x"] = -328226.87139958,
                                        ["name"] = "Ground-1-1",
                                        ["heading"] = 0,
                                        ["playerCanDrive"] = true,
                                    }, -- end of [11]
                                    [12] = 
                                    {
                                        ["skill"] = "Average",
                                        ["coldAtStart"] = false,
                                        ["type"] = "BTR-80",
                                        ["unitId"] = 16,
                                        ["y"] = 631815.69641757,
                                        ["x"] = -328527.19104812,
                                        ["name"] = "Ground-1-12",
                                        ["heading"] = 0,
                                        ["playerCanDrive"] = true,
                                    }, -- end of [12]
                                    [13] = 
                                    {
                                        ["skill"] = "Average",
                                        ["coldAtStart"] = false,
                                        ["type"] = "BTR-80",
                                        ["unitId"] = 17,
                                        ["y"] = 631796.32095637,
                                        ["x"] = -328557.22301297,
                                        ["name"] = "Ground-1-13",
                                        ["heading"] = 0,
                                        ["playerCanDrive"] = true,
                                    }, -- end of [13]
                                    [14] = 
                                    {
                                        ["skill"] = "Average",
                                        ["coldAtStart"] = false,
                                        ["type"] = "BTR-80",
                                        ["unitId"] = 18,
                                        ["y"] = 631829.25924041,
                                        ["x"] = -328559.16055909,
                                        ["name"] = "Ground-1-14",
                                        ["heading"] = 0,
                                        ["playerCanDrive"] = true,
                                    }, -- end of [14]
                                    [15] = 
                                    {
                                        ["skill"] = "Average",
                                        ["coldAtStart"] = false,
                                        ["type"] = "BTR-80",
                                        ["unitId"] = 19,
                                        ["y"] = 631845.72838242,
                                        ["x"] = -328527.19104812,
                                        ["name"] = "Ground-1-15",
                                        ["heading"] = 0,
                                        ["playerCanDrive"] = true,
                                    }, -- end of [15]
                                }, -- end of ["units"]
                                ["y"] = 631218.93221274,
                                ["x"] = -328275.31005257,
                                ["name"] = "Ground-1",
                                ["start_time"] = 0,
                            }, -- end of [1]
                        }, -- end of ["group"]
                    }, -- end of ["vehicle"]
                    ["name"] = "Russia",
                }, -- end of [1]
                [2] = 
                {
                    ["id"] = 81,
                    ["name"] = "CJTF Red",
                    ["plane"] = 
                    {
                        ["group"] = 
                        {
                            [1] = 
                            {
                                ["modulation"] = 0,
                                ["tasks"] = 
                                {
                                }, -- end of ["tasks"]
                                ["radioSet"] = false,
                                ["task"] = "CAS",
                                ["uncontrolled"] = false,
                                ["route"] = 
                                {
                                    ["points"] = 
                                    {
                                        [1] = 
                                        {
                                            ["alt"] = 2000,
                                            ["action"] = "From Ground Area",
                                            ["alt_type"] = "BARO",
                                            ["properties"] = 
                                            {
                                                ["addopt"] = 
                                                {
                                                }, -- end of ["addopt"]
                                            }, -- end of ["properties"]
                                            ["speed"] = 179.86111111111,
                                            ["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] = "UAVs",
                                                                            [6] = "Infantry",
                                                                            [7] = "Fortifications",
                                                                            [8] = "Tanks",
                                                                            [9] = "IFV",
                                                                            [10] = "APC",
                                                                            [11] = "Artillery",
                                                                            [12] = "Unarmed vehicles",
                                                                            [13] = "AAA",
                                                                            [14] = "SR SAM",
                                                                            [15] = "MR SAM",
                                                                            [16] = "LR SAM",
                                                                            [17] = "Aircraft Carriers",
                                                                            [18] = "Cruisers",
                                                                            [19] = "Destroyers",
                                                                            [20] = "Frigates",
                                                                            [21] = "Corvettes",
                                                                            [22] = "Light armed ships",
                                                                            [23] = "Unarmed ships",
                                                                            [24] = "Submarines",
                                                                            [25] = "Cruise missiles",
                                                                            [26] = "Antiship Missiles",
                                                                            [27] = "AA Missiles",
                                                                            [28] = "AG Missiles",
                                                                            [29] = "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"] = "TakeOffGround",
                                            ["ETA"] = 0,
                                            ["ETA_locked"] = true,
                                            ["y"] = 618208.06997368,
                                            ["x"] = -356111.63909964,
                                            ["formation_template"] = "",
                                            ["speed_locked"] = true,
                                        }, -- end of [1]
                                    }, -- end of ["points"]
                                }, -- end of ["route"]
                                ["groupId"] = 11,
                                ["hidden"] = false,
                                ["units"] = 
                                {
                                    [1] = 
                                    {
                                        ["alt"] = 2000,
                                        ["alt_type"] = "BARO",
                                        ["livery_id"] = "Algerian AF Desert KU-03",
                                        ["skill"] = "Client",
                                        ["speed"] = 179.86111111111,
                                        ["type"] = "Su-25T",
                                        ["unitId"] = 25,
                                        ["psi"] = -0.8146891467316,
                                        ["y"] = 618208.06997368,
                                        ["x"] = -356111.63909964,
                                        ["name"] = "Redscore",
                                        ["payload"] = 
                                        {
                                            ["pylons"] = 
                                            {
                                            }, -- end of ["pylons"]
                                            ["fuel"] = "3790",
                                            ["flare"] = 128,
                                            ["chaff"] = 128,
                                            ["gun"] = 100,
                                        }, -- end of ["payload"]
                                        ["heading"] = 0.8146891467316,
                                        ["callsign"] = 
                                        {
                                            [1] = 1,
                                            [2] = 1,
                                            ["name"] = "Enfield11",
                                            [3] = 1,
                                        }, -- end of ["callsign"]
                                        ["onboard_num"] = "010",
                                    }, -- end of [1]
                                }, -- end of ["units"]
                                ["y"] = 618208.06997368,
                                ["x"] = -356111.63909964,
                                ["name"] = "Redscore",
                                ["communication"] = true,
                                ["start_time"] = 0,
                                ["uncontrollable"] = false,
                                ["frequency"] = 124,
                            }, -- end of [1]
                        }, -- end of ["group"]
                    }, -- end of ["plane"]
                }, -- end of [2]
            }, -- end of ["country"]
        }, -- end of ["red"]
    }, -- end of ["coalition"]
    ["sortie"] = "DictKey_sortie_5",
    ["version"] = 22,
    ["trigrules"] = 
    {
        [1] = 
        {
            ["rules"] = 
            {
            }, -- end of ["rules"]
            ["eventlist"] = "",
            ["predicate"] = "triggerStart",
            ["actions"] = 
            {
                [1] = 
                {
                    ["text"] = "dcsCommon = {}\
dcsCommon.version = \"2.8.8\"\
--[[-- 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 understands 'red' and 'blue'\
 2.5.0 - \"Line\" formation with one unit places unit at center     \
 2.5.1 - vNorm(a)  \
 2.5.1 - added SA-18 Igla manpad to unitIsInfantry()\
 2.5.2 - added copyArray method\
       - corrected heading in createStaticObjectData\
 2.5.3 - corrected rotateGroupData bug for cz \
       - removed forced error in failed pickRandom\
 2.5.4 - rotateUnitData()\
       - randomBetween()\
 2.5.5 - stringStartsWithDigit()\
       - stringStartsWithLetter()\
       - stringIsPositiveNumber()\
 2.5.6 - corrected stringEndsWith() bug with str\
 2.5.7 - point2text(p) \
 2.5.8 - string2GroupCat()\
 2.5.9 - string2ObjectCat()\
 2.6.0 - unified uuid, removed uuIdent\
 2.6.1 - removed bug in rotateUnitData: cy --> cz param passing  \
 2.6.2 - new combineTables()\
 2.6.3 - new tacan2freq()\
 2.6.4 - new processHMS()\
 2.6.5 - new bearing2compass()\
       - new bearingdegrees2compass()\
       - new latLon2Text() - based on mist \
 2.6.6 - new nowString() \
       - new str2num()\
       - new stringRemainsStartingWith()\
       - new stripLF()\
       - new removeBlanks()\
 2.6.7 - new menu2text()\
 2.6.8 - new getMissionName()\
       - new flagArrayFromString()\
 2.6.9 - new getSceneryObjectsInZone()\
       - new getSceneryObjectInZoneByName()\
 2.7.0 - new synchGroupData()\
         clone, topClone and copyArray now all nil-trap \
 2.7.1 - new isPlayerUnit() -- moved from cfxPlayer\
         new getAllExistingPlayerUnitsRaw - from cfxPlayer\
         new typeIsInfantry()\
 2.7.2 - new rangeArrayFromString()\
         fixed leading blank bug in flagArrayFromString\
         new incFlag()\
         new decFlag()\
         nil trap in stringStartsWith()\
         new getClosestFreeSlotForCatInAirbaseTo()\
 2.7.3 - new string2Array()\
       - additional guard for isPlayerUnit\
 2.7.4 - new array2string()\
 2.7.5 - new bitAND32()\
       - new LSR()\
       - new num2bin()\
 2.7.6 - new getObjectsForCatAtPointWithRadius()\
 2.7.7 - clone() has new stripMeta option. pass true to remove all meta tables \
       - dumpVar2Str detects meta tables \
       - rotateGroupData kills unit's psi value if it existed since it messes with heading \
       - rotateGroupData - changes psi to -heading if it exists rather than nilling\
 2.7.8 - new getGeneralDirection()\
       - new getNauticalDirection()\
       - more robust guards for getUnitSpeed\
 2.7.9 - new bool2Num(theBool)\
       - new aspectByDirection()\
       - createGroundGroupWithUnits corrected spelling of minDist, crashed scattered formation\
       - randomPointInCircle fixed erroneous local for x, z \
       - \"scattered\" formation repaired\
 2.7.10- semaphore groundwork \
 2.8.0 - new collectMissionIDs at start-up  \
       - new getUnitNameByID\
       - new getGroupNameByID\
       - bool2YesNo alsco can return NIL\
       - new getUnitStartPosByID\
 2.8.1 - arrayContainsString: type checking for theArray and warning\
       - processStringWildcards()\
       - new wildArrayContainsString() \
       - fix for stringStartsWith oddity with aircraft types \
 2.8.2 - better fixes for string.find() in stringStartsWith and containsString\
       - dcsCommon.isTroopCarrier(theUnit, carriers) new carriers optional param\
       - better guards for getUnitAlt and getUnitAGL\
       - new newPointAtDegreesRange()\
       - new newPointAtAngleRange()\
       - new isTroopCarrierType()\
       - stringStartsWith now supports case insensitive match \
       - isTroopCarrier() supports 'any' and 'all'\
       - made getEnemyCoalitionFor() more resilient \
       - fix to smallRandom for negative numbers\
       - isTroopCarrierType uses wildArrayContainsString\
 2.8.3 - small optimizations in bearingFromAtoB()\
       - new whichSideOfMine()\
 2.8.4 - new rotatePointAroundOriginRad()\
       - new rotatePointAroundPointDeg()\
       - new rotatePointAroundPointRad()\
       - getClosestAirbaseTo() now supports passing list of air bases\
 2.8.5 - better guard in getGroupUnit()\
 2.8.6 - phonetic helpers \
         new spellString()\
 2.8.7 - new flareColor2Num()\
       - new flareColor2Text()\
       - new iteratePlayers()\
 2.8.8 - new hexString2RGBA()\
       - new playerName2Coalition()\
       - new coalition2Text()\
--]]--\
\
    -- dcsCommon is a library of common lua functions \
    -- for easy access and simple mission programming\
    -- (c) 2021 - 2023 by Chritian Franz and cf/x AG\
\
    dcsCommon.verbose = false -- set to true to see debug messages. Lots of them\
    dcsCommon.uuidStr = \"uuid-\"\
    dcsCommon.simpleUUID = 76543 -- a number to start. as good as any\
    \
    -- globals\
    dcsCommon.cbID = 0 -- callback id for simple callback scheduling\
    dcsCommon.troopCarriers = {\"Mi-8MT\", \"UH-1H\", \"Mi-24P\"} -- Ka-50, Apache and Gazelle can't carry troops\
    dcsCommon.coalitionSides = {0, 1, 2}\
    \
    -- lookup tables\
    dcsCommon.groupID2Name = {}\
    dcsCommon.unitID2Name = {}\
    dcsCommon.unitID2X = {}\
    dcsCommon.unitID2Y = {}\
\
    -- 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\
\
    -- read all groups and units from miz and build a reference table\
    function dcsCommon.collectMissionIDs()\
    -- create cross reference tables to be able to get a group or\
    -- unit's name by ID\
        for coa_name_miz, coa_data in pairs(env.mission.coalition) do -- iterate all coalitions\
            local coa_name = coa_name_miz\
            if string.lower(coa_name_miz) == 'neutrals' then -- remove 's' at neutralS\
                coa_name = 'neutral'\
            end\
            -- directly convert coalition into number for easier access later\
            local coaNum = 0\
            if coa_name == \"red\" then coaNum = 1 end \
            if coa_name == \"blue\" then coaNum = 2 end \
            \
            if type(coa_data) == 'table' then -- coalition = {bullseye, nav_points, name, county}, \
                                              -- with county being an array \
                if coa_data.country then -- make sure there a country table for this coalition\
                    for cntry_id, cntry_data in pairs(coa_data.country) do -- iterate all countries for this \
                        -- per country = {id, name, vehicle, helicopter, plane, ship, static}\
                        local countryName = string.lower(cntry_data.name)\
                        local countryID = cntry_data.id \
                        if type(cntry_data) == 'table' then    -- filter strings .id and .name \
                            for obj_type_name, obj_type_data in pairs(cntry_data) do\
                                -- only look at helos, ships, planes and vehicles\
                                if obj_type_name == \"helicopter\" or \
                                   obj_type_name == \"ship\" or \
                                   obj_type_name == \"plane\" or \
                                   obj_type_name == \"vehicle\" or \
                                   obj_type_name == \"static\" -- what about \"cargo\"?\
                                then -- (so it's not id or name)\
                                    local category = obj_type_name\
                                    if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then    --there's at least one group!\
                                        for group_num, group_data in pairs(obj_type_data.group) do\
                                            \
                                            local aName = group_data.name \
                                            local aID = group_data.groupId\
                                            -- store this reference \
                                            dcsCommon.groupID2Name[aID] = aName \
                                            \
                                            -- now iterate all units in this group \
                                            -- for player into \
                                            for unit_num, unit_data in pairs(group_data.units) do\
                                                if unit_data.name and unit_data.unitId then \
                                                    -- store this reference \
                                                    dcsCommon.unitID2Name[unit_data.unitId] = unit_data.name\
                                                    dcsCommon.unitID2X[unit_data.unitId] = unit_data.x\
                                                    dcsCommon.unitID2Y[unit_data.unitId] = unit_data.y\
                                                end\
                                            end -- for all units\
                                        end -- for all groups \
                                    end --if has category data \
                                end --if plane, helo etc... category\
                            end --for all objects in country \
                        end --if has country data \
                    end --for all countries in coalition\
                end --if coalition has country table \
            end -- if there is coalition data  \
        end --for all coalitions in mission \
    end\
\
    function dcsCommon.getUnitNameByID(theID)\
        -- accessor function for later expansion\
        return dcsCommon.unitID2Name[theID]\
    end\
    \
    function dcsCommon.getGroupNameByID(theID)\
        -- accessor function for later expansion \
        return dcsCommon.groupID2Name[theID]\
    end\
\
    function dcsCommon.getUnitStartPosByID(theID)\
        local x = dcsCommon.unitID2X[theID]\
        local y = dcsCommon.unitID2Y[theID]\
        return x, y\
    end\
    \
    -- returns only positive values, lo must be >0 and <= hi \
    function dcsCommon.randomBetween(loBound, hiBound)\
        if not loBound then loBound = 1 end \
        if not hiBound then hiBound = 1 end \
        if loBound == hiBound then return loBound end \
\
        local delayMin = loBound\
        local delayMax = hiBound \
        local delay = delayMax \
    \
        if delayMin ~= delayMax then \
            -- pick random in range , say 3-7 --> 5 s!\
            local delayDiff = (delayMax - delayMin) + 1 -- 7-3 + 1\
            delay = dcsCommon.smallRandom(delayDiff) - 1 --> 0-4\
            delay = delay + delayMin \
            if delay > delayMax then delay = delayMax end \
            if delay < 1 then delay = 1 end \
        \
            if dcsCommon.verbose then \
                trigger.action.outText(\"+++dcsC: delay range \" .. delayMin .. \"-\" .. delayMax .. \": selected \" .. delay, 30)\
            end\
        end\
        \
        return delay\
    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\
        theNum = math.floor(theNum)\
        if theNum >= 50 then return math.random(theNum) end\
        if theNum < 1 then\
            trigger.action.outText(\"smallRandom: invoke with argument < 1 (\" .. theNum .. \"), using 1\", 30)\
            theNum = 1 \
        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\
\
    -- combine table. creates new \
    function dcsCommon.combineTables(inOne, inTwo)\
        local outTable = {}\
        for idx, element in pairs(inOne) do \
            table.insert(outTable, element)\
        end\
        for idx, element in pairs(inTwo) do \
            table.insert(outTable, element)\
        end\
        return outTable\
    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, allYourBase)\
        local delta = math.huge\
        if not allYourBase then \
            allYourBase = dcsCommon.getAirbasesWhoseNameContains(\"*\", filterCat, filterCoalition) -- get em all and filter\
        end \
        \
        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\
\
    function dcsCommon.getClosestFreeSlotForCatInAirbaseTo(cat, x, y, theAirbase, ignore)\
        if not theAirbase then return nil end \
        if not ignore then ignore = {} end \
        if not cat then return nil end \
        if (not cat == \"helicopter\") and (not cat == \"plane\") then \
            trigger.action.outText(\"+++common-getslotforcat: wrong cat <\" .. cat .. \">\", 30)\
            return nil \
        end\
        local allFree = theAirbase:getParking(true) --  only free slots\
        local filterFreeByType = {}\
        for idx, aSlot in pairs(allFree) do \
            local termT = aSlot.Term_Type\
            if termT == 104 or \
            (termT == 72 and cat == \"plane\") or \
            (termT == 68 and cat == \"plane\") or \
            (termT == 40 and cat == \"helicopter\") then \
                table.insert(filterFreeByType, aSlot)\
            else \
                -- we skip this slot, not good for type \
            end\
        end\
        \
        if #filterFreeByType == 0 then \
            return nil\
        end \
        \
        local reallyFree = {}\
        for idx, aSlot in pairs(filterFreeByType) do \
            local slotNum = aSlot.Term_Index\
            isTaken = false \
            for idy, taken in pairs(ignore) do \
                if taken == slotNum then isTaken = true end \
            end\
            if not isTaken then \
                table.insert(reallyFree, aSlot)\
            end\
        end\
        \
        if #reallyFree < 1 then \
            reallyFree = filterFreeByType\
        end\
        \
        local closestDist = math.huge \
        local closestSlot = nil \
        local p = {x = x, y = 0, z = y} -- !!\
        for idx, aSlot in pairs(reallyFree) do \
            local sp = {x = aSlot.vTerminalPos.x, y = 0, z = aSlot.vTerminalPos.z}\
            local currDist = dcsCommon.distFlat(p, sp)\
            --trigger.action.outText(\"slot <\" .. aSlot.Term_Index .. \"> has dist \" .. math.floor(currDist) .. \" and _0 of <\" .. aSlot.Term_Index_0 .. \">\", 30)\
            if currDist < closestDist then \
                closestSlot = aSlot \
                closestDist = currDist \
            end\
        end\
        --trigger.action.outText(\"slot <\" .. closestSlot.Term_Index .. \"> has closest dist <\" .. math.floor(closestDist) .. \">\", 30)\
        return closestSlot\
    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 \
        if not A then \
            trigger.action.outText(\"WARNING: no 'A' in bearingFromAtoB\", 30)\
            return 0\
        end\
        if not B then\
            trigger.action.outText(\"WARNING: no 'A' in bearingFromAtoB\", 30)\
            return 0\
        end\
        if not A.x then \
            trigger.action.outText(\"WARNING: no 'A.x' (type A =<\" .. type(A) .. \">)in bearingFromAtoB\", 30)\
            return 0\
        end\
        if not A.y then \
            trigger.action.outText(\"WARNING: no 'A.x' (type A =<\" .. type(A) .. \">)in bearingFromAtoB\", 30)\
            return 0\
        end\
        if not B.x then \
            trigger.action.outText(\"WARNING: no 'B.x' (type B =<\" .. type(B) .. \">)in bearingFromAtoB\", 30)\
            return 0\
        end\
        if not B.y then \
            trigger.action.outText(\"WARNING: no 'B.y' (type B =<\" .. type(B) .. \">)in bearingFromAtoB\", 30)\
            return 0\
        end\
        \
        local dx = B.x - A.x\
        local dz = B.z - A.z\
        local 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.bearing2compass(inrad)\
        local bearing = math.floor(inrad / math.pi * 180)\
        if bearing < 0 then bearing = bearing + 360 end\
        if bearing > 360 then bearing = bearing - 360 end\
        return dcsCommon.bearingdegrees2compass(bearing)\
    end\
    \
    function dcsCommon.bearingdegrees2compass(bearing)\
        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\
        while direction >= 360 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.getGeneralDirection(direction) -- inspired by cws, improvements my own\
        if not direction then return \"unkown\" end\
        direction = math.fmod (direction, 360)\
        while direction < 0 do \
            direction = direction + 360\
        end\
        while direction >= 360 do \
            direction = direction - 360\
        end\
        if direction < 45 then return \"ahead\" end    \
        if direction < 135 then return \"right\" end\
        if direction < 225 then return \"behind\" end\
        if direction < 315 then return \"left\" end \
        return \"ahead\"\
    end\
    \
    function dcsCommon.getNauticalDirection(direction) -- inspired by cws, improvements my own\
        if not direction then return \"unkown\" end\
        direction = math.fmod (direction, 360)\
        while direction < 0 do \
            direction = direction + 360\
        end\
        while direction >= 360 do \
            direction = direction - 360\
        end\
        if direction < 45 then return \"ahead\" end    \
        if direction < 135 then return \"starboard\" end\
        if direction < 225 then return \"aft\" end\
        if direction < 315 then return \"port\" end \
        return \"ahead\"\
    end\
\
    function dcsCommon.aspectByDirection(direction) -- inspired by cws, improvements my own\
        if not direction then return \"unkown\" end\
        direction = math.fmod (direction, 360)\
        while direction < 0 do \
            direction = direction + 360\
        end\
        while direction >= 360 do \
            direction = direction - 360\
        end\
        \
        if direction < 45 then return \"hot\" end    \
        if direction < 135 then return \"beam\" end\
        if direction < 225 then return \"drag\" end\
        if direction < 315 then return \"beam\" end \
        return \"hot\"\
    end\
    \
    function dcsCommon.whichSideOfMine(theUnit, target) -- returs two values: -1/1 = left/right and \"left\"/\"right\" \
        if not theUnit then return nil end \
        if not target then return nil end \
        local uDOF = theUnit:getPosition() -- returns p, x, y, z Vec3\
        -- with x, y, z being the normalised vectors for right, up, forward \
        local heading = math.atan2(uDOF.x.z, uDOF.x.x) -- returns rads\
        if heading < 0 then\
            heading = heading + 2 * math.pi    -- put heading in range of 0 to 2*pi\
        end\
        -- heading now runs from 0 through 2Pi\
        local A = uDOF.p\
        local B = target:getPoint() \
         \
        -- now get bearing from theUnit to target  \
        local dx = B.x - A.x\
        local dz = B.z - A.z\
        local bearing = math.atan2(dz, dx) -- in rads\
        if bearing < 0 then\
            bearing = bearing + 2 * math.pi    -- make bearing 0 to 2*pi\
        end\
\
        -- we now have bearing to B, and own heading. \
        -- subtract own heading from bearing to see at what \
        -- bearing target would be if we 'turned the world' so\
        -- that theUnit is heading 0\
        local dBearing = bearing - heading\
        -- if result < 0 or > Pi (=180°), target is left from us\
        if dBearing < 0 or dBearing > math.pi then return -1, \"left\" end\
        return 1, \"right\"\
        -- note: no separate case for straight in front or behind\
    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\
        if not z then z = 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 \
        x = x + (innerRadius + r) * math.cos(degrees)\
        z = z + (innerRadius + r) * math.sin(degrees)\
    \
        local thePoint = {}\
        thePoint.x = x\
        thePoint.y = 0\
        thePoint.z = z \
        \
        return thePoint, degrees\
    end\
\
    function dcsCommon.newPointAtDegreesRange(p1, degrees, radius)\
        local rads = degrees * 3.14152 / 180\
        local p2 = dcsCommon.newPointAtAngleRange(p1, rads, radius)\
        return p2 \
    end\
    \
    function dcsCommon.newPointAtAngleRange(p1, angle, radius)\
        local p2 = {}\
        p2.x = p1.x + radius * math.cos(angle)\
        p2.y = p1.y \
        p2.z = p1.z + radius * math.sin(angle)\
        return p2 \
    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 Unit.isExist(theUnit) 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 type(aCoalition) == \"string\" then \
            aCoalition = aCoalition:lower()\
            if aCoalition == \"red\" then return 2 end\
            if aCoalition == \"blue\" then return 1 end\
            return nil \
        end\
        if aCoalition == 1 then return 2 end\
        if aCoalition == 2 then return 1 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)\
        if not orig then return nil end \
        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, stripMeta)\
        if not orig then return nil end \
        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\
            if not stripMeta then \
                -- also connect meta data\
                setmetatable(copy, dcsCommon.clone(getmetatable(orig)))\
            else \
                -- strip all except string, and for strings use a fresh string \
                if type(copy) == \"string\" then \
                    local tmp = \"\"\
                    tmp = tmp .. copy -- will get rid of any foreign metas for string \
                    copy = tmp \
                end\
            end\
        else -- number, string, boolean, etc\
            copy = orig\
        end\
        return copy\
    end\
\
    function dcsCommon.copyArray(inArray)\
        if not inArray then return nil end \
        \
        -- warning: this is a ref copy!\
        local theCopy = {}\
        for idx, element in pairs(inArray) do \
            table.insert(theCopy, element)\
        end\
        return theCopy \
    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)\
            -- if only one, place in middle of circle and be done \
            if num == 1 then \
                -- nothing. just stay in the middle \
            else \
                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    \
            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 until mindistance to all is kept or emergencybreak\
                    thePoint = dcsCommon.randomPointInCircle(radius, innerRadius) -- returns x, 0, z\
                    -- check if too close to others\
                    for idx, rUnit in pairs(processedUnits) do -- get min dist to all positioned units\
                        --trigger.action.outText(\"rPnt: thePoint =  \" .. dcsCommon.point2text(thePoint), 30)\
                        uPoint.x = rUnit.x\
                        uPoint.y = 0\
                        uPoint.z = rUnit.y \
                        --trigger.action.outText(\"rPnt: uPoint =  \" .. dcsCommon.point2text(uPoint), 30)\
                        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(\"+++dcsC: creating unit \" .. name .. \"-\" .. num .. \": \" .. theType, 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.rotatePointAroundOriginRad(inX, inY, angle) -- angle in degrees\
        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.rotatePointAroundOrigin(inX, inY, angle) -- angle in degrees\
        local rads =  3.14152 / 180 -- convert to radiants. \
        angle = angle * rads -- turns into rads\
        local px, py = dcsCommon.rotatePointAroundOriginRad(inX, inY, angle)\
        return px, py        \
    end\
    \
    function dcsCommon.rotatePointAroundPointRad(x, y, px, py, angle)\
        x = x - px \
        y = y - py\
        x, y = dcsCommon.rotatePointAroundOriginRad(x, y, angle)\
        x = x + px \
        y = y + py \
        return x, y\
    end\
\
    function dcsCommon.rotatePointAroundPointDeg(x, y, px, py, degrees)\
        x, y = dcsCommon.rotatePointAroundPointRad(x, y, px, py, degrees * 3.14152 / 180)\
        return x, y\
    end\
\
    -- rotates a Vec3-base inPoly on XZ pane around inPoint on XZ pane\
     function dcsCommon.rotatePoly3AroundVec3Rad(inPoly, inPoint, rads)\
        local outPoly = {}\
        for idx, aVertex in pairs(inPoly) do \
            local x, z = dcsCommon.rotatePointAroundPointRad(aVertex.x, aVertex.z, inPoint.x, inPoint.z, rads)        \
            local v3 = {x = x, y = aVertex.y, z = z}\
            outPoly[idx] = v3\
        end \
        return outPoly \
    end\
\
    function dcsCommon.rotateUnitData(theUnit, degrees, cx, cz)\
        if not cx then cx = 0 end\
        if not cz then cz = 0 end\
        local cy = cz \
        --trigger.action.outText(\"+++dcsC:rotGrp cy,cy = \"..cx .. \",\" .. cy, 30)\
        \
        local rads = degrees *  3.14152 / 180\
        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 degrees\
            theUnit.heading = theUnit.heading + rads \
        end\
    end\
    \
\
    function dcsCommon.rotateGroupData(theGroup, degrees, cx, cz)\
        if not cx then cx = 0 end\
        if not cz then cz = 0 end\
        local cy = cz \
        --trigger.action.outText(\"+++dcsC:rotGrp cy,cy = \"..cx .. \",\" .. cy, 30)\
        \
        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 degrees\
            theUnit.heading = theUnit.heading + rads \
            -- now kill psi if it existed before \
            -- theUnit.psi = nil\
            -- better code: psi is always -heading. Nobody knows what psi is, though\
            if theUnit.psi then \
                theUnit.psi = -theUnit.heading \
            end\
        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 = heading\
        -- 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\
\
function dcsCommon.synchGroupData(inGroupData) -- update group data block by \
-- comparing it to spawned group and update units by x, y, heding and isExist \
-- modifies inGroupData!\
    if not inGroupData then return end \
    -- groupdata from game, NOT MX DATA!\
    -- we synch the units and their coords \
    local livingUnits = {}\
    for idx, unitData in pairs(inGroupData.units) do \
        local theUnit = Unit.getByName(unitData.name)\
        if theUnit and theUnit:isExist() and theUnit:getLife()>1 then \
            -- update x and y and heading\
            local pos = theUnit:getPoint()\
            unitData.unitId = theUnit:getID()\
            unitData.x = pos.x \
            unitData.y = pos.z -- !!!!\
            unitData.heading = dcsCommon.getUnitHeading(gUnit)\
            table.insert(livingUnits, unitData)\
        end\
    end\
    inGroupData.units = livingUnits \
end\
\
--\
--\
-- M I S C   M E T H O D S \
--\
--\
\
-- as arrayContainsString, except it includes wildcard matches if EITHER \
-- ends on \"*\"\
    function dcsCommon.wildArrayContainsString(theArray, theString, caseSensitive) \
        if not theArray then return false end\
        if not theString then return false end\
        if not caseSensitive then caseSensitive = false end \
        if type(theArray) ~= \"table\" then \
            trigger.action.outText(\"***arrayContainsString: theArray is not type table but <\" .. type(theArray) .. \">\", 30)\
        end\
        if not caseSensitive then theString = string.upper(theString) end \
        \
        --trigger.action.outText(\"wildACS: theString = <\" .. theString .. \">, theArray contains <\" .. #theArray .. \"> elements\", 30)\
        local wildIn = dcsCommon.stringEndsWith(theString, \"*\")\
        if wildIn then dcsCommon.removeEnding(theString, \"*\") end \
        for idx, theElement in pairs(theArray) do -- i = 1, #theArray do \
            --local theElement = theArray[i]\
            --trigger.action.outText(\"test e <\" .. theElement .. \"> against s <\" .. theString .. \">\", 30)\
            if not caseSensitive then theElement = string.upper(theElement) end \
            local wildEle = dcsCommon.stringEndsWith(theElement, \"*\")\
            if wildEle then theElement = dcsCommon.removeEnding(theElement, \"*\") end \
            --trigger.action.outText(\"matching s=<\" .. theString .. \"> with e=<\" .. theElement .. \">\", 30)\
            if wildEle and wildIn then \
                -- both end on wildcards, partial match for both\
                if dcsCommon.stringStartsWith(theElement, theString) then return true end \
                if dcsCommon.stringStartsWith(theString, theElement) then return true end \
                --trigger.action.outText(\"match e* with s* failed.\", 30)\
            elseif wildEle then \
                -- Element is a wildcard, partial match \
                if dcsCommon.stringStartsWith(theString, theElement) then return true end\
                --trigger.action.outText(\"startswith - match e* <\" .. theElement .. \"> with s <\" .. theString .. \"> failed.\", 30)\
            elseif wildIn then\
                -- theString is a wildcard. partial match \
                if dcsCommon.stringStartsWith(theElement, theString) then return true end\
                --trigger.action.outText(\"match e with s* failed.\", 30)\
            else\
                -- standard: no wildcards, full match\
                if theElement == theString then return true end \
                --trigger.action.outText(\"match e with s (straight) failed.\", 30)\
            end\
            \
        end\
        return false \
    end\
\
\
    function dcsCommon.arrayContainsString(theArray, theString) \
        if not theArray then return false end\
        if not theString then return false end\
        if type(theArray) ~= \"table\" then \
            trigger.action.outText(\"***arrayContainsString: theArray is not type table but <\" .. type(theArray) .. \">\", 30)\
        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\
    \
    function dcsCommon.string2Array(inString, deli, uCase)\
        if not inString then return {} end \
        if not deli then return {} end \
        if not uCase then uCase = false end\
        if uCase then inString = string.upper(inString) end\
        inString = dcsCommon.trim(inString)\
        if dcsCommon.containsString(inString, deli) then \
            local a = dcsCommon.splitString(inString, deli)\
            a = dcsCommon.trimArray(a)\
            return a \
        else \
            return {inString}\
        end\
    end\
    \
    function dcsCommon.array2string(inArray, deli)\
        if not deli then deli = \",\" end\
        if type(inArray) ~= \"table\" then return \"<err in array2string: not an array>\" end\
        local s = \"\"\
        local count = 0\
        for idx, ele in pairs(inArray) do\
            if count > 0 then s = s .. deli .. \" \" end\
            s = s .. ele\
        end\
        return s\
    end\
    \
    function dcsCommon.stripLF(theString)\
        return theString:gsub(\"[\\r\\n]\", \"\")\
    end\
    \
    function dcsCommon.removeBlanks(theString)\
        return theString:gsub(\"%s\", \"\")\
    end\
    \
    function dcsCommon.stringIsPositiveNumber(theString)\
        -- only full integer positive numbers supported \
        if not theString then return false end \
--        if theString == \"\" then return false end \
        for i = 1, #theString do \
            local c = theString:sub(i,i)\
            if c < \"0\" or c > \"9\" then return false end \
        end\
        return true \
    end\
    \
    function dcsCommon.stringStartsWithDigit(theString)\
        if #theString < 1 then return false end \
        local c = string.sub(theString, 1, 1) \
        return c >= \"0\" and c <= \"9\" \
    end\
    \
    function dcsCommon.stringStartsWithLetter(theString)\
        if #theString < 1 then return false end \
        local c = string.sub(theString, 1, 1)\
        if c >= \"a\" and c <= \"z\" then return true end  \
        if c >= \"A\" and c <= \"Z\" then return true end \
        return false \
    end\
    \
    function dcsCommon.stringStartsWith(theString, thePrefix, caseInsensitive)\
        if not theString then return false end \
        if not thePrefix then return false end \
        if not caseInsensitive then caseInsensitive = false end \
        \
        if caseInsensitive then \
            theString = string.upper(theString)\
            thePrefix = string.upper(theString)\
        end\
        -- new code because old 'string.find' had some really \
        -- strange results with aircraft types. Prefix \"A-10\" did not \
        -- match string \"A-10A\" etc. \
        \
        -- superseded: string.find (s, pattern [, init [, plain]]) solves the problem \
        \
        --[[\
        local pl = string.len(thePrefix)\
        if pl > string.len(theString) then return false end\
        if pl < 1 then return false end\
         for i=1, pl do \
        local left =  string.sub(theString, i, i)\
        local right = string.sub(thePrefix, i, i)\
            if left ~= right then \
                return false\
            end\
        end\
    \
        return true \
--]]--        trigger.action.outText(\"---- OK???\", 30)\
        -- strange stuff happening with some strings, let's investigate \
        \
        local i, j = string.find(theString, thePrefix, 1, true)\
        return (i == 1)\
--[[--\
        if res then\
            trigger.action.outText(\"startswith: <\" .. theString .. \"> pre <\" .. thePrefix .. \"> --> YES\", 30)\
        else \
            trigger.action.outText(\"startswith: <\" .. theString .. \"> nojoy pre <\" .. thePrefix .. \">\", 30)\
        end\
        return res \
--]]--\
    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 theString: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, 1, true) -- 1, true means start at 1, plaintext\
    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\
            return \"NIL\"\
        end \
        if theBool then return \"yes\" end \
        return \"no\"\
    end\
    \
    function dcsCommon.bool2Num(theBool)\
        if not theBool then theBool = false end \
        if theBool then return 1 end \
        return 0\
    end\
\
    function dcsCommon.point2text(p) \
        if not p then return \"<!NIL!>\" end \
        local t = \"[x=\"\
        if p.x then t = t .. p.x .. \", \" else t = t .. \"<nil>, \" end \
        if p.y then t = t .. \"y=\" .. p.y .. \", \" else t = t .. \"y=<nil>, \" end \
        if p.z then t = t .. \"z=\" .. p.z .. \"]\" else t = t .. \"z=<nil>]\" end \
        return t \
    end\
\
    function dcsCommon.string2GroupCat(inString)\
\
        if not inString then return 2 end -- default ground \
        inString = inString:lower()\
        inString = dcsCommon.trim(inString)\
\
        local catNum = tonumber(inString)\
        if catNum then \
            if catNum < 0 then catNum = 0 end \
            if catNum > 4 then catNum = 4 end \
            return catNum \
        end\
    \
        catNum = 2 -- ground default \
        if dcsCommon.stringStartsWith(inString, \"grou\") then catNum = 2 end \
        if dcsCommon.stringStartsWith(inString, \"air\") then catNum = 0 end\
        if dcsCommon.stringStartsWith(inString, \"hel\") then catNum = 1 end\
        if dcsCommon.stringStartsWith(inString, \"shi\") then catNum = 3 end\
        if dcsCommon.stringStartsWith(inString, \"trai\") then catNum = 4 end\
\
        return catNum\
    end\
\
    function dcsCommon.string2ObjectCat(inString)\
\
        if not inString then return 3 end -- default static \
        inString = inString:lower()\
        inString = dcsCommon.trim(inString)\
\
        local catNum = tonumber(inString)\
        if catNum then \
            if catNum < 0 then catNum = 0 end \
            if catNum > 6 then catNum = 6 end \
            return catNum \
        end\
    \
        catNum = 3 -- static default \
        if dcsCommon.stringStartsWith(inString, \"uni\") then catNum = 1 end \
        if dcsCommon.stringStartsWith(inString, \"wea\") then catNum = 2 end\
        if dcsCommon.stringStartsWith(inString, \"bas\") then catNum = 4 end\
        if dcsCommon.stringStartsWith(inString, \"sce\") then catNum = 5 end\
        if dcsCommon.stringStartsWith(inString, \"car\") then catNum = 6 end\
\
        return catNum\
    end\
\
    function dcsCommon.menu2text(inMenu)\
        if not inMenu then return \"<nil>\" end\
        local s = \"\"\
        for n, v in pairs(inMenu) do \
            if type(v) == \"string\" then \
                if s == \"\" then s = \"[\" .. v .. \"]\"  else \
                    s = s .. \" | [\" .. type(v) .. \"]\" end\
            else \
                if s == \"\" then s = \"[<\" .. type(v) .. \">]\"  else\
                    s = s .. \" | [<\" .. type(v) .. \">]\" end\
            end\
        end\
        return s\
    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 getmetatable(value) then \
            if type(value) == \"string\" then \
            else \
                trigger.action.outText(prefix .. key (\" .. type(value) .. \") .. \" HAS META\", 30)\
            end\
        end\
        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\
    \
\
    \
    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.numberUUID() -- 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.flareColor2Text(flareColor)\
        if (flareColor == 0) then return \"Green\" end\
        if (flareColor == 1) then return \"Red\" end\
        if (flareColor == 2) then return \"White\" end\
        if (flareColor == 3) then return \"Yellow\" end\
        if (flareColor < 0) then return \"Random\" end \
        return (\"unknown: \" .. flareColor)\
    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.flareColor2Num(flareColor)\
        if not flareColor then flareColor = \"green\" end \
        if type(flareColor) ~= \"string\" then return 0 end \
        flareColor = flareColor:lower()\
        if (flareColor == \"green\") then return 0 end \
        if (flareColor == \"red\") then return 1 end \
        if (flareColor == \"white\") then return 2 end \
        if (flareColor == \"yellow\") then return 3 end \
        if (flareColor == \"random\") then return -1 end \
        if (flareColor == \"rnd\") then return -1 end \
        return 0\
    end\
\
    \
    function dcsCommon.markPointWithSmoke(p, smokeColor)\
        if not smokeColor then smokeColor = 0 end \
        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\
\
-- based on buzzer1977's idea, channel is number, eg in 74X, channel is 74, mode is \"X\"\
    function tacan2freq(channel, mode)    \
        if not mode then mode = \"X\" end \
        if not channel then channel = 1 end \
        if type(mode) ~= \"string\" then mode = \"X\" end \
        mode = mode:upper()\
        local offset = 1000000 * channel\
        if channel < 64 then \
            if mode == \"Y\" then\
                return 1087000000 + offset\
            end\
            return 961000000 + offset -- mode x\
        end\
    \
        if mode == \"Y\" then\
            return 961000000 + offset\
        end\
        return 1087000000 + offset -- mode x\
    end\
    \
    function dcsCommon.processHMS(msg, delta)\
        local rS = math.floor(delta)\
        local remainS = tostring(rS)\
        local rM = math.floor(delta/60)\
        local remainM = tostring(rM)\
        local rH = math.floor(delta/3600)\
        local remainH = tostring(rH)\
        local hmsH = remainH \
        if rH < 10 then hmsH = \"0\" .. hmsH end \
        \
        local hmsCount = delta - (rH * 3600) -- mins left \
        local mins = math.floor (hmsCount / 60)\
        local hmsM = tostring(mins)\
        if mins < 10 then hmsM = \"0\" .. hmsM end \
        \
        hmsCount = hmsCount - (mins * 60) \
        local secs = math.floor(hmsCount)\
        local hmsS = tostring(secs)\
        if secs < 10 then hmsS = \"0\" .. hmsS end \
        \
        msg = string.gsub(msg, \"<s>\", remainS)\
        msg = string.gsub(msg, \"<m>\", remainM)\
        msg = string.gsub(msg, \"<h>\", remainH)\
        \
        msg = string.gsub(msg, \"<:s>\", hmsS)\
        msg = string.gsub(msg, \"<:m>\", hmsM)\
        msg = string.gsub(msg, \"<:h>\", hmsH)\
        \
        return msg \
    end\
    \
    function dcsCommon.nowString()\
        local absSecs = timer.getAbsTime()-- + env.mission.start_time\
        while absSecs > 86400 do \
            absSecs = absSecs - 86400 -- subtract out all days \
        end\
        return dcsCommon.processHMS(\"<:h>:<:m>:<:s>\", absSecs)\
    end\
    \
    function dcsCommon.str2num(inVal, default) \
        if not default then default = 0 end\
        if not inVal then return default end\
        if type(inVal) == \"number\" then return inVal end                 \
        local num = nil\
        if type(inVal) == \"string\" then num = tonumber(inVal) end\
        if not num then return default end\
        return num\
    end\
    \
    function dcsCommon.stringRemainsStartingWith(theString, startingWith)\
        -- find the first position where startingWith starts \
        local pos = theString:find(startingWith)\
        if not pos then return theString end \
        -- now return the entire remainder of the string from pos \
        local nums = theString:len() - pos + 1\
        return theString:sub(-nums)\
    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.vNorm(a) \
    if not a then return {x = 0, y = 0, z = 0} end \
    m = dcsCommon.vMag(a)\
    if m <= 0 then return {x = 0, y = 0, z = 0} end \
    local r = {}\
    r.x = a.x / m \
    r.y = a.y / m \
    r.z = a.z / m\
    return r \
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.isTroopCarrierType(theType, carriers)\
    if not theType then return false end \
    if not carriers then carriers = dcsCommon.troopCarriers \
    end \
    -- remember that arrayContainsString is case INsensitive by default \
    if dcsCommon.wildArrayContainsString(carriers, theType) then \
        -- may add additional tests before returning true\
        return true\
    end\
    \
    -- see if user wanted 'any' or 'all' supported\
    if dcsCommon.arrayContainsString(carriers, \"any\") then \
        return true \
    end \
    \
    if dcsCommon.arrayContainsString(carriers, \"all\") then \
        return true \
    end \
    \
    return false\
end\
\
function dcsCommon.isTroopCarrier(theUnit, carriers)\
    -- return true if conf can carry troups\
    if not theUnit then return false end \
    local uType = theUnit:getTypeName()\
    return dcsCommon.isTroopCarrierType(uType, carriers) \
end\
\
function dcsCommon.isPlayerUnit(theUnit)\
    -- new patch. simply check if getPlayerName returns something\
    if not theUnit then return false end \
    if not Unit.isExist(theUnit) then return end \
    if not theUnit.getPlayerName then return false end -- map/static object \
    local pName = theUnit:getPlayerName()\
    if pName then return true end \
    return false \
end\
\
function dcsCommon.getAllExistingPlayerUnitsRaw()\
    local apu = {}\
    for idx, theSide in pairs(dcsCommon.coalitionSides) do\
        local thePlayers = coalition.getPlayers(theSide) \
        for idy, theUnit in pairs (thePlayers) do \
            if theUnit and theUnit:isExist() then \
                table.insert(apu, theUnit)\
            end\
        end\
    end\
    return apu \
end\
\
function dcsCommon.getUnitAlt(theUnit)\
    if not theUnit then return 0 end\
    if not Unit.isExist(theUnit) then return 0 end -- safer \
    local p = theUnit:getPoint()\
    return p.y \
end\
\
function dcsCommon.getUnitAGL(theUnit)\
    if not theUnit then return 0 end\
    if not Unit.isExist(theUnit) then return 0 end -- safe fix\
    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 Unit.isExist(theUnit) 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 360 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.typeIsInfantry(theType)\
    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) or \
                dcsCommon.containsString(theType, \"SA-18 Igla\", false)\
    return isInfantry\
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) or \
                dcsCommon.containsString(theType, \"SA-18 Igla\", false)\
    return isInfantry\
--]]--\
    return dcsCommon.typeIsInfantry(theType)\
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\
\
function dcsCommon.coalition2Text(coa)\
    if not coa then return \"!nil!\" end \
    if coa == 0 then return \"NEUTRAL\" end \
    if coa == 1 then return \"RED\" end \
    if coa == 2 then return \"BLUE\" end \
    return \"?UNKNOWN?\"\
end\
\
function dcsCommon.latLon2Text(lat, lon)\
    -- inspired by mist, thanks Grimes!\
    -- returns two strings: lat and lon \
    \
    -- determine hemispheres by sign\
    local latHemi, lonHemi\
    if lat > 0 then latHemi = 'N' else latHemi = 'S' end\
    if lon > 0 then lonHemi = 'E' else lonHemi = 'W' end\
\
    -- remove sign since we have hemi\
    lat = math.abs(lat)\
    lon = math.abs(lon)\
\
    -- calc deg / mins \
    local latDeg = math.floor(lat)\
    local latMin = (lat - latDeg) * 60\
    local lonDeg = math.floor(lon)\
    local lonMin = (lon - lonDeg) * 60\
\
    -- calc seconds \
    local rawLatMin = latMin\
    latMin = math.floor(latMin)\
    local latSec = (rawLatMin - latMin) * 60\
    local rawLonMin = lonMin\
    lonMin = math.floor(lonMin)\
    local lonSec = (rawLonMin - lonMin) * 60\
\
    -- correct for rounding errors \
    if latSec >= 60 then\
        latSec = latSec - 60\
        latMin = latMin + 1\
    end\
    if lonSec >= 60 then\
        lonSec = lonSec - 60\
        lonMin = lonMin + 1\
    end\
\
    -- prepare string output \
    local secFrmtStr = '%06.3f'\
    local lat = string.format('%02d', latDeg) .. '°' .. string.format('%02d', latMin) .. \"'\" .. string.format(secFrmtStr, latSec) .. '\"' .. latHemi\
    local lon = string.format('%02d', lonDeg) .. '°' .. string.format('%02d', lonMin) .. \"'\" .. string.format(secFrmtStr, lonSec) .. '\"' .. lonHemi\
    return lat, lon  \
end\
\
-- get mission name. If mission file name without \".miz\"\
function dcsCommon.getMissionName()\
    local mn = net.dostring_in(\"gui\", \"return DCS.getMissionName()\")\
    return mn\
end\
\
function dcsCommon.flagArrayFromString(inString, verbose)\
    if not verbose then verbose = false end \
    \
    if verbose then \
        trigger.action.outText(\"+++flagArray: processing <\" .. inString .. \">\", 30)\
    end \
\
    if string.len(inString) < 1 then \
        trigger.action.outText(\"+++flagArray: empty flags\", 30)\
        return {} \
    end\
    \
    \
    local flags = {}\
    local rawElements = dcsCommon.splitString(inString, \",\")\
    -- go over all elements \
    for idx, anElement in pairs(rawElements) do \
        anElement = dcsCommon.trim(anElement)\
        if dcsCommon.stringStartsWithDigit(anElement) and  dcsCommon.containsString(anElement, \"-\") then \
            -- interpret this as a range\
            local theRange = dcsCommon.splitString(anElement, \"-\")\
            local lowerBound = theRange[1]\
            lowerBound = tonumber(lowerBound)\
            local upperBound = theRange[2]\
            upperBound = tonumber(upperBound)\
            if lowerBound and upperBound then\
                -- swap if wrong order\
                if lowerBound > upperBound then \
                    local temp = upperBound\
                    upperBound = lowerBound\
                    lowerBound = temp \
                end\
                -- now add add numbers to flags\
                for f=lowerBound, upperBound do \
                    table.insert(flags, f)\
\
                end\
            else\
                -- bounds illegal\
                trigger.action.outText(\"+++flagArray: ignored range <\" .. anElement .. \"> (range)\", 30)\
            end\
        else\
            -- single number\
            local f = dcsCommon.trim(anElement) -- DML flag upgrade: accept strings tonumber(anElement)\
            if f then \
                table.insert(flags, f)\
\
            else \
                trigger.action.outText(\"+++flagArray: ignored element <\" .. anElement .. \"> (single)\", 30)\
            end\
        end\
    end\
    if verbose then \
        trigger.action.outText(\"+++flagArray: <\" .. #flags .. \"> flags total\", 30)\
    end \
    return flags\
end\
\
function dcsCommon.rangeArrayFromString(inString, verbose)\
    if not verbose then verbose = false end \
    \
    if verbose then \
        trigger.action.outText(\"+++rangeArray: processing <\" .. inString .. \">\", 30)\
    end \
\
    if string.len(inString) < 1 then \
        trigger.action.outText(\"+++rangeArray: empty ranges\", 30)\
        return {} \
    end\
    \
    local ranges = {}\
    local rawElements = dcsCommon.splitString(inString, \",\")\
    -- go over all elements \
    for idx, anElement in pairs(rawElements) do \
        anElement = dcsCommon.trim(anElement)\
        local outRange = {}\
        if dcsCommon.stringStartsWithDigit(anElement) and  dcsCommon.containsString(anElement, \"-\") then \
            -- interpret this as a range\
            local theRange = dcsCommon.splitString(anElement, \"-\")\
            local lowerBound = theRange[1]\
            lowerBound = tonumber(lowerBound)\
            local upperBound = theRange[2]\
            upperBound = tonumber(upperBound)\
            if lowerBound and upperBound then\
                -- swap if wrong order\
                if lowerBound > upperBound then \
                    local temp = upperBound\
                    upperBound = lowerBound\
                    lowerBound = temp \
                end\
                -- now add to ranges\
                outRange[1] = lowerBound\
                outRange[2] = upperBound\
                table.insert(ranges, outRange)\
                if verbose then \
                    trigger.action.outText(\"+++rangeArray: new range <\" .. lowerBound .. \"> to <\" .. upperBound .. \">\", 30)\
                end\
            else\
                -- bounds illegal\
                trigger.action.outText(\"+++rangeArray: ignored range <\" .. anElement .. \"> (range)\", 30)\
            end\
        else\
            -- single number\
            local f = dcsCommon.trim(anElement) \
            f = tonumber(f)\
            if f then \
                outRange[1] = f\
                outRange[2] = f\
                table.insert(ranges, outRange)\
                if verbose then \
                    trigger.action.outText(\"+++rangeArray: new (single-val) range <\" .. f .. \"> to <\" .. f .. \">\", 30)\
                end\
            else \
                trigger.action.outText(\"+++rangeArray: ignored element <\" .. anElement .. \"> (single)\", 30)\
            end\
        end\
    end\
    if verbose then \
        trigger.action.outText(\"+++rangeArray: <\" .. #ranges .. \"> ranges total\", 30)\
    end \
    return ranges\
end\
\
function dcsCommon.incFlag(flagName)\
    local v = trigger.misc.getUserFlag(flagName)\
    trigger.action.setUserFlag(flagName, v + 1)\
end\
\
function dcsCommon.decFlag(flagName)\
    local v = trigger.misc.getUserFlag(flagName)\
    trigger.action.setUserFlag(flagName, v - 1)\
end\
\
function dcsCommon.objectHandler(theObject, theCollector)\
    table.insert(theCollector, theObject)\
    return true \
end\
\
function dcsCommon.getObjectsForCatAtPointWithRadius(aCat, thePoint, theRadius)\
    if not aCat then aCat = Object.Category.UNIT end \
    local p = {x=thePoint.x, y=thePoint.y, z=thePoint.z}\
    local collector = {}\
    \
    -- now build the search argument \
    local args = {\
            id = world.VolumeType.SPHERE,\
            params = {\
                point = p,\
                radius = theRadius\
            }\
        }\
    \
    -- now call search\
    world.searchObjects(aCat, args, dcsCommon.objectHandler, collector)\
    return collector\
end\
\
function dcsCommon.getSceneryObjectsInZone(theZone) -- DCS ZONE!!! \
    local aCat = 5 -- scenery\
    -- WARNING: WE ARE USING DCS ZONES, NOT CFX!!!\
    local p = {x=theZone.x, y=0, z=theZone.y}\
    local lp = {x = p.x, y = p.z}\
    p.y = land.getHeight(lp)\
    local collector = {}\
    \
    -- now build the search argument \
    local args = {\
            id = world.VolumeType.SPHERE,\
            params = {\
                point = p,\
                radius = theZone.radius\
            }\
        }\
    \
    -- now call search\
    world.searchObjects(aCat, args, dcsCommon.objectHandler, collector)\
    return collector\
end\
\
function dcsCommon.getSceneryObjectInZoneByName(theName, theZone) -- DCS ZONE!!!\
    local allObs = dcsCommon.getSceneryObjectsInZone(theZone)\
    for idx, anObject in pairs(allObs) do \
        if tostring(anObject:getName()) == theName then return anObject end \
    end\
    return nil \
end\
\
--\
-- bitwise operators\
--\
function dcsCommon.bitAND32(a, b)\
    if not a then a = 0 end \
    if not b then b = 0 end \
    local z = 0\
    local e = 1\
    for i = 0, 31 do \
        local a1 = a % 2 -- 0 or 1\
        local b1 = b % 2 -- 0 or 1\
        if a1 == 1 and b1 == 1 then \
            a = a - 1 -- remove bit \
            b = b - 1 \
            z = z + e\
        else\
            if a1 == 1 then a = a - 1 end -- remove bit \
            if b1 == 1 then b = b - 1 end \
        end\
        a = a / 2 -- shift right\
        b = b / 2        \
        e = e * 2 -- raise e by 1 \
    end\
    return z\
end\
\
function dcsCommon.num2bin(a)\
    if not a then a = 0 end \
    local z = \"\"\
    for i = 0, 31 do \
        local a1 = a % 2 -- 0 or 1\
        if a1 == 1 then \
            a = a - 1 -- remove bit \
            z = \"1\"..z\
        else\
            z = \"0\"..z\
        end\
        a = a / 2 -- shift right\
    end\
    return z\
end\
\
function dcsCommon.LSR(a, num)\
    if not a then a = 0 end \
    if not num then num = 16 end \
    for i = 1, num do \
        local a1 = a % 2 -- 0 or 1\
        if a1 == 1 then \
            a = a - 1 -- remove bit \
        end\
        a = a / 2 -- shift right\
    end\
    return a\
end\
\
--\
-- string wildcards \
--\
function dcsCommon.processStringWildcards(inMsg)\
    -- Replace STATIC bits of message like CR and zone name \
    if not inMsg then return \"<nil inMsg>\" end\
    local formerType = type(inMsg)\
    if formerType ~= \"string\" then inMsg = tostring(inMsg) end  \
    if not inMsg then inMsg = \"<inMsg is incompatible type \" .. formerType .. \">\" end \
    local outMsg = \"\"\
    -- replace line feeds \
    outMsg = inMsg:gsub(\"<n>\", \"\\n\")\
\
    return outMsg \
end\
\
--\
-- phonetic alphabet \
--\
dcsCommon.alphabet = {\
    a = \"alpha\",\
    b = \"bravo\",\
    c = \"charlie\",\
    d = \"delta\",\
    e = \"echo\",\
    f = \"foxtrot\",\
    g = \"golf\",\
    h = \"hotel\",\
    i = \"india\",\
    j = \"juliet\",\
    k = \"kilo\",\
    l = \"lima\",\
    m = \"mike\",\
    n = \"november\",\
    o = \"oscar\",\
    p = \"papa\",\
    q = \"quebec\",\
    r = \"romeo\",\
    s = \"sierra\",\
    t = \"tango\",\
    u = \"uniform\",\
    v = \"victor\",\
    w = \"whiskey\",\
    x = \"x-ray\",\
    y = \"yankee\",\
    z = \"zulu\",\
[\"0\"] = \"zero\",\
[\"1\"] = \"wun\",\
[\"2\"] = \"too\",\
[\"3\"] = \"tree\",\
[\"4\"] = \"fower\",\
[\"5\"] = \"fife\" ,\
[\"6\"] = \"six\",\
[\"7\"] = \"seven\",\
[\"8\"] = \"att\",\
[\"9\"] = \"niner\",\
[\" \"] = \"break\",\
}\
\
function dcsCommon.letter(inChar)\
    local theChar = \"\"\
    if type(inChar == \"string\") then \
        if #inChar < 1 then return \"#ERROR0#\" end\
        inChar = string.lower(inChar)\
        theChar = string.sub(inChar, 1, 1)\
    elseif type(inChar == \"number\") then \
        if inChar > 255 then return \"#ERROR>#\" end \
        if inChar < 0 then return \"#ERROR<#\" end \
        theChar = char(inChar)\
    else \
        return \"#ERRORT#\"\
    end\
--    trigger.action.outText(\"doing <\" .. theChar .. \">\", 30)\
    local a = dcsCommon.alphabet[theChar]\
    if a == nil then a = \"#ERROR?#\" end \
    return a \
end\
\
function dcsCommon.spellString(inString)\
    local res = \"\"\
    local first = true \
    for i = 1, #inString do\
        local c = inString:sub(i,i)\
        if first then \
            res = dcsCommon.letter(c)\
            first = false \
        else \
            res = res .. \" \" .. dcsCommon.letter(c)\
        end\
    end\
    return res \
end\
\
--\
-- RGBA from hex\
--\
function dcsCommon.hexString2RGBA(inString) \
    -- enter with \"#FF0020\" (RGB) or \"#FF00AB99\" RGBA\
    -- check if it starts with #\
    if not inString then return nil end \
    if #inString ~= 7 and #inString ~=9 then return nil end \
    if inString:sub(1, 1) ~= \"#\" then return nil end \
    inString = inString:lower()\
    local red = tonumber(\"0x\" .. inString:sub(2,3)) \
    if not red then red = 0 end \
    local green = tonumber(\"0x\" .. inString:sub(4,5))\
    if not green then green = 0 end \
    local blue = tonumber(\"0x\" .. inString:sub(6,7))\
    if not blue then blue = 0 end \
    local alpha = 255 \
    if #inString == 9 then \
        alpha = tonumber(\"0x\" .. inString:sub(8,9))\
    end\
    if not alpha then alpha = 0 end\
    return {red/255, green/255, blue/255, alpha/255}\
end\
\
\
--\
-- Player handling \
--\
function dcsCommon.playerName2Coalition(playerName)\
    if not playerName then return 0 end \
    local factions = {1,2}\
    for idx, theFaction in pairs(factions) do \
        local players = coalition.getPlayers(theFaction)\
        for idy, theUnit in pairs(players) do \
            local upName = theUnit:getPlayerName()\
            if upName == playerName then return theFaction end\
        end\
    end\
    return 0\
end\
\
--\
-- iterators\
--\
-- iteratePlayers - call callback for all player units\
-- callback is of signature callback(playerUnit)\
--\
\
function dcsCommon.iteratePlayers(callBack)\
    local factions = {0, 1, 2}\
    for idx, theFaction in pairs(factions) do \
        local players = coalition.getPlayers(theFaction)\
        for idy, theUnit in pairs(players) do \
            callBack(theUnit)\
        end\
    end\
end\
\
--\
-- SEMAPHORES\
--\
dcsCommon.semaphores = {}\
\
-- replacement for trigger.misc.getUserFlag\
function dcsCommon.getUserFlag(flagName)\
    if dcsCommon.semaphores[flagName] then \
        return dcsCommon.semaphores[flagName]\
    end\
    \
    return trigger.misc.getUserFlag(flagName)\
end\
\
-- replacement for trigger.action.setUserFlag \
function dcsCommon.setUserFlag(flagName, theValue)\
    -- not yet connected: semaphores\
    \
    -- forget semaphore content if new value is old-school \
    if type(theValue) == \"number\" then \
        dcsCommon.semaphores[theValue] = nil --return to old-school \
    end\
    trigger.action.setUserFlag(flagName, theValue)\
end\
\
--\
--\
-- INIT\
--\
--\
    -- init any variables, tables etc that the lib requires internally\
    function dcsCommon.init()\
        cbID = 0\
        -- create ID tables\
        dcsCommon.collectMissionIDs()\
        \
        --dcsCommon.uuIdent = 0\
        if (dcsCommon.verbose) or true then\
          trigger.action.outText(\"dcsCommon v\" .. dcsCommon.version .. \" loaded\", 10)\
        end\
    end\
\
    \
-- do init. \
dcsCommon.init()\
\
",
                    ["predicate"] = "a_do_script",
                }, -- end of [1]
                [2] = 
                {
                    ["text"] = "cfxZones = {}\
cfxZones.version = \"3.1.2\"\
\
-- cf/x zone management module\
-- reads dcs zones and makes them accessible and mutable \
-- by scripting.\
--\
-- Copyright (c) 2021, 2022 by Christian Franz and cf/x AG\
--\
\
--[[-- 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\
 - 2.4.11 - removed typo in get closest zone \
 - 2.4.12 - getStringFromZoneProperty\
 - 2.5.0  - harden getZoneProperty and all getPropertyXXXX\
 - 2.5.1  - markZoneWithSmoke supports alt attribute \
 - 2.5.2  - getPoint also writes through to zone itself for optimization\
          - new method getPositiveRangeFromZoneProperty(theZone, theProperty, default)\
 - 2.5.3  - new getAllGroupsInZone()\
 - 2.5.4  - cleaned up getZoneProperty break on no properties \
          - extractPropertyFromDCS trims key and property \
 - 2.5.5  - pollFlag() centralized for banging \
          - allStaticsInZone\
 - 2.5.6  - flag accessor setFlagValue(), getFlagValue()  \
          - pollFlag supports theZone as final parameter\
          - randomDelayFromPositiveRange\
          - isMEFlag\
 - 2.5.7  - pollFlag supports dml flags\
 - 2.5.8  - flagArrayFromString\
          - getFlagNumber invokes tonumber() before returning result \
 - 2.5.9  - removed pass-back flag in getPoint() \
 - 2.6.0  - testZoneFlag() method based flag testing\
 - 2.6.1  - Watchflag parsing of zone condition for number-named flags\
          - case insensitive\
          - verbose for zone-local accepted (but not acted upon)\
          - hasProperty now offers active information when looking for '*?' and '*!'\
 - 2.7.0  - doPollFlag - fully support multiple flags per bang!\
 - 2.7.1  - setFlagValueMult()\
 - 2.7.2  - '261 repair'\
 - 2.7.3  - testZoneFlag returns mathodResult, lastVal\
          - evalFlagMethodImmediate()\
 - 2.7.4  - doPollFlag supports immediate number setting \
 - 2.7.5  - more QoL checks when mixing up ? and ! for attributes\
 - 2.7.6  - trim for getBoolFromZoneProperty and getStringFromZoneProperty\
 - 2.7.7  - randomInRange()\
          - show number of zones \
 - 2.7.8  - inc method now triggers if curr value > last value \
          - dec method noew triggers when curr value < last value \
          - testFlagByMethodForZone supports lohi, hilo transitions \
          - doPollFlag supports 'pulse'\
          - pulseFlag\
          - unpulse \
- 2.7.9   - getFlagValue QoL for <none>\
          - setFlagValue QoL for <none>\
- 2.8.0      - new allGroupNamesInZone()\
- 2.8.1   - new zonesLinkedToUnit()  \
- 2.8.2   - flagArrayFromString trims elements before range check \
- 2.8.3   - new verifyMethod()\
          - changed extractPropertyFromDCS() to also match attributes with blanks like \"the Attr\" to \"theAttr\"\
          - new expandFlagName()\
- 2.8.4   - fixed bug in setFlagValue()\
- 2.8.5   - createGroundUnitsInZoneForCoalition() now always passes back a copy of the group data \
          - data also contains cty = country and cat = category for easy spawn\
          - getFlagValue additional zone name guards \
- 2.8.6   - fix in getFlagValue for missing delay \
- 2.8.7   - update isPointInsideZone(thePoint, theZone, radiusIncrease) - new radiusIncrease\
          - isPointInsideZone() returns delta as well\
- 2.9.0   - linked zones can useOffset and useHeading \
          - getPoint update \
          - pointInZone understands useOrig\
          - allStaticsInZone supports useOrig \
          - dPhi for zones with useHeading \
          - uHdg for zones with useHading, contains linked unit's original heading\
          - Late-linking implemented:\
          - linkUnit works for late-activating units \
          - linkUnit now also works for player / clients, dynamic (re-)linking \
          - linkUnit uses zone's origin for all calculations \
- 2.9.1   - new evalRemainder()\
          - pollFlag supports +/- for immediate numbers, flags, number flags in parantheses\
          - stronger guards in hasProperty \
- 2.9.2   - new createRandomPointInPolyZone()\
          - createRandomZoneInZone uses createRandomPointInPolyZone\
          - new createRandomPointInZone()\
          - new randomPointInZone()\
- 3.0.0   - support for DCS 2.8 linkUnit attribute, integration with \
            linedUnit and warning.\
          - initZoneVerbosity()\
- 3.0.1   - updateMovingZones() better tracks linked units by name\
- 3.0.2   - maxRadius for all zones, only differs from radius in polyZones \
          - re-factoring zone-base string processing from messenger module\
          - new processStringWildcards() that does almost all that messenger can \
- 3.0.3   - new getLinkedUnit()\
- 3.0.4   - new createRandomPointOnZoneBoundary()\
- 3.0.5   - getPositiveRangeFromZoneProperty() now also supports upper bound (optional)\
- 3.0.6   - new createSimplePolyZone()\
          - new createSimpleQuadZone()\
- 3.0.7   - getPoint() can also get land y when passing true as second param\
- 3.0.8   - new cfxZones.pointInOneOfZones(thePoint, zoneArray, useOrig) \
- 3.0.9   - new getFlareColorStringFromZoneProperty()\
- 3.1.0      - new getRGBVectorFromZoneProperty()\
            new getRGBAVectorFromZoneProperty()\
- 3.1.1   - getRGBAVectorFromZoneProperty now supports #RRGGBBAA and #RRGGBB format \
          - owner for all, default 0 \
- 3.1.2   - getAllZoneProperties has numbersOnly option \
\
--]]--\
cfxZones.verbose = false\
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 retrieve 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, while 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. \
            -- WARNING: ME linked zones have a relative x any y \
            --          to the linked unit \
            if dcsZone.linkUnit then \
                -- calculate the zone's real position by accessing the unit's MX data \
                -- as precached by dcsCommon\
                local ux, uy = dcsCommon.getUnitStartPosByID(dcsZone.linkUnit)\
                newZone.point = cfxZones.createPoint(ux + dcsZone.x, 0, uy + dcsZone.y)\
                newZone.dcsOrigin = cfxZones.createPoint(ux + dcsZone.x, 0, uy + dcsZone.y)\
            else \
                newZone.point = cfxZones.createPoint(dcsZone.x, 0, dcsZone.y)\
                newZone.dcsOrigin = cfxZones.createPoint(dcsZone.x, 0, dcsZone.y)\
            end\
\
            -- 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\
                newZone.maxRadius = newZone.radius -- same for circular\
    \
            elseif zoneType == 2 then\
                -- polyZone\
                newZone.isPoly = true \
                newZone.radius = dcsZone.radius -- radius is still written in DCS, may change later. The radius has no meaning and is the last radius written before zone changed to poly.\
                -- note that newZone.point is only inside the tone for \
                -- convex polys, and DML only correctly works with convex polys\
                -- now transfer all point in the poly\
                -- note: DCS in 2.7 misspells vertices as 'verticies'\
                -- correct for this \
                newZone.maxRadius = 0\
                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\
                    -- measure distance from zone's point, and store maxRadius \
                    -- dcs always saves a point with the poly zone \
                    local dist = dcsCommon.dist(newZone.point, polyPoint)\
                    if dist > newZone.maxRadius then newZone.maxRadius = dist end \
                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!!!\
            --trigger.action.outText(\"znd: procced \" .. newZone.name .. \" with radius \" .. newZone.radius, 30)\
        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])\
        \
        local pRad = dcsCommon.dist(theZone.point, poly[1]) -- rRad is radius for polygon from theZone.point \
        \
        -- 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 \
            local dp = dcsCommon.dist(theZone.point, vertex)\
            if dp > pRad then pRad = dp end -- find largst distance to vertex\
        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 \
        -- store pRad \
        theZone.pRad = pRad -- not sure we'll ever need that, but at least we have it\
--        trigger.action.outText(\"+++Zones: poly zone <\" .. theZone.name .. \"> has pRad = \" .. pRad, 30) -- remember to remove me \
    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\
    -- handle xz only \
    if inPoint.z then \
        newPoint.z = inPoint.z \
    else \
        newPoint.z = inPoint.y \
    end\
    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)\
    -- warning: bounds do not move woth zone! may have to be updated\
    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.createRandomPointOnZoneBoundary(theZone)\
    if not theZone then return nil end \
    if theZone.isPoly then \
        local loc, dx, dy = cfxZones.createRandomPointInPolyZone(theZone, true)\
        return loc, dx, dy \
    else \
        local loc, dx, dy = cfxZones.createRandomPointInCircleZone(theZone, true)\
        return loc, dx, dy \
    end\
end\
\
function cfxZones.createRandomPointInZone(theZone)\
    if not theZone then return nil end \
    if theZone.isPoly then \
        local loc, dx, dy = cfxZones.createRandomPointInPolyZone(theZone)\
        return loc, dx, dy \
    else \
        local loc, dx, dy = cfxZones.createRandomPointInCircleZone(theZone)\
        return loc, dx, dy \
    end\
end\
\
function cfxZones.randomPointInZone(theZone)\
    local loc, dx, dy =  cfxZones.createRandomPointInZone(theZone)\
    return loc, dx, dy \
end\
\
function cfxZones.createRandomPointInCircleZone(theZone, onEdge)\
    if not theZone.isCircle then \
        trigger.action.outText(\"+++Zones: warning - createRandomPointInCircleZone called for non-circle zone <\" .. theZone.name .. \">\", 30)\
        return {x=theZone.point.x, y=0, z=theZone.point.z}\
    end\
    \
    -- ok, let's first create a random percentage value for the new radius\
    -- now lets get a random degree\
    local degrees = math.random() * 2 * 3.14152 -- radiants. \
    local r = theZone.radius \
    if not onEdge then \
        r = r * math.random()\
    end \
    local p = cfxZones.getPoint(theZone) -- force update of zone if linked\
    local dx = r * math.cos(degrees)\
    local dz = r * math.sin(degrees)\
    local px = p.x + dx -- r * math.cos(degrees)\
    local pz = p.z + dz -- r * math.sin(degrees)\
    return {x=px, y=0, z = pz}, dx, dz -- returns loc and offsets to theZone.point\
end\
\
function cfxZones.createRandomPointInPolyZone(theZone, onEdge)\
    if not theZone.isPoly then \
        trigger.action.outText(\"+++Zones: warning - createRandomPointInPolyZone called for non-poly zone <\" .. theZone.name .. \">\", 30)\
        return cfxZones.createPoint(theZone.point.x, 0, theZone.point.z)\
    end\
    -- force update of all points \
    local p = cfxZones.getPoint(theZone)\
    \
    -- point in convex poly: choose two different lines from that polygon \
    local lineIdxA = dcsCommon.smallRandom(#theZone.poly)\
    repeat lineIdxB = dcsCommon.smallRandom(#theZone.poly) until (lineIdxA ~= lineIdxB)\
    \
    -- we now have two different lines. pick a random point on each. \
    -- we use lerp to pick any point between a and b \
    local a = theZone.poly[lineIdxA]\
    lineIdxA = lineIdxA + 1 -- get next point in poly and wrap around\
    if lineIdxA > #theZone.poly then lineIdxA = 1 end \
    local b = theZone.poly[lineIdxA] \
    local randompercent = math.random()\
    local sourceA = dcsCommon.vLerp (a, b, randompercent)\
    -- if all we want is a point on an edge, we are done \
    if onEdge then \
        local polyPoint = sourceA\
        return polyPoint, polyPoint.x - p.x, polyPoint.z - p.z -- return loc, dx, dz \
    end \
    \
    -- now get point on second line \
    a = theZone.poly[lineIdxB]\
    lineIdxB = lineIdxB + 1 -- get next point in poly and wrap around\
    if lineIdxB > #theZone.poly then lineIdxB = 1 end \
    b = theZone.poly[lineIdxB] \
    randompercent = math.random()\
    local sourceB = dcsCommon.vLerp (a, b, randompercent)\
    \
    -- now take a random point on that line that entirely \
    -- runs through the poly \
    randompercent = math.random()\
    local polyPoint = dcsCommon.vLerp (sourceA, sourceB, randompercent)\
    return polyPoint, polyPoint.x - p.x, polyPoint.z - p.z -- return loc, dx, dz \
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.createSimplePolyZone(name, location, points, addToManaged)\
    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.createPolyZone(name, points)\
    \
    if addToManaged then \
        cfxZones.addZoneToManagedZones(newZone)\
    end\
    return newZone\
end\
\
function cfxZones.createSimpleQuadZone(name, location, points, addToManaged)\
    if not location then \
        location = {}\
    end\
    if not location.x then location.x = 0 end \
    if not location.z then location.z = 0 end \
        \
    -- synthesize 4 points if they don't exist\
    -- remember: in DCS positive x is up, positive z is right \
    if not points then \
        points = {} \
    end\
    if not points[1] then \
        -- upper left \
        points[1] = {x = location.x-1, y = 0, z = location.z-1}\
    end\
    if not points[2] then \
        -- upper right \
        points[2] = {x = location.x-1, y = 0, z = location.z+1}\
    end\
    if not points[3] then \
        -- lower right \
        points[3] = {x = location.x+1, y = 0, z = location.z+1}\
    end\
    if not points[4] then \
        -- lower left \
        points[4] = {x = location.x+1, y = 0, z = location.z-1}\
    end\
    \
    return cfxZones.createSimplePolyZone(name, location, points, addToManaged)\
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.\
    -- entirelyInside is not guaranteed for polyzones\
    \
--    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.\
        --[[ replaced by new code \
        \
        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: emergency brake for inZone\" .. inZone.name,  10)\
                break\
            end\
        until cfxZones.isPointInsidePoly(newPoint, inZone.poly)\
        --]]--\
        local newPoint = cfxZones.createRandomPointInPolyZone(inZone)\
        -- 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, radiusIncrease)\
    -- radiusIncrease only works for circle zones \
    if not radiusIncrease then radiusIncrease = 0 end \
    local p = {x=thePoint.x, y = 0, z = thePoint.z} -- zones have no altitude\
    if (theZone.isCircle) then \
        local zp = cfxZones.getPoint(theZone)\
        local d = dcsCommon.dist(p, theZone.point)\
        return d < theZone.radius + radiusIncrease, d \
    end \
    \
    if (theZone.isPoly) then \
        --trigger.action.outText(\"zne: isPointInside: \" .. theZone.name .. \" is Polyzone!\", 30)\
        return (cfxZones.isPointInsidePoly(p, theZone.poly)), 0 -- always returns delta 0\
    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.allGroupsInZone(theZone, categ) -- categ is optional, must be code \
    -- warning: does not check for exiting!\
    --trigger.action.outText(\"Zone \" .. theZone.name .. \" radius \" .. theZone.radius, 30)\
    local inZones = {}\
    local coals = {0, 1, 2} -- all coalitions\
    for idx, coa in pairs(coals) do \
        local allGroups = coalition.getGroups(coa, categ)\
        for key, group in pairs(allGroups) do -- iterate all groups\
            if cfxZones.isGroupPartiallyInZone(group, theZone) then\
                table.insert(inZones, group)\
            end\
        end\
    end\
    return inZones\
end\
\
function cfxZones.allGroupNamesInZone(theZone, categ) -- categ is optional, must be code \
    -- warning: does not check for exiting!\
    --trigger.action.outText(\"Zone \" .. theZone.name .. \" radius \" .. theZone.radius, 30)\
    local inZones = {}\
    local coals = {0, 1, 2} -- all coalitions\
    for idx, coa in pairs(coals) do \
        local allGroups = coalition.getGroups(coa, categ)\
        for key, group in pairs(allGroups) do -- iterate all groups\
            if cfxZones.isGroupPartiallyInZone(group, theZone) then\
                table.insert(inZones, group:getName())\
            end\
        end\
    end\
    return inZones\
end\
\
function cfxZones.allStaticsInZone(theZone, useOrigin) -- categ is optional, must be code \
    -- warning: does not check for exiting!\
    local inZones = {}\
    local coals = {0, 1, 2} -- all coalitions\
    for idx, coa in pairs(coals) do \
        local allStats = coalition.getStaticObjects(coa)\
        for key, statO in pairs(allStats) do -- iterate all groups\
            local oP = statO:getPoint()\
            if useOrigin then \
                if cfxZones.pointInZone(oP, theZone, true) then \
                    -- use DCS original coords\
                    table.insert(inZones, statO)\
                end\
            elseif cfxZones.pointInZone(oP, theZone) then\
                table.insert(inZones, statO)\
            end\
        end\
    end\
    return inZones\
end\
\
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)            \
            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 \
        \
    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()\
            local inzone, percent, dist = cfxZones.pointInZone(p, aZone)\
            if inzone then -- cfxZones.isPointInsideZone(p, aZone) then             \
                --trigger.action.outText(\"zne: YAY <\" .. aUnit:getName() .. \"> IS IN \" .. aZone.name, 30) \
                return true\
            end \
            --trigger.action.outText(\"zne: <\" .. aUnit:getName() .. \"> not in \" .. aZone.name .. \", dist = \" .. dist .. \", rad = \", aZone.radius, 30) \
        end\
    end\
    return false\
end\
\
function cfxZones.isEntireGroupInZone(aGroup, aZone)\
    if not aGroup then return false end \
    if not aZone then return false end \
    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 \
        if not aZone then \
            trigger.action.outText(\"+++zone: nil aZone for \" .. k, 30)\
        else \
            local lU = cfxZones.getZoneProperty(aZone, propertyName)\
            if lU then \
                table.insert(theZones, aZone)\
            end\
        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 lPoint = {x=point.x, y=0, z=point.z}\
    local currDelta = math.huge \
    local closestZone = nil\
    for zName, zData in pairs(theZones) do \
        local zPoint = cfxZones.getPoint(zData)\
        local delta = dcsCommon.dist(lPoint, zPoint) -- emulate flag compare \
        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, alt)\
    if not alt then alt = 5 end \
    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}) + alt\
    -- 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, alt)\
    local rads = degrees * math.pi / 180\
    local dx = radius * math.sin(rads)\
    local dz = radius * math.cos(rads)\
    cfxZones.markZoneWithSmoke(theZone, dx, dz, smokeColor, alt)\
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\
\
function cfxZones.pointInOneOfZones(thePoint, zoneArray, useOrig) \
    if not zoneArray then zoneArray = cfxZones.zones end \
    for idx, theZone in pairs(zoneArray) do \
        local isIn, percent, dist = cfxZones.pointInZone(thePoint, theZone, useOrig)\
        if isIn then return isIn, percent, dist, theZone end \
    end\
    return false, 0, 0, nil \
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, useOrig)\
\
    if not (theZone) then return false, 0, 0 end\
        \
    local pflat = {x = thePoint.x, y = 0, z = thePoint.z}\
    \
    local zpoint \
    if useOrig then\
        zpoint = cfxZones.getDCSOrigin(theZone)\
    else \
        zpoint = cfxZones.getPoint(theZone) -- updates zone if linked \
    end\
    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)\
    -- store cty and cat for later access. DCS doesn't need it, but we may \
    \
    theGroup.cty = theSideCJTF\
    theGroup.cat = Group.Category.GROUND\
    \
    -- create a copy of the group data for \
    -- later reference \
    local groupDataCopy = dcsCommon.clone(theGroup)\
\
    local newGroup = coalition.addGroup(theSideCJTF, Group.Category.GROUND, theGroup)\
    return newGroup, groupDataCopy\
end\
\
--\
-- ===============\
-- FLAG PROCESSING \
-- ===============\
--\
\
--\
-- Flag Pulling \
--\
function cfxZones.pulseFlag(theFlag, method, theZone)\
    local args = {}\
    args.theFlag = theFlag\
    args.method = method\
    args.theZone = theZone \
    local delay = 3\
    if dcsCommon.containsString(method, \",\") then \
        local parts = dcsCommon.splitString(method, \",\")\
        delay = parts[2]\
        if delay then delay = tonumber(delay) end  \
    end\
    if not delay then delay = 3 end \
    if theZone.verbose then \
        trigger.action.outText(\"+++zne: RAISING pulse t=\"..delay..\" for flag <\" .. theFlag .. \"> in zone <\" .. theZone.name ..\">\", 30)\
    end \
    local newVal = 1\
    cfxZones.setFlagValue(theFlag, newVal, theZone)\
    \
    -- schedule second half of pulse \
    timer.scheduleFunction(cfxZones.unPulseFlag, args, timer.getTime() + delay)\
end\
\
function cfxZones.unPulseFlag(args)\
    local theZone = args.theZone\
    local method = args.method \
    local theFlag = args.theFlag \
    local newVal = 0\
    -- we may later use method to determine pulse direction / newVal\
    -- for now, we always go low \
    if theZone.verbose then \
        trigger.action.outText(\"+++zne: DOWNPULSE pulse for flag <\" .. theFlag .. \"> in zone <\" .. theZone.name ..\">\", 30)\
    end\
    cfxZones.setFlagValue(theFlag, newVal, theZone)\
end\
\
function cfxZones.evalRemainder(remainder)\
    local rNum = tonumber(remainder)\
    if not rNum then \
        -- we use remainder as name for flag \
        -- PROCESS ESCAPE SEQUENCES\
        local esc = string.sub(remainder, 1, 1)\
        local last = string.sub(remainder, -1)\
        if esc == \"@\" then \
            remainder = string.sub(remainder, 2)\
            remainder = dcsCommon.trim(remainder)\
        end\
        \
        if esc == \"(\" and last == \")\" and string.len(remainder) > 2 then \
            -- note: iisues with startswith(\"(\") ???\
            remainder = string.sub(remainder, 2, -2)\
            remainder = dcsCommon.trim(remainder)        \
        end\
        if esc == \"\\\"\" and last == \"\\\"\" and string.len(remainder) > 2 then \
            remainder = string.sub(remainder, 2, -2)\
            remainder = dcsCommon.trim(remainder)        \
        end\
        if cfxZones.verbose then \
            trigger.action.outText(\"+++zne: accessing flag <\" .. remainder .. \">\", 30)\
        end \
        rNum = cfxZones.getFlagValue(remainder, theZone)\
    end \
    return rNum\
end\
\
function cfxZones.doPollFlag(theFlag, method, theZone)\
    if cfxZones.verbose then \
        trigger.action.outText(\"+++zones: polling flag \" .. theFlag .. \" with \" .. method, 30)\
    end \
    \
    if not theZone then \
        trigger.action.outText(\"+++zones: nil theZone on pollFlag\", 30)\
    end\
    \
    method = method:lower()\
    method = dcsCommon.trim(method)\
    val = tonumber(method)\
    if dcsCommon.stringStartsWith(method, \"+\") or dcsCommon.stringStartsWith(method, \"-\")\
    then \
        -- skip this processing, a legal Lua val can start with \"+\" or \"-\"\
        -- but we interpret it as a method\
    else\
        if val then \
            cfxZones.setFlagValue(theFlag, val, theZone)\
            if cfxZones.verbose or theZone.verbose then\
                trigger.action.outText(\"+++zones: flag <\" .. theFlag .. \"> changed to #\" .. val, 30)\
            end \
            return\
        end \
    end\
    --trigger.action.outText(\"+++zones: polling \" .. theZone.name .. \" method \" .. method .. \" flag \" .. theFlag, 30)\
    local currVal = cfxZones.getFlagValue(theFlag, theZone)\
    if method == \"inc\" or method == \"f+1\" then \
        --trigger.action.setUserFlag(theFlag, currVal + 1)\
        cfxZones.setFlagValue(theFlag, currVal+1, theZone)\
        \
    elseif method == \"dec\" or method == \"f-1\" then \
        -- trigger.action.setUserFlag(theFlag, currVal - 1)\
        cfxZones.setFlagValue(theFlag, currVal-1, theZone)\
\
    elseif method == \"off\" or method == \"f=0\" then \
        -- trigger.action.setUserFlag(theFlag, 0)\
        cfxZones.setFlagValue(theFlag, 0, theZone)\
\
    elseif method == \"flip\" or method == \"xor\" then \
        if currVal ~= 0 then \
--            trigger.action.setUserFlag(theFlag, 0)\
            cfxZones.setFlagValue(theFlag, 0, theZone)\
\
        else \
            --trigger.action.setUserFlag(theFlag, 1)\
            cfxZones.setFlagValue(theFlag, 1, theZone)\
        end\
        \
    elseif dcsCommon.stringStartsWith(method, \"pulse\") then \
        cfxZones.pulseFlag(theFlag, method, theZone)\
        \
    elseif dcsCommon.stringStartsWith(method, \"+\") then \
        -- we add whatever is to the right \
        local remainder = dcsCommon.removePrefix(method, \"+\")\
        local adder = cfxZones.evalRemainder(remainder)\
        cfxZones.setFlagValue(theFlag, currVal+adder, theZone)\
        if theZone.verbose then \
            trigger.action.outText(\"+++zones: (poll) updating with '+' flag <\" .. theFlag .. \"> in <\" .. theZone.name .. \"> by <\" .. adder .. \"> to <\" .. adder + currVal .. \">\", 30)\
        end\
        \
    elseif dcsCommon.stringStartsWith(method, \"-\") then \
        -- we subtract whatever is to the right \
        local remainder = dcsCommon.removePrefix(method, \"-\")\
        local adder = cfxZones.evalRemainder(remainder)\
        cfxZones.setFlagValue(theFlag, currVal-adder, theZone)\
\
    else \
        if method ~= \"on\" and method ~= \"f=1\" then \
            trigger.action.outText(\"+++zones: unknown method <\" .. method .. \"> - using 'on'\", 30)\
        end\
        -- default: on.\
--        trigger.action.setUserFlag(theFlag, 1)\
        cfxZones.setFlagValue(theFlag, 1, theZone)\
    end\
    \
    if cfxZones.verbose then\
        local newVal = cfxZones.getFlagValue(theFlag, theZone)\
        trigger.action.outText(\"+++zones: flag <\" .. theFlag .. \"> changed from \" .. currVal .. \" to \" .. newVal, 30)\
    end \
end\
\
function cfxZones.pollFlag(theFlag, method, theZone) \
    local allFlags = {}\
    if dcsCommon.containsString(theFlag, \",\") then \
        if cfxZones.verbose then \
            trigger.action.outText(\"+++zones: will poll flag set <\" .. theFlag .. \"> with \" .. method, 30)\
        end\
        allFlags = dcsCommon.splitString(theFlag, \",\")\
    else \
        table.insert(allFlags, theFlag)\
    end\
    \
    for idx, aFlag in pairs(allFlags) do \
        aFlag = dcsCommon.trim(aFlag)\
        -- note: mey require range preprocessing, but that's not\
        -- a priority \
        cfxZones.doPollFlag(aFlag, method, theZone)\
    end \
    \
end\
\
function cfxZones.expandFlagName(theFlag, theZone) \
    if not theFlag then return \"!NIL\" end \
    local zoneName = \"<dummy>\"\
    if theZone then \
        zoneName = theZone.name -- for flag wildcards\
    end\
    \
    if type(theFlag) == \"number\" then \
        -- straight number, return \
        return theFlag\
    end\
    \
    -- we assume it's a string now\
    theFlag = dcsCommon.trim(theFlag) -- clear leading/trailing spaces\
    local nFlag = tonumber(theFlag) \
    if nFlag then -- a number, legal\
        return theFlag\
    end\
        \
    -- now do wildcard processing. we have alphanumeric\
    if dcsCommon.stringStartsWith(theFlag, \"*\") then  \
        theFlag = zoneName .. theFlag\
    end\
    return theFlag\
end\
\
function cfxZones.setFlagValueMult(theFlag, theValue, theZone)\
    local allFlags = {}\
    if dcsCommon.containsString(theFlag, \",\") then \
        if cfxZones.verbose then \
            trigger.action.outText(\"+++zones: will multi-set flags <\" .. theFlag .. \"> to \" .. theValue, 30)\
        end\
        allFlags = dcsCommon.splitString(theFlag, \",\")\
    else \
        table.insert(allFlags, theFlag)\
    end\
    \
    for idx, aFlag in pairs(allFlags) do \
        aFlag = dcsCommon.trim(aFlag)\
        -- note: mey require range preprocessing, but that's not\
        -- a priority \
        cfxZones.setFlagValue(aFlag, theValue, theZone)\
    end \
end\
\
function cfxZones.setFlagValue(theFlag, theValue, theZone)\
    local zoneName = \"<dummy>\"\
    if not theZone then \
        trigger.action.outText(\"+++Zne: no zone on setFlagValue\", 30) -- mod me for detector\
    else \
        zoneName = theZone.name -- for flag wildcards\
    end\
    \
    if type(theFlag) == \"number\" then \
        -- straight set, ME flag \
        trigger.action.setUserFlag(theFlag, theValue)\
        return \
    end\
    \
    -- we assume it's a string now\
    theFlag = dcsCommon.trim(theFlag) -- clear leading/trailing spaces\
    local nFlag = tonumber(theFlag) \
    if nFlag then \
        trigger.action.setUserFlag(theFlag, theValue)\
        return \
    end\
    \
    -- some QoL: detect \"<none>\"\
    if dcsCommon.containsString(theFlag, \"<none>\") then \
        trigger.action.outText(\"+++Zone: warning - setFlag has '<none>' flag name in zone <\" .. zoneName .. \">\", 30) -- if error, intended break\
    end\
    \
    -- now do wildcard processing. we have alphanumeric\
    if dcsCommon.stringStartsWith(theFlag, \"*\") then  \
        theFlag = zoneName .. theFlag\
    end\
    trigger.action.setUserFlag(theFlag, theValue)\
end \
\
function cfxZones.getFlagValue(theFlag, theZone)\
    local zoneName = \"<dummy>\"\
    if not theZone or not theZone.name then \
        trigger.action.outText(\"+++Zne: no zone or zone name on getFlagValue\", 30)\
    else \
        zoneName = theZone.name -- for flag wildcards\
    end\
    \
    if type(theFlag) == \"number\" then \
        -- straight get, ME flag \
        return tonumber(trigger.misc.getUserFlag(theFlag))\
    end\
    \
    -- we assume it's a string now\
    theFlag = dcsCommon.trim(theFlag) -- clear leading/trailing spaces\
    local nFlag = tonumber(theFlag) \
    if nFlag then \
        return tonumber(trigger.misc.getUserFlag(theFlag))\
    end\
    \
    -- some QoL: detect \"<none>\"\
    if dcsCommon.containsString(theFlag, \"<none>\") then \
        trigger.action.outText(\"+++Zone: warning - getFlag has '<none>' flag name in zone <\" .. zoneName .. \">\", 30) -- break here\
    end\
    \
    -- now do wildcard processing. we have alphanumeric\
    if dcsCommon.stringStartsWith(theFlag, \"*\") then  \
            theFlag = zoneName .. theFlag\
    end\
    return tonumber(trigger.misc.getUserFlag(theFlag))\
end\
\
function cfxZones.isMEFlag(inFlag)\
    -- do NOT use me\
    trigger.action.outText(\"+++zne: warning: deprecated isMEFlag\", 30)\
    return true \
    -- returns true if inFlag is a pure positive number\
end\
\
function cfxZones.verifyMethod(theMethod, theZone)\
    local lMethod = string.lower(theMethod)\
    if lMethod == \"#\" or lMethod == \"change\" then \
        return true\
    end\
\
    if lMethod == \"0\" or lMethod == \"no\" or lMethod == \"false\" \
       or lMethod == \"off\" then \
        return true  \
    end\
    \
    if lMethod == \"1\" or lMethod == \"yes\" or lMethod == \"true\" \
       or lMethod == \"on\" then \
        return true  \
    end\
    \
    if lMethod == \"inc\" or lMethod == \"+1\" then \
        return true\
    end\
    \
    if lMethod == \"dec\" or lMethod == \"-1\" then \
        return true \
    end \
    \
    if lMethod == \"lohi\" or lMethod == \"pulse\" then \
        return true\
    end\
    \
    if lMethod == \"hilo\" then \
        return true\
    end\
    \
    -- number constraints\
    -- or flag constraints     -- ONLY RETURN TRUE IF CHANGE AND CONSTRAINT MET \
    local op = string.sub(theMethod, 1, 1) \
    local remainder = string.sub(theMethod, 2)\
    remainder = dcsCommon.trim(remainder) -- remove all leading and trailing spaces\
\
    if true then \
        -- we have a comparison = \">\", \"=\", \"<\" followed by a number \
        -- THEY TRIGGER EACH TIME lastVal <> currVal AND condition IS MET  \
        if op == \"=\" then \
            return true\
        end\
        \
        if op == \"#\" or op == \"~\" then \
            return true\
        end \
        \
        if op == \"<\" then \
            return true\
        end\
        \
        if op == \">\" then \
            return true\
        end\
    end\
    \
    return false \
end\
\
-- method-based flag testing \
function cfxZones.evalFlagMethodImmediate(currVal, theMethod, theZone)\
    -- immediate eval - does not look at last val. \
    -- return true/false/value based on theMethod's contraints \
    -- simple constraints\
    local lMethod = string.lower(theMethod)\
    if lMethod == \"#\" or lMethod == \"change\" then \
        -- ALWAYS RETURNS TRUE for currval <> 0, flase if currval = 0\
        return currVal ~= 0  \
    end\
    \
    if lMethod == \"0\" or lMethod == \"no\" or lMethod == \"false\" \
       or lMethod == \"off\" then \
        -- WARNING: ALWAYS RETURNS FALSE\
        return false  \
    end\
    \
    if lMethod == \"1\" or lMethod == \"yes\" or lMethod == \"true\" \
       or lMethod == \"on\" then \
        -- WARNING: ALWAYS RETURNS TRUE\
        return true  \
    end\
    \
    if lMethod == \"inc\" or lMethod == \"+1\" then \
        return currVal+1 -- this may be unexpected\
    end\
    \
    if lMethod == \"dec\" or lMethod == \"-1\" then \
        return currVal-1 -- this may be unexpectd\
    end \
    \
    -- number constraints\
    -- or flag constraints \
    -- ONLY RETURN TRUE IF CHANGE AND CONSTRAINT MET \
    local op = string.sub(theMethod, 1, 1) \
    local remainder = string.sub(theMethod, 2)\
    remainder = dcsCommon.trim(remainder) -- remove all leading and trailing spaces\
    local rNum = tonumber(remainder)\
    if not rNum then \
        -- we use remainder as name for flag \
        -- PROCESS ESCAPE SEQUENCES\
        local esc = string.sub(remainder, 1, 1)\
        local last = string.sub(remainder, -1)\
        if esc == \"@\" then \
            remainder = string.sub(remainder, 2)\
            remainder = dcsCommon.trim(remainder)\
        end\
        \
        if esc == \"(\" and last == \")\" and string.len(remainder) > 2 then \
            -- note: iisues with startswith(\"(\") ???\
            remainder = string.sub(remainder, 2, -2)\
            remainder = dcsCommon.trim(remainder)        \
        end\
        if esc == \"\\\"\" and last == \"\\\"\" and string.len(remainder) > 2 then \
            remainder = string.sub(remainder, 2, -2)\
            remainder = dcsCommon.trim(remainder)        \
        end\
        if cfxZones.verbose then \
            trigger.action.outText(\"+++zne: accessing flag <\" .. remainder .. \">\", 30)\
        end \
        rNum = cfxZones.getFlagValue(remainder, theZone)\
    end \
    if rNum then \
        -- we have a comparison = \">\", \"=\", \"<\" followed by a number  \
        if op == \"=\" then \
            return currVal == rNum\
        end\
        \
        if op == \"#\" or op == \"~\" then \
            return currVal ~= rNum \
        end \
        \
        if op == \"<\" then \
            return currVal < rNum\
        end\
        \
        if op == \">\" then \
            return currVal > rNum\
        end\
    end\
    \
    -- if we get here, we have an error \
    local zoneName = \"<NIL>\"\
    if theZone then zoneName = theZone.name end \
    trigger.action.outText(\"+++Zne: illegal |\" .. theMethod .. \"| in eval for zone \" .. zoneName, 30 )\
    return false     \
end\
\
function cfxZones.testFlagByMethodForZone(currVal, lastVal, theMethod, theZone)\
    -- return true/false based on theMethod's contraints \
    -- simple constraints\
    -- ONLY RETURN TRUE IF CHANGE AND CONSTRAINT MET \
    local lMethod = string.lower(theMethod)\
    if lMethod == \"#\" or lMethod == \"change\" then \
        -- check if currVal different from lastVal\
        return currVal ~= lastVal  \
    end\
    \
    if lMethod == \"0\" or lMethod == \"no\" or lMethod == \"false\" \
       or lMethod == \"off\" then \
        -- WARNING: ONLY RETURNS TRUE IF FALSE AND lastval not zero!\
        return currVal == 0 and currVal ~= lastVal  \
    end\
    \
    if lMethod == \"1\" or lMethod == \"yes\" or lMethod == \"true\" \
       or lMethod == \"on\" then \
        -- WARNING: only returns true if lastval was false!!!!\
        return (currVal ~= 0 and lastVal == 0)  \
    end\
    \
    if lMethod == \"inc\" or lMethod == \"+1\" then \
--        return currVal == lastVal+1 -- better: test for greater than \
        return currVal > lastVal\
    end\
    \
    if lMethod == \"dec\" or lMethod == \"-1\" then \
        --return currVal == lastVal-1\
        return currVal < lastVal \
    end \
    \
    if lMethod == \"lohi\" or lMethod == \"pulse\" then \
        return (lastVal <= 0 and currVal > 0)\
    end\
    \
    if lMethod == \"hilo\" then \
        return (lastVal > 0 and currVal <= 0)\
    end\
    \
    -- number constraints\
    -- or flag constraints \
    -- ONLY RETURN TRUE IF CHANGE AND CONSTRAINT MET \
    local op = string.sub(theMethod, 1, 1) \
    local remainder = string.sub(theMethod, 2)\
    remainder = dcsCommon.trim(remainder) -- remove all leading and trailing spaces\
    local rNum = tonumber(remainder)\
    if not rNum then \
        -- we use remainder as name for flag \
        -- PROCESS ESCAPE SEQUENCES\
        local esc = string.sub(remainder, 1, 1)\
        local last = string.sub(remainder, -1)\
        if esc == \"@\" then \
            remainder = string.sub(remainder, 2)\
            remainder = dcsCommon.trim(remainder)\
        end\
        \
        if esc == \"(\" and last == \")\" and string.len(remainder) > 2 then \
            -- note: iisues with startswith(\"(\") ???\
            remainder = string.sub(remainder, 2, -2)\
            remainder = dcsCommon.trim(remainder)        \
        end\
        if esc == \"\\\"\" and last == \"\\\"\" and string.len(remainder) > 2 then \
            remainder = string.sub(remainder, 2, -2)\
            remainder = dcsCommon.trim(remainder)        \
        end\
        if cfxZones.verbose then \
            trigger.action.outText(\"+++zne: accessing flag <\" .. remainder .. \">\", 30)\
        end \
        rNum = cfxZones.getFlagValue(remainder, theZone)\
    end \
    if rNum then \
        -- we have a comparison = \">\", \"=\", \"<\" followed by a number \
        -- THEY TRIGGER EACH TIME lastVal <> currVal AND condition IS MET  \
        if op == \"=\" then \
            return currVal == rNum and lastVal ~= currVal\
        end\
        \
        if op == \"#\" or op == \"~\" then \
            return currVal ~= rNum and lastVal ~= currVal \
        end \
        \
        if op == \"<\" then \
            return currVal < rNum and lastVal ~= currVal\
        end\
        \
        if op == \">\" then \
            return currVal > rNum and lastVal ~= currVal\
        end\
    end\
    \
    -- if we get here, we have an error \
    local zoneName = \"<NIL>\"\
    if theZone then zoneName = theZone.name end \
    trigger.action.outText(\"+++Zne: illegal method constraints |\" .. theMethod .. \"| for zone \" .. zoneName, 30 )\
    return false \
end\
\
\
function cfxZones.testZoneFlag(theZone, theFlagName, theMethod, latchName)\
    -- returns two values: true/false method result, and curr value\
    -- returns true if method constraints are met for flag theFlagName\
    -- as defined by theMethod \
    if not theMethod then \
        theMethod = \"change\"\
    end \
    \
    -- will read and update theZone[latchName] as appropriate \
    if not theZone then \
        trigger.action.outText(\"+++Zne: no zone for testZoneFlag\", 30)\
        return nil, nil \
    end \
    if not theFlagName then \
        -- this is common, no error, only on verbose \
        if cfxZones.verbose then \
            trigger.action.outText(\"+++Zne: no flagName for zone \" .. theZone.name .. \" for testZoneFlag\", 30)\
        end \
        return nil, nil\
    end\
    if not latchName then \
        trigger.action.outText(\"+++Zne: no latchName for zone \" .. theZone.name .. \" for testZoneFlag\", 30)\
        return nil, nil \
    end\
    -- get current value \
    local currVal = cfxZones.getFlagValue(theFlagName, theZone)\
    \
    -- get last value from latch\
    local lastVal = theZone[latchName]\
    if not lastVal then \
        trigger.action.outText(\"+++Zne: latch <\" .. latchName .. \"> not valid for zone \" .. theZone.name, 30) -- intentional break here \
        return nil, nil\
    end\
    \
    -- now, test by method \
    -- we should only test if currVal <> lastVal \
    if currVal == lastVal then\
        return false, currVal\
    end \
    \
    --trigger.action.outText(\"+++Zne: about to test: c = \" .. currVal .. \", l = \" .. lastVal, 30)\
    local testResult = cfxZones.testFlagByMethodForZone(currVal, lastVal, theMethod, theZone)\
\
    -- update latch by method\
    theZone[latchName] = currVal \
\
    -- return result\
    return testResult, currVal\
end\
\
\
\
function cfxZones.flagArrayFromString(inString)\
-- original code from RND flag\
    if string.len(inString) < 1 then \
        trigger.action.outText(\"+++zne: empty flags\", 30)\
        return {} \
    end\
    if cfxZones.verbose then \
        trigger.action.outText(\"+++zne: processing <\" .. inString .. \">\", 30)\
    end \
    \
    local flags = {}\
    local rawElements = dcsCommon.splitString(inString, \",\")\
    -- go over all elements \
    for idx, anElement in pairs(rawElements) do \
        anElement = dcsCommon.trim(anElement)\
        if dcsCommon.stringStartsWithDigit(anElement) and dcsCommon.containsString(anElement, \"-\") then \
            -- interpret this as a range\
            local theRange = dcsCommon.splitString(anElement, \"-\")\
            local lowerBound = theRange[1]\
            lowerBound = tonumber(lowerBound)\
            local upperBound = theRange[2]\
            upperBound = tonumber(upperBound)\
            if lowerBound and upperBound then\
                -- swap if wrong order\
                if lowerBound > upperBound then \
                    local temp = upperBound\
                    upperBound = lowerBound\
                    lowerBound = temp \
                end\
                -- now add add numbers to flags\
                for f=lowerBound, upperBound do \
                    table.insert(flags, tostring(f))\
                end\
            else\
                -- bounds illegal\
                trigger.action.outText(\"+++zne: ignored range <\" .. anElement .. \"> (range)\", 30)\
            end\
        else\
            -- single number\
            f = dcsCommon.trim(anElement) -- DML flag upgrade: accept strings tonumber(anElement)\
            if f then \
                table.insert(flags, f)\
\
            else \
                trigger.action.outText(\"+++zne: ignored element <\" .. anElement .. \"> (single)\", 30)\
            end\
        end\
    end\
    if cfxZones.verbose then \
        trigger.action.outText(\"+++zne: <\" .. #flags .. \"> flags total\", 30)\
    end \
    return flags\
end\
\
--\
-- ===================\
-- PROPERTY PROCESSING\
-- =================== \
--\
\
function cfxZones.getAllZoneProperties(theZone, caseInsensitive, numbersOnly) -- return as dict \
    if not caseInsensitive then caseInsensitive = false end \
    if not numbersOnly then numbersOnly = 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 \
        local v = theProp.value \
        if numbersOnly then \
            v = tonumber(v)\
            if not v then v = 0 end \
        end\
        props[theKey] = v\
    end\
    return props \
end\
\
function cfxZones.extractPropertyFromDCS(theKey, theProperties)\
-- trim\
    theKey = dcsCommon.trim(theKey) \
--    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 = dcsCommon.trim(theP.key)  \
        if not cfxZones.caseSensitiveProperties then \
            existingKey = string.lower(existingKey)\
        end\
        if existingKey == theKey then \
            return theP.value\
        end\
        \
        -- now check after removing all blanks \
        existingKey = dcsCommon.removeBlanks(existingKey)\
        if existingKey == theKey then \
            return theP.value\
        end\
    end\
    return nil \
end\
\
function cfxZones.getZoneProperty(cZone, theKey)\
    if not cZone then \
        trigger.action.outText(\"+++zone: no zone in getZoneProperty\", 30)\
--        breek.here.noew = 1\
        return nil\
    end \
    if not theKey then \
        trigger.action.outText(\"+++zone: no property key in getZoneProperty for zone \" .. cZone.name, 30)\
--        breakme.here = 1\
        return \
    end    \
\
    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 \
        p = dcsCommon.trim(p)\
        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.randomInRange(minVal, maxVal)\
    if maxVal < minVal then \
        local t = minVal\
        minVal = maxVal \
        maxVal = t\
    end\
    return cfxZones.randomDelayFromPositiveRange(minVal, maxVal)\
end\
\
function cfxZones.randomDelayFromPositiveRange(minVal, maxVal) \
    if not maxVal then return minVal end \
    if not minVal then return maxVal end \
    local delay = maxVal\
    if minVal > 0 and minVal < delay then \
        -- we want a randomized from time from minTime .. delay\
        local varPart = delay - minVal + 1\
        varPart = dcsCommon.smallRandom(varPart) - 1\
        delay = minVal + varPart\
    end\
    return delay \
end\
\
function cfxZones.getPositiveRangeFromZoneProperty(theZone, theProperty, default, defaultmax)\
    -- reads property as string, and interprets as range 'a-b'. \
    -- if not a range but single number, returns both for upper and lower \
    --trigger.action.outText(\"***Zne: enter with <\" .. theZone.name .. \">: range for property <\" .. theProperty .. \">!\", 30)\
    if not default then default = 0 end \
    if not defaultmax then defaultmax = default end \
    \
    local lowerBound = default\
    local upperBound = defaultmax \
    \
    local rangeString = cfxZones.getStringFromZoneProperty(theZone, theProperty, \"\")\
    if dcsCommon.containsString(rangeString, \"-\") then \
        local theRange = dcsCommon.splitString(rangeString, \"-\")\
        lowerBound = theRange[1]\
        lowerBound = tonumber(lowerBound)\
        upperBound = theRange[2]\
        upperBound = tonumber(upperBound)\
        if lowerBound and upperBound then\
            -- swap if wrong order\
            if lowerBound > upperBound then \
                local temp = upperBound\
                upperBound = lowerBound\
                lowerBound = temp \
            end\
\
        else\
            -- bounds illegal\
            trigger.action.outText(\"+++Zne: illegal range  <\" .. rangeString .. \">, using \" .. default .. \"-\" .. defaultmax, 30)\
            lowerBound = default\
            upperBound = defaultmax \
        end\
    else \
        upperBound = cfxZones.getNumberFromZoneProperty(theZone, theProperty, defaultmax) -- between pulses \
        lowerBound = upperBound\
    end\
\
    return lowerBound, upperBound\
end\
\
function cfxZones.hasProperty(theZone, theProperty) \
    if not theProperty then \
        trigger.action.outText(\"+++zne: WARNING - hasProperty called with nil theProperty for zone <\" .. theZone.name .. \">\", 30)\
        return false \
    end \
    local foundIt = cfxZones.getZoneProperty(theZone, theProperty)\
    if not foundIt then \
        -- check for possible forgotten or exchanged IO flags \
        if string.sub(theProperty, -1) == \"?\" then\
            local lessOp = theProperty:sub(1,-2)\
            if cfxZones.getZoneProperty(theZone, lessOp) ~= nil then \
                trigger.action.outText(\"*** NOTE: \" .. theZone.name .. \"'s property <\" .. lessOp .. \"> may be missing a Query ('?') symbol\", 30)\
            end\
            local lessPlus = lessOp .. \"!\"\
            if cfxZones.getZoneProperty(theZone, lessPlus) ~= nil then \
                trigger.action.outText(\"*** NOTE: \" .. theZone.name .. \"'s property <\" .. lessOp .. \"> may be using '!' instead of '?' for input\", 30)\
            end\
            return false \
        end\
        \
        if string.sub(theProperty, -1) == \"!\" then \
            local lessOp = theProperty:sub(1,-2)\
            if cfxZones.getZoneProperty(theZone, lessOp) ~= nil then \
                trigger.action.outText(\"*** NOTE: \" .. theZone.name .. \"'s property <\" .. lessOp .. \"> may be missing a Bang! ('!') symbol\", 30)\
            end\
            local lessPlus = lessOp .. \"?\"\
            if cfxZones.getZoneProperty(theZone, lessPlus) ~= nil then \
                trigger.action.outText(\"*** NOTE: \" .. theZone.name .. \"'s property <\" .. lessOp .. \"> may be using '!' instead of '?' for input\", 30)\
            end\
            return false \
        end\
        \
        if string.sub(theProperty, -1) == \":\" then \
            local lessOp = theProperty:sub(1,-2)\
            if cfxZones.getZoneProperty(theZone, lessOp) ~= nil then \
                trigger.action.outText(\"*** NOTE: \" .. theZone.name .. \"'s property <\" .. lessOp .. \"> may be missing a colon (':') at end\", 30)\
            end\
            return false \
        end\
        \
        return false \
    end\
    return true \
--    return foundIt ~= 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() \
    p = dcsCommon.trim(p) \
    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\
\
function cfxZones.getRGBVectorFromZoneProperty(theZone, theProperty, defaultVal)\
    if not defaultVal then defaultVal = {1.0, 1.0, 1.0} end \
    if #defaultVal ~=3 then defaultVal = {1.0, 1.0, 1.0} end\
    local s = cfxZones.getStringFromZoneProperty(theZone, theProperty, \"\")\
    local sVec = dcsCommon.splitString(s, \",\")\
    local nVec = {}\
    for i = 1, 3 do \
        n = sVec[i]\
        if n then n = tonumber(n) end \
        if not n then n = defaultVal[i] end \
        if n > 1.0 then n = 1.0 end\
        if n < 0 then n = 0 end \
        nVec[i] = n\
    end\
        \
    return nVec \
end\
\
function cfxZones.getRGBAVectorFromZoneProperty(theZone, theProperty, defaultVal)\
    if not defaultVal then defaultVal = {1.0, 1.0, 1.0, 1.0} end \
    if #defaultVal ~=4 then defaultVal = {1.0, 1.0, 1.0, 1.0} end\
    local s = cfxZones.getStringFromZoneProperty(theZone, theProperty, \"\")\
    s = dcsCommon.trim(s)\
    if s:sub(1,1) == \"#\" then \
        -- it's probably a \"#RRGGBBAA\" format hex string \
        local hVec = dcsCommon.hexString2RGBA(s)\
        if hVec then return hVec end \
    end\
\
    local sVec = dcsCommon.splitString(s, \",\")\
    local nVec = {}\
    for i = 1, 4 do \
        n = sVec[i]\
        if n then n = tonumber(n) end \
        if not n then n = defaultVal[i] end \
        if n > 1.0 then n = 1.0 end\
        if n < 0 then n = 0 end \
        nVec[i] = n\
    end\
        \
    return nVec \
end\
\
function cfxZones.getRGBFromZoneProperty(theZone, theProperty, default)\
    --if not default then default = {1.0, 1.0, 1.0} end -- white \
    local rawRGB = cfxZones.getVectorFromZoneProperty(theZone, theProperty, 3, 1.0)\
    local retVal = {}\
    for i = 1, 3 do \
        local cp = rawRGB[i]\
        if cp > 1.0 then cp = 1.0 end\
        if cp < 0 then cp = 0 end \
        retVal[i] = cp\
    end\
    return retVal\
end\
\
\
function cfxZones.getSmokeColorStringFromZoneProperty(theZone, theProperty, default) -- smoke as 'red', 'green', or 1..5\
    if not default then default = \"red\" end \
    local s = cfxZones.getStringFromZoneProperty(theZone, theProperty, default)\
    s = s:lower()\
    s = dcsCommon.trim(s)\
    -- check numbers \
    if (s == \"0\") then return \"green\" end\
    if (s == \"1\") then return \"red\" end\
    if (s == \"2\") then return \"white\" end\
    if (s == \"3\") then return \"orange\" end\
    if (s == \"4\") then return \"blue\" end\
    \
    if s == \"green\" or\
       s == \"red\" or\
       s == \"white\" or\
       s == \"orange\" or\
       s == \"blue\" then return s end\
\
    return default \
end\
\
function cfxZones.getFlareColorStringFromZoneProperty(theZone, theProperty, default) -- smoke as 'red', 'green', or 1..5\
    if not default then default = \"red\" end \
    local s = cfxZones.getStringFromZoneProperty(theZone, theProperty, default)\
    s = s:lower()\
    s = dcsCommon.trim(s)\
    -- check numbers \
    if (s == \"rnd\") then return \"random\" end \
    if (s == \"0\") then return \"green\" end\
    if (s == \"1\") then return \"red\" end\
    if (s == \"2\") then return \"white\" end\
    if (s == \"3\") then return \"yellow\" end\
    if (s == \"-1\") then return \"random\" end  \
    \
    if s == \"green\" or\
       s == \"red\" or\
       s == \"white\" or\
       s == \"yellow\" or \
       s == \"random\" then\
    return s end\
\
    return default \
end\
\
\
--\
-- Zone-based wildcard processing\
-- \
\
-- process <z>\
function cfxZones.processZoneStatics(inMsg, theZone)\
    if theZone then \
        inMsg = inMsg:gsub(\"<z>\", theZone.name)\
    end\
    return inMsg \
end\
\
-- process <t>, <lat>, <lon>, <ele>, <mgrs> \
function cfxZones.processSimpleZoneDynamics(inMsg, theZone, timeFormat, imperialUnits)\
    if not inMsg then return \"<nil inMsg>\" end\
    -- replace <t> with current mission time HMS\
    local absSecs = timer.getAbsTime()-- + env.mission.start_time\
    while absSecs > 86400 do \
        absSecs = absSecs - 86400 -- subtract out all days \
    end\
    if not timeFormat then timeFormat = \"<:h>:<:m>:<:s>\" end \
    local timeString  = dcsCommon.processHMS(timeFormat, absSecs)\
    local outMsg = inMsg:gsub(\"<t>\", timeString)\
    \
    -- replace <lat> with lat of zone point and <lon> with lon of zone point \
    -- and <mgrs> with mgrs coords of zone point \
    local currPoint = cfxZones.getPoint(theZone)\
    local lat, lon = coord.LOtoLL(currPoint)\
    lat, lon = dcsCommon.latLon2Text(lat, lon)\
    local alt = land.getHeight({x = currPoint.x, y = currPoint.z})\
    if imperialUnits then \
        alt = math.floor(alt * 3.28084) -- feet \
    else \
        alt = math.floor(alt) -- meters \
    end \
    outMsg = outMsg:gsub(\"<lat>\", lat)\
    outMsg = outMsg:gsub(\"<lon>\", lon)\
    outMsg = outMsg:gsub(\"<ele>\", alt)\
    local grid = coord.LLtoMGRS(coord.LOtoLL(currPoint))\
    local mgrs = grid.UTMZone .. ' ' .. grid.MGRSDigraph .. ' ' .. grid.Easting .. ' ' .. grid.Northing\
    outMsg = outMsg:gsub(\"<mgrs>\", mgrs)\
    return outMsg\
end \
\
-- process <v: flag>, <rsp: flag> <rrnd>\
function cfxZones.processDynamicValues(inMsg, theZone, msgResponses)\
    -- replace all occurences of <v: flagName> with their values \
    local pattern = \"<v:%s*[%s%w%*%d%.%-_]+>\" -- no list allowed but blanks and * and . and - and _ --> we fail on the other specials to keep this simple \
    local outMsg = inMsg\
    repeat -- iterate all patterns one by one \
        local startLoc, endLoc = string.find(outMsg, pattern)\
        if startLoc then \
            local theValParam = string.sub(outMsg, startLoc, endLoc)\
            -- strip lead and trailer \
            local param = string.gsub(theValParam, \"<v:%s*\", \"\")\
            param = string.gsub(param, \">\",\"\")\
            -- param = dcsCommon.trim(param) -- trim is called anyway\
            -- access flag\
            local val = cfxZones.getFlagValue(param, theZone)\
            val = tostring(val)\
            if not val then val = \"NULL\" end \
            -- replace pattern in original with new val \
            outMsg = string.gsub(outMsg, pattern, val, 1) -- only one sub!\
        end\
    until not startLoc\
    \
    -- now process rsp \
    pattern = \"<rsp:%s*[%s%w%*%d%.%-_]+>\" -- no list allowed but blanks and * and . and - and _ --> we fail on the other specials to keep this simple \
\
    if msgResponses and (#msgResponses > 0) then -- only if this zone has an array\
        --trigger.action.outText(\"enter response proccing\", 30)\
        repeat -- iterate all patterns one by one \
            local startLoc, endLoc = string.find(outMsg, pattern)\
            if startLoc then \
                --trigger.action.outText(\"response: found an occurence\", 30)\
                local theValParam = string.sub(outMsg, startLoc, endLoc)\
                -- strip lead and trailer \
                local param = string.gsub(theValParam, \"<rsp:%s*\", \"\")\
                param = string.gsub(param, \">\",\"\")\
                \
                -- access flag\
                local val = cfxZones.getFlagValue(param, theZone)\
                if not val or (val < 1) then val = 1 end \
                if val > msgResponses then val = msgResponses end \
                \
                val = msgResponses[val]\
                val = dcsCommon.trim(val)\
                -- replace pattern in original with new val \
                outMsg = string.gsub(outMsg, pattern, val, 1) -- only one sub!\
            end\
        until not startLoc\
        \
        -- rnd response \
        local rndRsp = dcsCommon.pickRandom(msgResponses)\
        outMsg = outMsg:gsub (\"<rrnd>\", rndRsp)\
    end\
    \
    return outMsg\
end\
\
-- process <t: flag>\
function cfxZones.processDynamicTime(inMsg, theZone, timeFormat)\
    if not timeFormat then timeFormat = \"<:h>:<:m>:<:s>\" end\
    -- replace all occurences of <t: flagName> with their values \
    local pattern = \"<t:%s*[%s%w%*%d%.%-_]+>\" -- no list allowed but blanks and * and . and - and _ --> we fail on the other specials to keep this simple \
    local outMsg = inMsg\
    repeat -- iterate all patterns one by one \
        local startLoc, endLoc = string.find(outMsg, pattern)\
        if startLoc then \
            local theValParam = string.sub(outMsg, startLoc, endLoc)\
            -- strip lead and trailer \
            local param = string.gsub(theValParam, \"<t:%s*\", \"\")\
            param = string.gsub(param, \">\",\"\")\
            -- access flag\
            local val = cfxZones.getFlagValue(param, theZone)\
            -- use this to process as time value \
            --trigger.action.outText(\"time: accessing <\" .. param .. \"> and received <\" .. val .. \">\", 30)\
            local timeString  = dcsCommon.processHMS(timeFormat, val)\
            \
            if not timeString then timeString = \"NULL\" end \
            -- replace pattern in original with new val \
            outMsg = string.gsub(outMsg, pattern, timeString, 1) -- only one sub!\
        end\
    until not startLoc\
    return outMsg\
end\
\
-- process <lat/lon/ele/mgrs/lle/latlon/alt/vel/hdg/rhdg/type/player: zone/unit>\
function cfxZones.processDynamicLoc(inMsg, imperialUnits, responses)\
    local locales = {\"lat\", \"lon\", \"ele\", \"mgrs\", \"lle\", \"latlon\", \"alt\", \"vel\", \"hdg\", \"rhdg\", \"type\", \"player\"}\
    local outMsg = inMsg\
    local uHead = 0\
    for idx, aLocale in pairs(locales) do \
        local pattern = \"<\" .. aLocale .. \":%s*[%s%w%*%d%.%-_]+>\"\
        repeat -- iterate all patterns one by one \
            local startLoc, endLoc = string.find(outMsg, pattern)\
            if startLoc then\
                local theValParam = string.sub(outMsg, startLoc, endLoc)\
                -- strip lead and trailer \
                local param = string.gsub(theValParam, \"<\" .. aLocale .. \":%s*\", \"\")\
                param = string.gsub(param, \">\",\"\")\
                -- find zone or unit\
                param = dcsCommon.trim(param)\
                local thePoint = nil \
                local tZone = cfxZones.getZoneByName(param)\
                local tUnit = Unit.getByName(param)\
                local spd = 0\
                local angels = 0 \
                local theType = \"<errType>\"\
                local playerName = \"Unknown\"\
                if tZone then\
                    theType = \"Zone\"\
                    playerName = \"?zone?\"\
                    thePoint = cfxZones.getPoint(tZone)\
                    if tZone.linkedUnit and Unit.isExist(tZone.linkedUnit) then \
                        local lU = tZone.linkedUnit\
                        local masterPoint = lU:getPoint()\
                        thePoint.y = masterPoint.y \
                        spd = dcsCommon.getUnitSpeed(lU)\
                        spd = math.floor(spd * 3.6)\
                        uHead = math.floor(dcsCommon.getUnitHeading(tUnit) * 57.2958) -- to degrees.\
                    else \
                        -- since zones always have elevation of 0, \
                        -- now get the elevation from the map \
                        thePoint.y = land.getHeight({x = thePoint.x, y = thePoint.z})\
                    end\
                elseif tUnit then \
                    if Unit.isExist(tUnit) then\
                        theType = tUnit:getTypeName()\
                        if tUnit.getPlayerName and tUnit:getPlayerName() then\
                            playerName = tUnit:getPlayerName()\
                        end\
                        thePoint = tUnit:getPoint()\
                        spd = dcsCommon.getUnitSpeed(tUnit)\
                        -- convert m/s to km/h \
                        spd = math.floor(spd * 3.6)\
                        uHead = math.floor(dcsCommon.getUnitHeading(tUnit) * 57.2958) -- to degrees. \
                    end\
                else \
                    -- nothing to do, remove me.\
                end\
\
                local locString = \"err\"\
                if thePoint then \
                    -- now that we have a point, we can do locale-specific\
                    -- processing. return result in locString\
                    local lat, lon, alt = coord.LOtoLL(thePoint)\
                    lat, lon = dcsCommon.latLon2Text(lat, lon)\
                    angels = math.floor(thePoint.y) \
                    if imperialUnits then \
                        alt = math.floor(alt * 3.28084) -- feet\
                        spd = math.floor(spd * 0.539957) -- km/h to knots    \
                        angels = math.floor(angels * 3.28084)\
                    else \
                        alt = math.floor(alt) -- meters \
                    end \
                    \
                    if angels > 1000 then \
                        angels = math.floor(angels / 100) * 100 \
                    end\
                    \
                    if aLocale == \"lat\" then locString = lat \
                    elseif aLocale == \"lon\" then locString = lon \
                    elseif aLocale == \"ele\" then locString = tostring(alt)\
                    elseif aLocale == \"lle\" then locString = lat .. \" \" .. lon .. \" ele \" .. tostring(alt) \
                    elseif aLocale == \"latlon\" then locString = lat .. \" \" .. lon \
                    elseif aLocale == \"alt\" then locString = tostring(angels) -- don't confuse alt and angels, bad var naming here\
                    elseif aLocale == \"vel\" then locString = tostring(spd)\
                    elseif aLocale == \"hdg\" then locString = tostring(uHead)\
                    elseif aLocale == \"type\" then locString = theType \
                    elseif aLocale == \"player\" then locString = playerName \
                    elseif aLocale == \"rhdg\" and (responses) then \
                        local offset = cfxZones.rspMapper360(uHead, #responses)\
                        locString = dcsCommon.trim(responses[offset])\
                    else \
                        -- we have mgrs\
                        local grid = coord.LLtoMGRS(coord.LOtoLL(thePoint))\
                        locString = grid.UTMZone .. ' ' .. grid.MGRSDigraph .. ' ' .. grid.Easting .. ' ' .. grid.Northing\
                    end\
                end\
                -- replace pattern in original with new val \
                outMsg = string.gsub(outMsg, pattern, locString, 1) -- only one sub!\
            end -- if startloc\
        until not startLoc\
    end -- for all locales \
    return outMsg\
end\
\
function cfxZones.rspMapper360(directionInDegrees, numResponses)\
    -- maps responses around a clock. Clock has 12 'responses' (12, 1, .., 11), \
    -- with the first (12) also mapping to the last half arc \
    -- this method dynamically 'winds' the responses around \
    -- a clock and returns the index of the message to display \
    if numResponses < 1 then numResponses = 1 end \
    directionInDegrees = math.floor(directionInDegrees) \
    while directionInDegrees < 0 do directionInDegrees = directionInDegrees + 360 end \
    while directionInDegrees >= 360 do directionInDegrees = directionInDegrees - 360 end \
    -- now we have 0..360 \
    -- calculate arc per item \
    local arcPerItem = 360 / numResponses\
    local halfArc = arcPerItem / 2\
\
    -- we now map 0..360 to (0-halfArc..360-halfArc) by shifting \
    -- direction by half-arc and clipping back 0..360\
    -- and now we can directly derive the index of the response \
    directionInDegrees = directionInDegrees + halfArc\
    if directionInDegrees >= 360 then directionInDegrees = directionInDegrees - 360 end \
    \
    local index = math.floor(directionInDegrees / arcPerItem) + 1 -- 1 .. numResponses \
    \
    return index \
end\
\
-- replaces dcsCommon with same name \
-- timeFormat is optional, default is \"<:h>:<:m>:<:s>\"\
-- imperialUnits is optional, defaults to meters \
-- responses is an array of string, defaults to {}\
function cfxZones.processStringWildcards(inMsg, theZone, timeFormat, imperialUnits, responses)\
    if not inMsg then return \"<nil inMsg>\" end\
    local formerType = type(inMsg)\
    if formerType ~= \"string\" then inMsg = tostring(inMsg) end\
    if not inMsg then inMsg = \"<inMsg is incompatible type \" .. formerType .. \">\" end\
    local theMsg = inMsg\
    -- process common DCS stuff like /n \
    theMsg = dcsCommon.processStringWildcards(theMsg) -- call old inherited\
    -- process <z>\
    theMsg = cfxZones.processZoneStatics(theMsg, theZone)\
    -- process <t>, <lat>, <lon>, <ele>, <mgrs>\
    theMsg = cfxZones.processSimpleZoneDynamics(theMsg, theZone, timeFormat, imperialUnits)\
    -- process <v: flag>, <rsp: flag> <rrnd>\
    theMsg = cfxZones.processDynamicValues(theMsg, theZone, responses)\
    -- process <t: flag>\
    theMsg = cfxZones.processDynamicTime(theMsg, theZone, timeFormat)\
    -- process <lat/lon/ele/mgrs/lle/latlon/alt/vel/hdg/rhdg/type/player: zone/unit>\
    theMsg = cfxZones.processDynamicLoc(theMsg, imperialUnits, responses)\
\
    return theMsg\
end\
\
--\
-- ============\
-- MOVING ZONES \
-- ============ \
-- \
-- Moving zones 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.getDCSOrigin(aZone)\
    local o = {}\
    o.x = aZone.dcsOrigin.x\
    o.y = 0\
    o.z = aZone.dcsOrigin.z \
    return o\
end\
\
function cfxZones.getLinkedUnit(theZone)\
    if not theZone then return nil end \
    if not theZone.linkedUnit then return nil end \
    if not Unit.isExist(theZone.linkedUnit) then return nil end \
    return theZone.linkedUnit \
end\
\
function cfxZones.getPoint(aZone, getHeight) -- always works, even linked, returned point can be reused\
-- returned y (when using getHeight) is that of the land, else 0 \
    if not getHeight then getHeight = false end \
    if aZone.linkedUnit then \
        local theUnit = aZone.linkedUnit\
        -- has a link. is link existing?\
        if Unit.isExist(theUnit) then \
            -- updates zone position \
            cfxZones.centerZoneOnUnit(aZone, theUnit)\
            local dx = aZone.dx\
            local dy = aZone.dy\
            if aZone.useHeading then \
                dx, dy = cfxZones.calcHeadingOffset(aZone, theUnit)\
            end\
            cfxZones.offsetZone(aZone, dx, dy)\
        end\
    end\
    local thePos = {}\
    thePos.x = aZone.point.x\
    thePos.z = aZone.point.z\
    if not getHeight then \
        thePos.y = 0 -- aZone.y \
    else \
        thePos.y = land.getHeight({x = thePos.x, y = thePos.z})\
    end\
    \
    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 \
    theZone.rxy = math.sqrt(dx * dx + dy * dy) -- radius \
    local unitHeading = dcsCommon.getUnitHeading(theUnit)\
    local bearingOffset = math.atan2(dy, dx) -- rads \
    if bearingOffset < 0 then bearingOffset = bearingOffset + 2 * 3.141592 end \
\
    local dPhi = bearingOffset - unitHeading\
    if dPhi < 0 then dPhi = dPhi + 2 * 3.141592 end\
    if (theZone.verbose and theZone.useHeading) then \
        trigger.action.outText(\"Zone is at <\" .. math.floor(57.2958 * dPhi) .. \"> relative to unit heading\", 30)\
    end\
    theZone.dPhi = dPhi -- constant delta between unit heading and \
    -- direction to zone \
    theZone.uHdg = unitHeading -- original unit heading to turn other \
    -- units if need be \
    --trigger.action.outText(\"Link setup: dx=<\" .. dx .. \">, dy=<\" .. dy .. \"> unit original hdg = <\" .. math.floor(57.2958 * unitHeading)  .. \">\", 30)\
end\
\
function cfxZones.zonesLinkedToUnit(theUnit) -- returns all zones linked to this unit \
    if not theUnit then return {} end \
    local linkedZones = {}\
    for idx, theZone in pairs (cfxZones.zones) do \
        if theZone.linkedUnit == theUnit then \
            table.insert(linkedZones, theZone)\
        end\
    end\
    return linkedZones\
end\
\
function cfxZones.calcHeadingOffset(aZone, theUnit)\
    -- recalc dx and dy based on ry and current heading \
    -- since 0 degrees is [0,1] = [0,r] the calculation of \
    -- rotated coords can be simplified from \
    -- xr = x cos phi - y sin phi = -r sin phi\
    -- yr = y cos phi + x sin phi = r cos phi \
    local unitHeading = dcsCommon.getUnitHeading(theUnit)\
    -- add heading offset \
    local zoneBearing = unitHeading + aZone.dPhi \
    if zoneBearing > 2 * 3.141592 then zoneBearing = zoneBearing - 2 * 3.141592 end \
                    \
    -- in DCS, positive x is north (wtf?) and positive z is east \
    local dy = (-aZone.rxy) * math.sin(zoneBearing)\
    local dx = aZone.rxy * math.cos(zoneBearing)\
    \
    --trigger.action.outText(\"zone bearing is \" .. math.floor(zoneBearing * 57.2958) .. \" dx = <\" .. dx .. \"> , dy = <\" .. dy .. \">\", 30)\
    return dx, -dy -- note: dy is z coord!!!!\
end\
\
function cfxZones.updateMovingZones()\
    cfxZones.updateSchedule = timer.scheduleFunction(cfxZones.updateMovingZones, {}, timer.getTime() + 1/cfxZones.ups)\
    -- simply scan all cfx zones for the linkName property, and if present\
    -- update the zone's points\
    for aName,aZone in pairs(cfxZones.zones) do\
        -- only do this if ther is a linkName property, \
        -- else this zone isn't linked. link name is harmonized from \
        -- both linkUnit non-DML and linedUnit DML        \
        if aZone.linkName then \
            if aZone.linkBroken then \
                -- try to relink \
                cfxZones.initLink(aZone)\
            else --if aZone.linkName then  \
                -- always re-acquire linkedUnit via Unit.getByName()\
                -- this way we gloss over any replacements via spawns\
                aZone.linkedUnit = Unit.getByName(aZone.linkName)\
            end\
            \
            if aZone.linkedUnit then \
                local theUnit = aZone.linkedUnit\
                -- has a link. is link existing?\
                if theUnit:isExist() then \
                    cfxZones.centerZoneOnUnit(aZone, theUnit)\
                    local dx = aZone.dx \
                    local dy = aZone.dy -- this is actually z \
                    if aZone.useHeading then \
                        dx, dy = cfxZones.calcHeadingOffset(aZone, theUnit)\
                    end\
                    cfxZones.offsetZone(aZone, dx, dy)\
                else \
                    -- we lost link (track level)\
                    aZone.linkBroken = true \
                    aZone.linkedUnit = nil \
                end\
            else \
                -- we lost link (top level)\
                aZone.linkBroken = true \
                aZone.linkedUnit = nil \
            end\
        else \
            -- this zone isn't linked\
        end\
    end\
end\
\
function cfxZones.initLink(theZone)\
\
    theZone.linkBroken = true \
    theZone.linkedUnit = nil \
    theUnit = Unit.getByName(theZone.linkName)\
    if theUnit then\
\
        local dx = 0\
        local dz = 0\
        if theZone.useOffset or theZone.useHeading then \
            local A = cfxZones.getDCSOrigin(theZone)\
            local B = theUnit:getPoint()\
            local delta = dcsCommon.vSub(A,B) \
            dx = delta.x \
            dz = delta.z\
        end\
        cfxZones.linkUnitToZone(theUnit, theZone, dx, dz) -- also sets theZone.linkedUnit\
\
        if theZone.verbose then \
            trigger.action.outText(\"Link established for zone <\" .. theZone.name .. \"> to unit <\" .. theZone.linkName .. \">: dx=<\" .. math.floor(dx) .. \">, dz=<\" .. math.floor(dz) .. \"> dist = <\" .. math.floor(math.sqrt(dx * dx + dz * dz)) .. \">\" , 30)\
        end \
        theZone.linkBroken = nil \
\
    else \
        if theZone.verbose then \
            trigger.action.outText(\"Linked unit: no unit <\" .. theZone.linkName .. \"> to link <\" .. theZone.name .. \"> to\", 30)\
        end\
    end\
end\
\
function cfxZones.startMovingZones()\
    -- read all zones, and look for a property called 'linkedUnit'\
    -- which will make them a linked zone if there is a unit that exists\
    -- also suppors 'useOffset' and 'useHeading'\
    for aName,aZone in pairs(cfxZones.zones) do\
        \
        local lU = nil \
        -- check if DCS zone has the linkUnit new attribute introduced in \
        -- late 2022 with 2.8\
        if aZone.dcsZone.linkUnit then \
            local theID = aZone.dcsZone.linkUnit \
            lU = dcsCommon.getUnitNameByID(theID)\
            if not lU then \
                trigger.action.outText(\"WARNING: Zone <\" .. aZone.name .. \">: cannot resolve linked unit ID <\" .. theID .. \">\", 30)\
                lU = \"***DML link err***\"\
            end\
        elseif cfxZones.hasProperty(aZone, \"linkedUnit\") then \
            lU = cfxZones.getZoneProperty(aZone, \"linkedUnit\")\
        end\
        \
        -- sanity check \
        if aZone.dcsZone.linkUnit and cfxZones.hasProperty(aZone, \"linkedUnit\") then \
            trigger.action.outText(\"WARNING: Zone <\" .. aZone.name .. \"> has dual unit link definition. Will use link to unit <\" .. lU .. \">\", 30)\
        end\
        \
        if lU then \
            aZone.linkName = lU\
            aZone.useOffset = cfxZones.getBoolFromZoneProperty(aZone, \"useOffset\", false)\
            aZone.useHeading = cfxZones.getBoolFromZoneProperty(aZone, \"useHeading\", false)\
            \
            cfxZones.initLink(aZone)\
\
        end\
        \
    end\
end\
\
\
--\
-- ===========\
-- INIT MODULE\
-- ===========\
--\
\
function cfxZones.initZoneVerbosity()\
    for aName,aZone in pairs(cfxZones.zones) do\
        -- support for zone-local verbose flag \
        aZone.verbose = cfxZones.getBoolFromZoneProperty(aZone, \"verbose\", false)\
    end\
end\
\
function cfxZones.init()\
    -- read all zones into my own db\
    cfxZones.readFromDCS(true) -- true: erase old\
\
    -- pre-read zone owner for all zones\
    -- much like verbose, all zones have owner\
--    local pZones = cfxZones.zonesWithProperty(\"owner\")\
--    for n, aZone in pairs(pZones) do\
    for n, aZone in pairs(cfxZones.zones) do\
        aZone.owner = cfxZones.getCoalitionFromZoneProperty(aZone, \"owner\", 0)\
    end\
        \
    -- enable all zone's verbose flags if present\
    -- must be done BEFORE we start the moving zones \
    cfxZones.initZoneVerbosity()\
    \
    -- now initialize moving zones\
    cfxZones.startMovingZones()\
    cfxZones.updateMovingZones() -- will auto-repeat\
    \
    trigger.action.outText(\"cf/x Zones v\".. cfxZones.version .. \": loaded, zones:\" .. dcsCommon.getSizeOfTable(cfxZones.zones), 30)\
\
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.1\"\
--[[-- 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)\
- 3.0.1 - isPlayerUnit guard against scenery object or map object \
--]]--\
\
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 \
    if not theUnit.getPlayerName then return false end -- map/static object \
    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 is 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"] = "cfxPlayerScore = {}\
cfxPlayerScore.version = \"2.2.0\"\
cfxPlayerScore.name = \"cfxPlayerScore\" -- compatibility with flag bangers\
cfxPlayerScore.badSound = \"Death BRASS.wav\"\
cfxPlayerScore.scoreSound = \"Quest Snare 3.wav\"\
cfxPlayerScore.announcer = true \
cfxPlayerScore.firstSave = true -- to force overwrite \
--[[-- VERSION HISTORY\
    1.0.1 - bug fixes to killDetected \
    1.0.2 - messaging clean-up, less verbose \
    1.1.0 - integrated score base system\
          - accepts configZones \
          - module validation \
          - isNamedUnit(theUnit)\
          - notify if named unit killed \
          - kill weapon reported \
    1.2.0 - score table \
          - announcer attribute \
          - badSound name \
          - scoreSound name \
    1.3.0 - object2score \
          - static objects also can score \
          - can now also score members of group by adding group name \
          - scenery objects are now supported. use the \
            number that is given under OBJECT ID when \
            using assign as...\
    1.3.1 - isStaticObject() to better detect buildings after Match 22 patch\
    1.3.2 - corrected ground default score \
          - removed dependency to cfxPlayer \
    1.4.0 - persistence support \
          - better unit-->static switch support for generic type kill\
    1.5.0 - added feats to score\
          - feats API \
          - logFeatForPlayer(playerName, theFeat, coa)\
    1.5.1 - init feats before reading \
    2.0.0 - sound name for good and bad corrected \
          - scoreOnly option \
          - saveScore? input in config\
          - incremental option in config for save \
          - preProcessor() added land and birth for players \
          - addSafeZone()\
          - landing score possible as feat \
          - also detect landing and birth events for players \
          - birth zeroes deferred scores and feats\
          - delayAfterLanding property \
          - delayBetweenLandings to filter landings and \
            space them properly from take offs \
          - ranking option \
          - scoreOnly option \
          - scoreFileName option \
          - update() loop \
          - read \"scoreSafe\" zones \
          - scoreaccu in playerScore \
          - landing feat added, enabled with landing > 0 score attribute\
          - delayed awards after landing \
          - save score to file \
          - show score to all \
          - feat zones \
          - awardLimit - feats can be limited in number total\
          - wildcard support for feature \
          - kill zones - limit kill score awards to inside zones \
          - feats can be limited to once per player\
          - persistence: featNum \
          - persistence: awardedTo\
          - always schedule\
          - hasAward logic \
          - unit2player\
          - detect player plane death \
          - ffMod attribute\
          - pkMod attribute\
          - pvp feat \
          - immediate awarding of all negative scores, even if deferred\
    2.0.1 - corrected access to nowString()\
          - more robust config reading \
    2.1.0 - coalition score \
          - reportCoalition switch \
          - persist coalition score \
          - add score to coalition when scoring player \
    2.1.1 - check ownership of scoreSafe zone upon touch-down \
          - new scoreSummaryForPlayersOfCoalition()\
          - new noGrief option in config \
          - improved guards when checking ownership (nil zone owner)\
    2.0.0 - score flags for red and blue \
    \
--]]--\
\
cfxPlayerScore.requiredLibs = {\
    \"dcsCommon\", -- this is doing score keeping\
    \"cfxZones\", -- zones for config \
}\
cfxPlayerScore.playerScore = {} -- indexed by playerName\
cfxPlayerScore.coalitionScore = {} -- score per coalition\
cfxPlayerScore.coalitionScore[1] = 0 -- init red\
cfxPlayerScore.coalitionScore[2] = 0 -- init blue\
cfxPlayerScore.deferred = false -- on deferred, we only award after landing, and erase on any form of re-slot\
cfxPlayerScore.delayAfterLanding = 10 -- seconds after landing \
cfxPlayerScore.safeZones = {} -- safe zones to land in  \
cfxPlayerScore.featZones = {} -- zones that define feats \
cfxPlayerScore.killZones = {} -- when set, kills only count here \
\
-- typeScore: dictionary sorted by typeString for score \
-- extend to add more types. It is used by unitType2score to \
-- determine the base unit score  \
cfxPlayerScore.typeScore = {}\
cfxPlayerScore.lastPlayerLanding = {} -- timestamp, by player name  \
cfxPlayerScore.delayBetweenLandings = 30 -- seconds to count as separate landings, also set during take-off to prevent janky t/o to count. \
--\
-- we subscribe to the kill event. each time a unit \
-- is killed, we check if it was killed by a player\
-- and if so, that player record is updated and the side\
-- whom the player belongs to is informed\
--\
cfxPlayerScore.aircraft = 50 \
cfxPlayerScore.helo = 40 \
cfxPlayerScore.ground = 10\
cfxPlayerScore.ship = 80 \
cfxPlayerScore.train = 5 \
cfxPlayerScore.landing = 0 -- if > 0 it scores as feat\
\
cfxPlayerScore.unit2player = {} -- lookup and reverse look-up \
\
function cfxPlayerScore.addSafeZone(theZone)\
    theZone.scoreSafe = cfxZones.getCoalitionFromZoneProperty(theZone, \"scoreSafe\", 0)\
    table.insert(cfxPlayerScore.safeZones, theZone)\
end\
\
function cfxPlayerScore.addKillZone(theZone)\
    theZone.killZone = cfxZones.getCoalitionFromZoneProperty(theZone, \"killZone\", 0) -- value currently ignored \
    theZone.duet = cfxZones.getBoolFromZoneProperty(theZone, \"duet\", false) -- does killer have to be in zone? \
    table.insert(cfxPlayerScore.killZones, theZone)\
end\
\
function cfxPlayerScore.addFeatZone(theZone)\
    theZone.coalition = cfxZones.getCoalitionFromZoneProperty(theZone, \"feat\", 0) -- who can earn, 0 for all sides \
    theZone.featType = cfxZones.getStringFromZoneProperty(theZone, \"featType\", \"kill\")\
    theZone.featType = string.upper(theZone.featType)\
    if theZone.featType == \"LAND\" then theZone.featType = \"LANDING\" end \
    if theZone.featType ~= \"KILL\" and \
       theZone.featType ~= \"LANDING\" and \
       theZone.featType ~= \"PVP\"\
    then\
        theZone.featType = \"KILL\"\
    end    \
    theZone.featDesc = cfxZones.getStringFromZoneProperty(theZone, \"description\", \"(some feat)\")\
    theZone.featNum = cfxZones.getNumberFromZoneProperty(theZone, \"awardLimit\", -1) -- how many times this can be awarded, -1 is infinite \
    theZone.ppOnce = cfxZones.getBoolFromZoneProperty(theZone, \"awardOnce\", false)\
    theZone.awardedTo = {} -- by player name: true/false \
    table.insert(cfxPlayerScore.featZones, theZone)\
    if cfxPlayerScore.verbose then \
        trigger.action.outText(\"+++ feat zone <\" .. theZone.name .. \"> read: [\" .. theZone.featDesc .. \"] for <\" .. theZone.featType .. \">\", 30)\
    end \
end\
\
function cfxPlayerScore.getFeatByName(name)\
    for idx, theZone in pairs(cfxPlayerScore.featZones) do \
        if name == theZone.name then return theZone end \
    end\
    return nil \
end\
\
function cfxPlayerScore.featsForLocation(name, loc, coa, featType, killer, victim)\
    if not loc then return {} end \
    -- loc is location of landing unit for landing \
    -- and location of victim for kill \
    -- coa is coalition of landing unit \
    -- and coalition of killer for kill \
\
    if not coa then coa = 0 end \
    if not featType then featType = \"KILL\" end \
    featType = string.upper(featType)\
    local theFeats = {}\
    for idx, theZone in pairs(cfxPlayerScore.featZones) do \
        local canAward = true \
                   \
        -- check if it can be awarded \
        if theZone.featNum == 0 then \
            canAward = false \
        end \
        \
        if theZone.featType ~= featType then \
            canAward = false\
        end\
        \
        if not (theZone.coalition == 0 or theZone.coalition == coa) then \
            canAward = false \
        end            \
        \
        if featType == \"PVP\" then \
            -- make sure kill is pvp kill \
            if not victim then canAward = false \
            elseif not victim.getPlayerName then \
                canAward = false \
            elseif not victim:getPlayerName() then\
                canAward = false \
            end\
        end\
        \
        if not cfxZones.pointInZone(loc, theZone) then \
            canAward = false \
        end\
        \
        if theZone.ppOnce then \
            if theZone.awardedTo[name] then \
                canAward = false\
            end\
        end\
        \
        if canAward then \
            table.insert(theFeats, theZone) -- jupp, add it\
        else \
        end \
\
    end\
    return theFeats\
end\
\
function cfxPlayerScore.preprocessWildcards(inMsg, aUnit, aVictim)\
    local theMsg = inMsg\
    if not aVictim then aVictim = aUnit end \
    local pName = \"Unknown\"\
    if aUnit then \
        if aUnit.getPlayerName then \
            pN = aUnit:getPlayerName()\
            if pN then pName = pN end \
        end\
        theMsg = theMsg:gsub(\"<punit>\", aUnit:getName())\
        theMsg = theMsg:gsub(\"<ptype>\", aUnit:getTypeName())\
        theMsg = theMsg:gsub(\"<pgroup>\", aUnit:getGroup():getName())\
    end\
    theMsg = theMsg:gsub(\"<player>\", pName)\
    if aVictim then \
        -- if player killed, get killed player's name else use unknown AI\
        if aVictim.getPlayerName then \
            pkName = aVictim:getPlayerName()\
            if pkName then \
                theMsg = theMsg:gsub(\"<kplayer>\", pkName)\
            else \
                theMsg = theMsg:gsub(\"<kplayer>\", \"unknown AI\")\
            end\
        end\
        theMsg = theMsg:gsub(\"<unit>\", aVictim:getName())\
        theMsg = theMsg:gsub(\"<type>\", aVictim:getTypeName())\
        -- victim may not have group. guard against that \
        -- happens if unit 'cooks off'\
        local aGroup = nil \
        if aVictim.getGroup then \
            aVictim:getGroup()\
        end \
        if aGroup and aGroup.getName then \
            theMsg = theMsg:gsub(\"<group>\", aGroup:getName())\
        else \
            theMsg = theMsg:gsub(\"<group>\", \"(Unknown)\")\
        end \
    end \
    return theMsg\
end\
\
function cfxPlayerScore.evalFeatDescription(name, theZone, playerUnit, victim) \
    local msg = theZone.featDesc \
    if not victim then victim = playerUnit end \
    -- eval wildcards \
    msg = cfxPlayerScore.preprocessWildcards(msg, playerUnit, victim)\
    msg = cfxZones.processStringWildcards(msg, theZone) -- nil time format, nil imperial, nil responses\
        \
    -- update featNum since it's been 'used' \
    if theZone.featNum > 0 then \
        theZone.featNum = theZone.featNum -1 \
    end\
    -- mark this feat awarded to player, only relevant for ppOnce \
    theZone.awardedTo[name] = true \
    return msg \
end\
\
function cfxPlayerScore.cat2BaseScore(inCat)\
    if inCat == 0 then return cfxPlayerScore.aircraft end -- airplane\
    if inCat == 1 then return cfxPlayerScore.helo end -- helo \
    if inCat == 2 then return cfxPlayerScore.ground end -- ground \
    if inCat == 3 then return cfxPlayerScore.ship end -- ship \
    if inCat == 4 then return cfxPlayerScore.train end -- train \
    \
    trigger.action.outText(\"+++scr c2bs: unknown category for lookup: <\" .. inCat .. \">, returning 1\", 30)\
    \
    return 1 \
end\
\
function cfxPlayerScore.object2score(inVictim) -- does not have group\
    if not inVictim then return end \
    local inName = inVictim:getName()\
    if not inName then return 0 end \
    if type(inName) == \"number\" then \
        inName = tostring(inName)\
    end\
    \
    -- since 2.7x DCS turns units into static objects for \
    -- cooking off, so first thing we need to do is do a name check \
    local objectScore = cfxPlayerScore.typeScore[inName]\
    if not objectScore then \
        -- try the type desc \
        local theType = inVictim:getTypeName()\
        objectScore = cfxPlayerScore.typeScore[theType]\
    end\
    \
    if type(objectScore) == \"string\" then \
        objectScore = tonumber(objectScore)\
    end\
    \
    if objectScore then return objectScore end\
    \
    -- we now try and get the general type of the killed object\
    local desc = inVictim:getDesc() -- Object.getDesc(inVictim)\
    local attributes = desc.attributes \
    if attributes then \
        if attributes[\"Vehicles\"] or attributes[\"Ground vehicles\"] or attributes[\"Ground Units\"] then return cfxPlayerScore.ground end \
        if attributes[\"Helicopters\"] then return cfxPlayerScore.helo end\
        if attributes[\"Planes\"] then return cfxPlayerScore.aircraft end \
        if attributes[\"Ships\"] then return cfxPlayerScore.ship end \
        -- trains can't be detected\
    end \
    \
    if not objectScore then return 0 end \
    return objectScore \
end\
\
function cfxPlayerScore.unit2score(inUnit)\
    local vicGroup = inUnit:getGroup()\
    local vicCat = vicGroup:getCategory()\
    local vicType = inUnit:getTypeName()\
    local vicName = inUnit:getName() \
    if type(vicName) == \"number\" then vicName = tostring(vicName) end \
    \
    -- simply extend by adding items to the typescore table.concat\
    -- we first try by unit name. This allows individual\
    -- named hi-value targets to have individual scores \
    local uScore = cfxPlayerScore.typeScore[vicName]\
\
    -- see if all members of group score \
    if not uScore then \
        local grpName = vicGroup:getName()\
        uScore = cfxPlayerScore.typeScore[grpName]\
    end\
    \
    if uScore == nil then \
        -- WE NOW TRY TO ACCESS BY VICTIM'S TYPE STRING        \
        uScore = cfxPlayerScore.typeScore[vicType]\
    else \
\
    end \
    if type(uScore) == \"string\" then \
        -- convert string to number \
        uScore = tonumber(uScore)\
    end\
\
    if uScore == nil then uScore = 0 end \
    if uScore > 0 then return uScore end \
    \
    -- only apply base scores when the lookup did not give a result\
    uScore = cfxPlayerScore.cat2BaseScore(vicCat)\
    return uScore \
end\
\
function cfxPlayerScore.getPlayerScore(playerName)\
    local thePlayerScore = cfxPlayerScore.playerScore[playerName]\
    if thePlayerScore == nil then \
        thePlayerScore = {}\
        thePlayerScore.name = playerName\
        thePlayerScore.score = 0 -- score\
        thePlayerScore.scoreaccu = 0 -- for deferred \
        thePlayerScore.killTypes = {} -- the type strings killed, dict <typename> <numkilla>\
        thePlayerScore.killQueue = {} -- when using deferred\
        thePlayerScore.totalKills = 0 -- number of kills total \
        thePlayerScore.featTypes = {} -- dict <featname> <number> of other things player did \
        thePlayerScore.featQueue = {} -- when using deferred \
        thePlayerScore.totalFeats = 0        \
    end\
    return thePlayerScore\
end\
\
function cfxPlayerScore.setPlayerScore(playerName, thePlayerScore)\
    cfxPlayerScore.playerScore[playerName] = thePlayerScore\
end\
\
-- will never defer \
function cfxPlayerScore.updateScoreForPlayerImmediate(playerName, score)\
    local thePlayerScore = cfxPlayerScore.getPlayerScore(playerName)\
    thePlayerScore.score = thePlayerScore.score + score\
    cfxPlayerScore.setPlayerScore(playerName, thePlayerScore)\
    -- if coalitionScore is active, trace player back to their current \
    -- coalition and add points to that coalition if positive \
    -- or always if noGrief is true \
    local pFaction = dcsCommon.playerName2Coalition(playerName)\
    if cfxPlayerScore.noGrief then  \
        -- only on positive score\
        if (score > 0) and pFaction > 0 then \
            cfxPlayerScore.coalitionScore[pFaction] = cfxPlayerScore.coalitionScore[pFaction] + score \
        end\
    else \
        if pFaction > 0 then \
            cfxPlayerScore.coalitionScore[pFaction] = cfxPlayerScore.coalitionScore[pFaction] + score \
        end\
    end\
    return thePlayerScore.score \
end\
\
function cfxPlayerScore.updateScoreForPlayer(playerName, score)\
    -- main update score \
    if cfxPlayerScore.deferred then -- just queue it\
        local thePlayerScore = cfxPlayerScore.getPlayerScore(playerName) \
        thePlayerScore.scoreaccu = thePlayerScore.scoreaccu + score\
        cfxPlayerScore.setPlayerScore(playerName, thePlayerScore) -- write-through. why? because it may be a new entry.\
        return thePlayerScore.score -- this is the old score!!! \
    end\
    -- now write immediately \
    return cfxPlayerScore.updateScoreForPlayerImmediate(playerName, score)\
end\
\
function cfxPlayerScore.doLogTypeKill(playerName, thePlayerScore, theType)\
    local killCount = thePlayerScore.killTypes[theType]    \
    if killCount == nil then \
        killCount = 0\
    end\
    killCount = killCount + 1\
    thePlayerScore.totalKills = thePlayerScore.totalKills + 1\
    thePlayerScore.killTypes[theType] = killCount\
    \
    cfxPlayerScore.setPlayerScore(playerName, thePlayerScore)\
end \
\
function cfxPlayerScore.logKillForPlayer(playerName, theUnit)\
    -- main kill type /total count logging, can be deferred \
    -- no score change here \
    if not theUnit then return end\
    if not playerName then return end \
    local thePlayerScore = cfxPlayerScore.getPlayerScore(playerName)    \
    local theType = theUnit:getTypeName()\
    \
    if cfxPlayerScore.deferred then \
        -- just queue it \
        table.insert(thePlayerScore.killQueue, theType)\
        cfxPlayerScore.setPlayerScore(playerName, thePlayerScore) -- write-through. why? because it may be a new entry.\
        return \
    end\
    \
    cfxPlayerScore.doLogTypeKill(playerName, thePlayerScore, theType)\
end\
\
function cfxPlayerScore.doLogFeat(playerName, thePlayerScore, theFeat)\
    if not thePlayerScore.featTypes then thePlayerScore.featTypes = {} end\
    local featCount = thePlayerScore.featTypes[theFeat]\
    if featCount == nil then \
        featCount = 0\
    end\
    featCount = featCount + 1\
    thePlayerScore.totalFeats = thePlayerScore.totalFeats + 1\
    thePlayerScore.featTypes[theFeat] = featCount\
    \
    cfxPlayerScore.setPlayerScore(playerName, thePlayerScore)\
\
end\
\
function cfxPlayerScore.logFeatForPlayer(playerName, theFeat, coa)\
    -- usually called externally with theFeat being a string. no \
    -- scoring is passed \
    if not theFeat then return end\
    if not playerName then return end \
    -- access player's record. will alloc if new by itself\
\
    if coa then \
        local disclaim = \"\"\
        if cfxPlayerScore.deferred then disclaim = \" (award pending)\" end \
        trigger.action.outTextForCoalition(coa, playerName .. \" achieved \" .. theFeat .. disclaim, 30)\
        trigger.action.outSoundForCoalition(coa, cfxPlayerScore.scoreSound)\
    end\
    \
    local thePlayerScore = cfxPlayerScore.getPlayerScore(playerName)\
    if cfxPlayerScore.deferred then \
        table.insert(thePlayerScore.featQueue, theFeat)\
        cfxPlayerScore.setPlayerScore(playerName, thePlayerScore)\
        return \
    end\
    \
    cfxPlayerScore.doLogFeat(playerName, thePlayerScore, theFeat)\
end\
\
function cfxPlayerScore.playerScore2text(thePlayerScore, scoreOnly)\
    if not scoreOnly then scoreOnly = false end \
    local desc = thePlayerScore.name .. \" statistics:\\n\"\
\
    if cfxPlayerScore.reportScore then     \
        desc = desc .. \" - score: \".. thePlayerScore.score .. \" - total kills: \" .. thePlayerScore.totalKills .. \"\\n\"\
        if scoreOnly then \
            return desc \
        end \
        \
        -- now go through all kills\
        desc = desc .. \"\\nKills by type:\\n\"\
        if dcsCommon.getSizeOfTable(thePlayerScore.killTypes)  < 1 then \
            desc = desc .. \"    - NONE -\\n\"\
        end\
        for theType, quantity in pairs(thePlayerScore.killTypes) do \
            desc = desc .. \"  - \" .. theType .. \": \" .. quantity .. \"\\n\"\
        end\
    end \
    \
    -- now enumerate all feats\
    if not thePlayerScore.featTypes then thePlayerScore.featTypes = {} end\
    if cfxPlayerScore.reportFeats then \
        desc = desc .. \"\\n Accomplishments:\\n\"\
        if dcsCommon.getSizeOfTable(thePlayerScore.featTypes) < 1 then \
            desc = desc .. \"    - NONE -\\n\"\
        end\
        for theFeat, quantity in pairs(thePlayerScore.featTypes) do \
            desc = desc .. \"  - \" .. theFeat\
            if quantity > 1 then \
                desc = desc .. \" (x\" .. quantity .. \")\"\
            end \
            desc = desc .. \"\\n\"\
        end\
    end \
    \
    if cfxPlayerScore.reportScore and thePlayerScore.scoreaccu > 0 then \
        desc = desc .. \"\\n - unclaimed score: \" .. thePlayerScore.scoreaccu ..\"\\n\"\
    end\
    \
    local featCount = dcsCommon.getSizeOfTable(thePlayerScore.featQueue)\
    if cfxPlayerScore.reportFeats and featCount > 0 then \
        desc = desc .. \" - unclaimed feats: \" .. featCount ..\"\\n\"\
    end\
    \
    return desc\
end\
\
function cfxPlayerScore.scoreTextForPlayerNamed(playerName)\
    local thePlayerScore = cfxPlayerScore.getPlayerScore(playerName)\
    return cfxPlayerScore.playerScore2text(thePlayerScore)\
end\
\
function cfxPlayerScore.scoreSummaryForPlayersOfCoalition(side)\
    -- only list players who are in the coalition RIGHT NOW\
    -- only list their score \
    if not side then side = -1 end \
    local desc = \"\\nCurrent score for players in \" .. dcsCommon.coalition2Text(side) ..\" coalition:\\n\"\
    local count = 0 \
    for pName, pScore in pairs(cfxPlayerScore.playerScore) do \
        local coa = dcsCommon.playerName2Coalition(pName)\
        if coa == side then \
            desc = desc .. pName ..\": \" .. pScore.score .. \"\\n\"\
            count = count + 1\
        end\
    end\
    if count < 1 then \
        desc = desc .. \"  (No score yet)\"\
    end\
    \
    desc = desc .. \"\\n\"\
    return desc\
end\
\
function cfxPlayerScore.scoreTextForAllPlayers(ranked) \
    if not ranked then ranked = false end \
    local theText = \"\"\
    local isFirst = true \
    local theScores = cfxPlayerScore.playerScore\
    if cfxPlayerScore.verbose then \
        trigger.action.outText(\"+++pScr: Generating score - <\" .. dcsCommon.getSizeOfTable(theScores) .. \"> entries.\", 30)\
    end \
    if ranked then \
        table.sort(theScores, function(left, right) return left.score < right.score end )\
    end\
    local rank = 1\
    for name, score in pairs(theScores) do \
        if not isFirst then \
            theText = theText .. \"\\n\"\
        end\
        if ranked then \
            if rank < 10 then theText = theText .. \" \" end\
            theText = theText .. rank .. \". \"\
        end\
        theText = theText .. cfxPlayerScore.playerScore2text(score, cfxPlayerScore.scoreOnly)  \
        isFirst = false\
        rank = rank + 1\
    end\
    \
    if dcsCommon.getSizeOfTable(theScores) < 1 then \
        theText = theText .. \"  (No score yet)\\n\"\
    end\
    \
    if cfxPlayerScore.reportCoalition then \
        --theText = theText .. \"\\n\"\
        theText = theText .. \"\\nRED  total: \" .. cfxPlayerScore.coalitionScore[1]\
        theText = theText .. \"\\nBLUE total: \" .. cfxPlayerScore.coalitionScore[2]\
    end\
    \
    return theText\
end\
\
\
function cfxPlayerScore.isNamedUnit(theUnit) \
    if not theUnit then return false end \
    local theName = \"(cfx_none)\"\
    if type(theUnit) == \"string\" then \
        theName = theUnit -- direct name assignment\
        -- WARNING: NO EXIST CHECK DONE!\
    else \
        -- after kill, unit is dead, so will no longer exist!\
        theName = theUnit:getName() \
        if not theName then return false end \
    end\
    if cfxPlayerScore.typeScore[theName] then \
        return true\
    end\
    return false \
end\
\
function cfxPlayerScore.awardScoreTo(killSide, theScore, killerName)\
    local playerScore \
    if theScore < 0 then \
        playerScore = cfxPlayerScore.updateScoreForPlayerImmediate(killerName, theScore)\
    else \
        playerScore = cfxPlayerScore.updateScoreForPlayer(killerName, theScore)\
    end\
    \
    if not cfxPlayerScore.reportScore then return end \
    \
    if cfxPlayerScore.announcer then\
        if (theScore > 0) and cfxPlayerScore.deferred then \
            thePlayerRecord = cfxPlayerScore.getPlayerScore(killerName) -- re-read after write\
            trigger.action.outTextForCoalition(killSide, \"Killscore:  \" .. theScore .. \", now \" .. thePlayerRecord.scoreaccu .. \" waiting for \" .. killerName .. \", awarded after landing\", 30)\
        else -- negative score or not deferred \
            trigger.action.outTextForCoalition(killSide, \"Killscore:  \" .. theScore .. \" for a total of \" .. playerScore .. \" for \" .. killerName, 30)\
            \
            if cfxPlayerScore.reportCoalition then \
                trigger.action.outTextForCoalition(killSide, \"\\nCoalition Total:  \" .. cfxPlayerScore.coalitionScore[killSide], 30)\
            end \
        end\
    end \
end\
\
--\
-- EVENT HANDLING\
--\
function cfxPlayerScore.linkUnitWithPlayer(theUnit)\
    -- create the entries for lookup and reverseLooup tables\
    local uName = theUnit:getName()\
    local pName = theUnit:getPlayerName()\
    cfxPlayerScore.unit2player[uName] = pName \
    --cfxPlayerScore.player2unit[pName] = uName -- is this needed?\
end\
\
function cfxPlayerScore.unlinkUnit(theUnit)\
    local uName = theUnit:getName()\
    cfxPlayerScore.unit2player[uName] = nil     \
end\
\
function cfxPlayerScore.preProcessor(theEvent)\
    -- return true if the event should be processed\
    -- by us\
    if theEvent.initiator  == nil then \
        return false \
    end \
\
    -- check if this was FORMERLY a player plane \
    local theUnit = theEvent.initiator \
    local uName = theUnit:getName()\
    if cfxPlayerScore.unit2player[uName] then \
        -- this requires special IMMEDIATE handling when event is\
        -- one of the below         \
        if theEvent.id == 5 or -- crash \
           theEvent.id == 8 or -- dead \
           theEvent.id == 9 or -- pilot_dead\
           theEvent.id == 30 or -- unit loss \
           theEvent.id == 6 then -- eject \
            -- these can lead to a pilot demerit\
            --trigger.action.outText(\"PREPROC plane player extra event - possible death\", 30)\
            -- event does NOT have a player\
            cfxPlayerScore.handlePlayerDeath(theEvent)\
            return false \
        end \
    end\
    \
    -- initiator must be player \
    if not theUnit.getPlayerName or  \
       not theUnit:getPlayerName() then \
       return false \
    end \
    \
    if theEvent.id == 28 then\
        -- we only are interested in kill events where \
        -- there is a target  \
        local killer = theEvent.initiator \
        if theEvent.target == nil then \
            if cfxPlayerScore.verbose then \
                trigger.action.outText(\"+++scr pre: nil TARGET\", 30) \
            end \
            return false \
        end \
        \
        -- if there are kill zones, we filter all kills that happen outside of kill zones \
        if #cfxPlayerScore.killZones > 0 then\
            local pLoc = theUnit:getPoint() \
            local tLoc = theEvent.target:getPoint()\
            local isIn, percent, dist, theZone = cfxZones.pointInOneOfZones(tLoc, cfxPlayerScore.killZones)\
        \
            if not isIn then \
                if cfxPlayerScore.verbose then \
                    trigger.action.outText(\"+++pScr: kill detected, but target <\" .. theEvent.target:getName() .. \"> was outside of any kill zones\", 30)\
                end\
                return false \
            end\
        \
            if theZone.duet and not cfxZones.pointInZone(pLoc, theZone) then \
                -- player must be in same zone but was not\
                if cfxPlayerScore.verbose then \
                    trigger.action.outText(\"+++pScr: kill detected, but player <\" .. theUnit:getPlayerName() .. \"> was outside of kill zone <\" .. theZone.name .. \">\", 30)\
                end\
                return false\
            end            \
        end\
        return true \
    end\
    \
    -- birth event for players initializes score if \
    -- not existed, and nils the queue \
    if theEvent.id == 15 then \
        -- player birth\
        -- link player and unit\
        cfxPlayerScore.linkUnitWithPlayer(theUnit)\
        return true \
    end\
    \
    -- take off. overwrites timestamp for last landing \
    -- so a blipping t/o does nor count. Pre-proc only \
    if theEvent.id == 3 then \
        local now = timer.getTime()\
        local playerName = theUnit:getPlayerName() \
        cfxPlayerScore.lastPlayerLanding[playerName] = now -- overwrite \
        return false \
    end\
    \
    -- landing can score. but only the first landing in x seconds\
    -- landing in safe zone promotes any queued scores to \
    -- permanent if enabled, then nils queue\
    if theEvent.id == 4 then \
        -- player landed. filter multiple landed events\
        local now = timer.getTime()\
        local playerName = theUnit:getPlayerName() \
        local lastLanding = cfxPlayerScore.lastPlayerLanding[playerName]\
        cfxPlayerScore.lastPlayerLanding[playerName] = now -- overwrite \
        if lastLanding and lastLanding + cfxPlayerScore.delayBetweenLandings > now then \
            if cfxPlayerScore.verbose then \
                trigger.action.outText(\"+++pScr: Player <\" .. playerName .. \"> touch-down ignored: too soon.\", 30)\
                trigger.action.outText(\"now is <\" .. now .. \">, between is <\" .. cfxPlayerScore.delayBetweenLandings .. \">, last + between is <\" .. lastLanding + cfxPlayerScore.delayBetweenLandings .. \">\", 30)\
            end \
            -- filter this event \
            return false \
        end\
        return true \
    end\
    \
    return false \
end\
\
function cfxPlayerScore.postProcessor(theEvent)\
    -- don't do anything\
end\
\
function cfxPlayerScore.isStaticObject(theUnit) \
    if not theUnit.getGroup then return true end \
    local aGroup = theUnit:getGroup()\
    if aGroup then return false end \
    return true \
end\
\
function cfxPlayerScore.checkKillFeat(name, killer, victim, fratricide)\
    if not fratricide then fratricide = false end \
    local theLoc = victim:getPoint() -- vic's loc is relevant for zone check\
    local coa = killer:getCoalition() \
    \
    local killFeats = cfxPlayerScore.featsForLocation(name, theLoc, coa,\"KILL\", killer, victim)\
    \
    if (not fratricide) and #killFeats > 0 then \
\
        -- use the feat description\
        -- we may want to use closest, currently simply the first \
        theFeatZone = killFeats[1]\
        local desc = cfxPlayerScore.evalFeatDescription(name, theFeatZone, killer, victim)  -- updates awardedTo\
                    \
        cfxPlayerScore.logFeatForPlayer(name, desc, playerSide)\
        theScore = cfxPlayerScore.getPlayerScore(name) -- re-read after write\
        \
        if cfxPlayerScore.verbose then \
            trigger.action.outText(\"Kill feat awarded/queued for <\" .. name .. \">\", 30)\
        end\
    end\
\
end\
\
function cfxPlayerScore.killDetected(theEvent)\
    -- we are only getting called when and if \
    -- a kill occured and killer was a player \
    -- and target exists\
    local killer = theEvent.initiator\
    local killerName = killer:getPlayerName()\
    if not killerName then killerName = \"<nil>\" end\
    local killSide = killer:getCoalition()\
    local killVehicle = killer:getTypeName()\
    if not killVehicle then killVehicle = \"<nil>\" end \
    local victim = theEvent.target\
\
    -- was it a player kill?\
    local pk = dcsCommon.isPlayerUnit(victim)\
\
    -- was it a scenery object? \
    local wasBuilding = dcsCommon.isSceneryObject(victim)\
    if wasBuilding then \
        -- these objects have no coalition; we simply award the score if \
        -- it exists in look-up table. \
        --trigger.action.outText(\"KILL SCENERY\", 30)\
        local staticScore = cfxPlayerScore.object2score(victim)\
        if staticScore > 0 then \
            trigger.action.outSoundForCoalition(killSide, cfxPlayerScore.scoreSound)\
            cfxPlayerScore.awardScoreTo(killSide, staticScore, killerName)\
            cfxPlayerScore.checkKillFeat(killerName, killer, victim, false)\
        end\
        return \
    end\
\
    -- was it fratricide?\
    local vicSide = victim:getCoalition()\
    local fraternicide = killSide == vicSide\
    local vicDesc = victim:getTypeName()\
    local scoreMod = 1 -- start at one \
\
    -- see what kind of unit (category) we killed\
    -- and look up base score \
    local isStO = cfxPlayerScore.isStaticObject(victim) \
    --if not victim.getGroup then\
    if isStO then \
        -- static objects have no group \
        \
        local staticName = victim:getName() -- on statics, this returns \
                                            -- name as entered in TOP LINE\
        local staticScore = cfxPlayerScore.object2score(victim)\
\
        if staticScore > 0 then \
            -- this was a named static, return the score - unless our own\
            if fraternicide then \
                scoreMod = cfxPlayerScore.ffMod * scoreMod -- blue on blue static kill\
                trigger.action.outSoundForCoalition(killSide, cfxPlayerScore.badSound)\
            else \
                trigger.action.outSoundForCoalition(killSide, cfxPlayerScore.scoreSound)\
            end\
            staticScore = scoreMod * staticScore\
            cfxPlayerScore.logKillForPlayer(killerName, victim)\
            cfxPlayerScore.awardScoreTo(killSide, staticScore, killerName)\
        else \
            -- no score, no mentions\
        end\
        \
        if not fraternicide then \
            cfxPlayerScore.checkKillFeat(killerName, killer, victim, false)\
        end \
        \
        \
        return \
    end \
    \
    local vicGroup = victim:getGroup()\
    if not vicGroup then \
        trigger.action.outText(\"+++scr: strange stuff:group, outta here\", 30)\
        return \
    end \
    local vicCat = vicGroup:getCategory()\
        if not vicCat then \
        trigger.action.outText(\"+++scr: strange stuff:cat, outta here\", 30)\
        return \
    end\
    local unitScore = cfxPlayerScore.unit2score(victim)\
\
    -- see which weapon was used. gun kills score 2x \
    local killMeth = \"\"\
    local killWeap = theEvent.weapon\
    --[[--\
    if killWeap then \
        local killWeapType = killWeap:getCategory()\
        if killWeapType == 0 then \
            killMeth = \" with GUNS\" \
            scoreMod = scoreMod * 2\
        else \
            local kWeapon = killWeap:getTypeName()\
            killMeth = \" with \" .. kWeapon\
        end        \
    end\
    --]]--\
    if pk then \
        vicDesc = victim:getPlayerName() .. \" in \" .. vicDesc \
        scoreMod = scoreMod * cfxPlayerScore.pkMod\
    end \
\
    \
    -- if fratricide, times ffMod (friedlyFire) \
    if fraternicide then\
        scoreMod = scoreMod * cfxPlayerScore.ffMod ---2\
        if cfxPlayerScore.announcer then \
            trigger.action.outTextForCoalition(killSide, killerName .. \" in \" .. killVehicle .. \" killed FRIENDLY \" .. vicDesc .. killMeth .. \"!\", 30)\
            trigger.action.outSoundForCoalition(killSide, cfxPlayerScore.badSound)\
        end \
    else \
        if cfxPlayerScore.announcer then \
            trigger.action.outText(killerName .. \" in \" .. killVehicle ..\" killed \" .. vicDesc .. killMeth ..\"!\", 30)\
            trigger.action.outSoundForCoalition(vicSide, cfxPlayerScore.badSound)\
            trigger.action.outSoundForCoalition(killSide, cfxPlayerScore.scoreSound)\
         end \
         -- since not fraticide, log this kill\
         -- logging kills does not impact score\
         cfxPlayerScore.logKillForPlayer(killerName, victim)\
    end\
    \
    -- see if it was a named target \
    if cfxPlayerScore.isNamedUnit(victim) then \
        if cfxPlayerScore.announcer then \
            trigger.action.outTextForCoalition(killSide, killerName .. \" reports killing strategic unit '\" .. victim:getName() .. \"'\", 30)\
        end \
    end\
    \
    local totalScore = unitScore * scoreMod\
    -- if the score is negative, awardScoreTo will automatically\
    -- make it immediate, else depending on deferred \
    cfxPlayerScore.awardScoreTo(killSide, totalScore, killerName)\
\
    if not fraternicide then \
        -- only award kill feats for kills of the enemy\
        cfxPlayerScore.checkKillFeat(killerName, killer, victim, false)\
    end \
\
end\
\
function cfxPlayerScore.handlePlayerLanding(theEvent)\
    local thePlayerUnit = theEvent.initiator\
    local theLoc = thePlayerUnit:getPoint()     \
    local playerSide = thePlayerUnit:getCoalition()\
    local playerName = thePlayerUnit:getPlayerName()\
    if cfxPlayerScore.verbose then \
        trigger.action.outText(\"+++pScr: Player <\" .. playerName .. \"> landed\", 30)\
    end\
    \
    local theScore = cfxPlayerScore.getPlayerScore(playerName)\
    \
    -- see if a feat is available for this landing \
    local landingFeats = cfxPlayerScore.featsForLocation(playerName, theLoc, playerSide,\"LANDING\")\
    \
    -- first, scheck if landing is awardable, and if so, \
    -- award the landing \
    if cfxPlayerScore.landing > 0 or #landingFeats > 0 then \
        -- yes, landings are awarded a score. do before \
        -- resolving any queues \
        desc = \"Landed\"\
        if #landingFeats > 0 then \
            -- use the feat description\
            -- we may want to use closest, currently simply the first \
            theFeatZone = landingFeats[1]\
            desc = cfxPlayerScore.evalFeatDescription(playerName, theFeatZone, thePlayerUnit) -- nil victim, defaults to player \
            \
        else \
            if theEvent.place then \
                desc = desc .. \" successfully (\" .. theEvent.place:getName() .. \")\"\
            else \
                desc = desc .. \" aircraft\"\
            end\
        end \
        \
        cfxPlayerScore.updateScoreForPlayer(playerName, cfxPlayerScore.landing)\
        cfxPlayerScore.logFeatForPlayer(playerName, desc, playerSide)\
        theScore = cfxPlayerScore.getPlayerScore(playerName) -- re-read after write\
        if cfxPlayerScore.verbose then \
            trigger.action.outText(\"Landing feat awarded/queued for <\" .. playerName .. \">\", 30)\
        end\
    end\
    \
    -- see if we are using deferred scoring, else can end right now \
    if not cfxPlayerScore.deferred then \
        return \
    end\
    -- only continue if there is anything to award \
    local killSize = dcsCommon.getSizeOfTable(theScore.killQueue)\
    local featSize = dcsCommon.getSizeOfTable(theScore.featQueue)\
    \
    if cfxPlayerScore.verbose then \
        trigger.action.outText(\"+++pScr: prepping deferred score for <\" .. playerName ..\">\", 30)\
    end\
    \
    -- see if player landed in a scoreSafe zone \
    local theUnit = thePlayerUnit\
    local loc = theUnit:getPoint()\
    local uid = theUnit:getID()\
    local coa = theUnit:getCoalition()\
    local isSafe = false \
    for idx, theZone in pairs(cfxPlayerScore.safeZones) do \
        if theZone.scoreSafe == 0 or theZone.scoreSafe == coa then \
            -- make sure that this zone doesn't belong to the \
            -- wrong faction (if owned zone) \
            if (theZone.owner == coa) or (theZone.owner == 0) or (theZone.owner == nil) then \
                if cfxZones.pointInZone(loc, theZone) then \
                    isSafe = true\
                end\
            else \
                if cfxPlayerScore.verbose then \
                    trigger.action.outText(\"+++pSc: Zone <\" .. theZone.name .. \">: owner=<\" .. theZone.owner .. \">, my coa=<\" .. coa .. \">, no owner match\")\
                end\
            end\
        end \
    end\
    \
    if not isSafe then \
        if cfxPlayerScore.verbose then \
            trigger.action.outText(\"+++pScr: deferred, but not inside score safe zone.\", 30)\
        end\
        return \
    end \
    \
    trigger.action.outTextForUnit(uid, playerName .. \", please wait in safe zone to claim pending score/feats (\" .. cfxPlayerScore.delayAfterLanding .. \" seconds).\", 30)\
\
    local unitName = theUnit:getName()\
    local args = {playerName, unitName}\
    timer.scheduleFunction(cfxPlayerScore.scheduledAward, args, timer.getTime() + cfxPlayerScore.delayAfterLanding)\
end\
\
function cfxPlayerScore.scheduledAward(args)\
    -- called with player name and unit name in args \
    local playerName = args[1]\
    local unitName = args[2]\
    \
    local theUnit = Unit.getByName(unitName)\
    if not theUnit or \
       not Unit.isExist(theUnit) \
    then \
        -- unit is gone\
        trigger.action.outText(\"Player <\" .. playerName .. \"> lost score.\", 30)\
        return \
    end\
    \
    local uid = theUnit:getID()\
    if theUnit:inAir() then \
        trigger.action.outTextForUnit(uid, \"Can't award score to <\" .. playerName .. \">: unit not on the ground.\", 30)\
        return \
    end\
    \
    if theUnit:getLife() < 1 then \
        trigger.action.outTextForUnit(uid, \"Can't award score to <\" .. playerName .. \">: unit did not survive landing.\", 30)\
        return  -- needs to reslot, don't have to nil player score\
    end\
    \
    -- see if player is *still* within a scoreSafe zone \
    local loc = theUnit:getPoint()\
    local coa = theUnit:getCoalition()\
    local isSafe = false \
    for idx, theZone in pairs(cfxPlayerScore.safeZones) do \
        if theZone.scoreSafe == 0 or theZone.scoreSafe == coa then\
            -- we no longer check ownership of zone, we did that when we landed\
            if cfxZones.pointInZone(loc, theZone) then \
                isSafe = true\
            end\
        end \
    end\
    \
    if not isSafe then \
        trigger.action.outTextForUnit(uid, \"Can't award score for <\" .. playerName .. \">, not in safe zone.\", 30)\
        return \
    end \
    \
    \
    local theScore = cfxPlayerScore.getPlayerScore(playerName)\
    local playerSide = dcsCommon.playerName2Coalition(playerName)\
    if playerSide < 1 then\
        trigger.action.outText(\"+++pScr: WARNING - unaffiliated player <\" .. playerName .. \">, score award ignored\", 30)\
        return \
    end \
    if dcsCommon.getSizeOfTable(theScore.killQueue) < 1 and \
       dcsCommon.getSizeOfTable(theScore.featQueue) < 1 and \
       theScore.scoreaccu < 1 then \
        -- player changed planes or \
        -- there was nothing to award \
        trigger.action.outTextForUnit(uid, \"Thank you, \" .. playerName .. \", no scores or feats pending.\", 30)\
        return \
    end\
    \
    local hasAward = false \
    \
    -- when we get here we award all scores, kills, and feats \
    local desc = \"\\nPlayer \" .. playerName .. \" is awarded:\\n\"\
    -- score and total score \
    if theScore.scoreaccu > 0 then -- remember: negatives are immediate \
        theScore.score = theScore.score + theScore.scoreaccu\
        desc = desc .. \"  score: \" .. theScore.scoreaccu .. \" for a new total of \" .. theScore.score .. \"\\n\"\
        cfxPlayerScore.coalitionScore[playerSide] = cfxPlayerScore.coalitionScore[playerSide] + theScore.scoreaccu\
        theScore.scoreaccu = 0 \
        hasAward = true \
    end \
    \
    if cfxPlayerScore.verbose then \
        trigger.action.outText(\"Iterating kill q <\" .. dcsCommon.getSizeOfTable(theScore.killQueue) .. \"> and feat q <\" .. dcsCommon.getSizeOfTable(theScore.featQueue) .. \">\", 30)\
    end\
    -- iterate kill type list \
    if dcsCommon.getSizeOfTable(theScore.killQueue) > 0 then \
        desc = desc .. \"  confirmed kills in order:\\n\"\
        for idx, theType in pairs(theScore.killQueue) do \
            desc = desc .. \"    \" .. theType .. \"\\n\"\
            cfxPlayerScore.doLogTypeKill(playerName, theScore, theType)\
        end\
        hasAward = true \
    end\
    theScore.killQueue = {}\
    \
    -- iterate feats \
    if dcsCommon.getSizeOfTable(theScore.featQueue) > 0 then \
        desc = desc .. \"  confirmed feats:\\n\"\
        for idx, theFeat in pairs(theScore.featQueue) do \
            desc = desc .. \"    \" .. theFeat .. \"\\n\"\
            cfxPlayerScore.doLogFeat(playerName, theScore, theFeat)\
        end\
        hasAward = true \
    end\
    theScore.featQueue = {}\
    \
    if cfxPlayerScore.reportCoalition then \
        desc = desc .. \"\\nCoalition Total: \" .. cfxPlayerScore.coalitionScore[playerSide]\
    end\
    \
    -- output score \
    desc = desc .. \"\\n\"\
    if hasAward then \
        trigger.action.outTextForCoalition(coa, desc, 30)\
    end \
end\
\
function cfxPlayerScore.handlePlayerDeath(theEvent)\
    -- multiple of these events can occur per player \
    -- so we use the unit2player link to see player \
    -- is affected, and if so, erase the link so it \
    -- only counts once \
    local theUnit = theEvent.initiator \
    local uName = theUnit:getName()\
    \
    if cfxPlayerScore.verbose then \
        trigger.action.outText(\"+++pScr: LOA/player death handler entry for <\" .. uName .. \">\", 30)\
    end\
    \
    local pName = cfxPlayerScore.unit2player[uName] \
    if pName then \
        -- this was a player name with link still live.\
        if cfxPlayerScore.planeLoss ~= 0 then \
            -- plane loss has IMMEDIATE consequences \
            cfxPlayerScore.updateScoreForPlayerImmediate(pName, cfxPlayerScore.planeLoss)\
            if cfxPlayerScore.announcer then \
                local uid = theUnit:getID()\
                local thePlayerRecord = cfxPlayerScore.getPlayerScore(pName)\
                trigger.action.outTextForUnit(uid, \"Loss of aircraft detected: \" .. cfxPlayerScore.planeLoss .. \" awarded immediately, for new total of \" .. thePlayerRecord.score, 30)\
            end\
        end\
        -- always clear the link.\
        cfxPlayerScore.unit2player[uName] = nil\
    else \
        if cfxPlayerScore.verbose then \
            trigger.action.outText(\"+++pScr - no action for LOA\", 30)\
        end\
    end\
\
end\
\
function cfxPlayerScore.handlePlayerEvent(theEvent)\
    if theEvent.id == 28 then \
        -- kill from player detected.\
        cfxPlayerScore.killDetected(theEvent)    \
        \
    elseif theEvent.id == 15 then -- birth \
        -- access player score for player. this will \
        -- allocate if doesn't exist. Any player ever \
        -- birthed will be in db\
        local thePlayerUnit = theEvent.initiator \
        local playerSide = thePlayerUnit:getCoalition()\
        local playerName = thePlayerUnit:getPlayerName()\
        local theScore = cfxPlayerScore.getPlayerScore(playerName)\
        -- now re-init feat and score queues \
        \
        if theScore.scoreaccu and theScore.scoreaccu > 0 then \
            trigger.action.outTextForCoalition(playerSide, \"Player \" .. playerName .. \", score of <\" .. theScore.scoreaccu .. \"> points discarded.\", 30)\
        end \
        theScore.scoreaccu = 0 \
        if dcsCommon.getSizeOfTable(theScore.killQueue) > 0 then \
            trigger.action.outTextForCoalition(playerSide, \"Player \" .. playerName .. \", <\" .. dcsCommon.getSizeOfTable(theScore.killQueue) .. \"> kills discarded.\", 30)\
        end\
        theScore.killQueue = {}\
        if dcsCommon.getSizeOfTable(theScore.featQueue) > 0 then \
            trigger.action.outTextForCoalition(playerSide, \"Player \" .. playerName .. \", <\" .. dcsCommon.getSizeOfTable(theScore.featQueue) .. \"> feats discarded.\", 30)\
        end        \
        theScore.featQueue = {}\
        -- write back\
        cfxPlayerScore.setPlayerScore(playerName, theScore)\
        \
    elseif theEvent.id == 4 then -- land \
        -- see if plane is still connected to player \
        local theUnit = theEvent.initiator\
        local uName = theUnit:getName() \
        if cfxPlayerScore.unit2player[uName] then \
        -- is filtered if too soon after last take-off/landing \
        cfxPlayerScore.handlePlayerLanding(theEvent)\
        else \
            if verbose then \
                trigger.action.outText(\"+++pScr: filtered landing for <\" .. uName .. \">: player no longer linked to unit\", 30)\
            end\
        end    \
\
    end\
end\
\
function cfxPlayerScore.readConfigZone(theZone)\
    cfxPlayerScore.verbose = cfxZones.getBoolFromZoneProperty(theZone, \"verbose\", false)\
    -- default scores \
    cfxPlayerScore.aircraft = cfxZones.getNumberFromZoneProperty(theZone, \"aircraft\", 50) \
    cfxPlayerScore.helo = cfxZones.getNumberFromZoneProperty(theZone, \"helo\", 40)  \
    cfxPlayerScore.ground = cfxZones.getNumberFromZoneProperty(theZone, \"ground\", 10)  \
    cfxPlayerScore.ship = cfxZones.getNumberFromZoneProperty(theZone, \"ship\", 80)   \
    cfxPlayerScore.train = cfxZones.getNumberFromZoneProperty(theZone, \"train\", 5)\
    cfxPlayerScore.landing = cfxZones.getNumberFromZoneProperty(theZone, \"landing\", 0) -- if > 0 then feat \
    \
    cfxPlayerScore.pkMod = cfxZones.getNumberFromZoneProperty(theZone, \"pkMod\", 1) -- factor for killing a player\
    cfxPlayerScore.ffMod = cfxZones.getNumberFromZoneProperty(theZone, \"ffMod\", -2) -- factor for friendly fire \
    cfxPlayerScore.planeLoss = cfxZones.getNumberFromZoneProperty(theZone, \"planeLoss\", -10) -- points added when player's plane crashes\
    \
    cfxPlayerScore.announcer = cfxZones.getBoolFromZoneProperty(theZone, \"announcer\", true)\
    \
    if cfxZones.hasProperty(theZone, \"badSound\") then \
        cfxPlayerScore.badSound = cfxZones.getStringFromZoneProperty(theZone, \"badSound\", \"<nosound>\")\
    end\
    if cfxZones.hasProperty(theZone, \"scoreSound\") then \
        cfxPlayerScore.scoreSound = cfxZones.getStringFromZoneProperty(theZone, \"scoreSound\", \"<nosound>\")\
    end\
    \
    -- triggering saving scores\
    if cfxZones.hasProperty(theZone, \"saveScore?\") then \
        cfxPlayerScore.saveScore = cfxZones.getStringFromZoneProperty(theZone, \"saveScore?\", \"none\")\
        cfxPlayerScore.lastSaveScore = trigger.misc.getUserFlag(cfxPlayerScore.saveScore)\
        cfxPlayerScore.incremental = cfxZones.getBoolFromZoneProperty(theZone, \"incremental\", false) -- incremental saves \
    end\
    \
    -- triggering show all scores\
    if cfxZones.hasProperty(theZone, \"showScore?\") then \
        cfxPlayerScore.showScore = cfxZones.getStringFromZoneProperty(theZone, \"showScore?\", \"none\")\
        cfxPlayerScore.lastShowScore = trigger.misc.getUserFlag(cfxPlayerScore.showScore)\
    end\
    \
    cfxPlayerScore.rankPlayers = cfxZones.getBoolFromZoneProperty(theZone, \"rankPlayers\", false)\
    \
    cfxPlayerScore.scoreOnly = cfxZones.getBoolFromZoneProperty(theZone, \"scoreOnly\", true)\
    \
    cfxPlayerScore.deferred = cfxZones.getBoolFromZoneProperty(theZone, \"deferred\", false)\
    \
    cfxPlayerScore.delayAfterLanding = cfxZones.getNumberFromZoneProperty(theZone, \"delayAfterLanding\", 10)\
    \
    cfxPlayerScore.scoreFileName = cfxZones.getStringFromZoneProperty(theZone, \"scoreFileName\", \"Player Scores\")\
\
    cfxPlayerScore.reportScore = cfxZones.getBoolFromZoneProperty(theZone, \"reportScore\", true)\
    \
    cfxPlayerScore.reportFeats = cfxZones.getBoolFromZoneProperty(theZone, \"reportFeats\", true)\
    \
    cfxPlayerScore.reportCoalition = cfxZones.getBoolFromZoneProperty(\
    theZone, \"reportCoalition\", false) -- also show coalition score \
    \
    cfxPlayerScore.noGrief = cfxZones.getBoolFromZoneProperty(theZone, \"noGrief\", true) -- noGrief = only add positive score \
end\
\
--\
-- load / save (game data)\
--\
function cfxPlayerScore.saveData()\
    local theData = {}\
    -- save current score list. simple clone \
    local theScore = dcsCommon.clone(cfxPlayerScore.playerScore)\
    theData.theScore = theScore\
    -- build feat zone list \
    theData.coalitionScore = dcsCommon.clone(cfxPlayerScore.coalitionScore)\
    local featZones = {}\
    for idx, theZone in pairs(cfxPlayerScore.featZones) do \
        local theFeat = {}\
        theFeat.awardedTo = theZone.awardedTo \
        theFeat.featNum = theZone.featNum \
        featZones[theZone.name] = theFeat\
    end\
    theData.featData = featZones \
    return theData\
end\
\
function cfxPlayerScore.loadData()\
    if not persistence then return end \
    local theData = persistence.getSavedDataForModule(\"cfxPlayerScore\")\
    if not theData then \
        if cfxPlayerScore.verbose then \
            trigger.action.outText(\"+++playerscore: no save date received, skipping.\", 30)\
        end\
        return\
    end\
    \
    local theScore = theData.theScore\
    cfxPlayerScore.playerScore = theScore \
    if theData.coalitionScore then \
        cfxPlayerScore.coalitionScore = theData.coalitionScore\
    end\
    local featData = theData.featData \
    if featData then \
        for name, data in pairs(featData) do \
            local theZone = cfxPlayerScore.getFeatByName(name)\
            if theZone then \
                theZone.awardedTo = data.awardedTo\
                theZone.featNum = data.featNum\
            end\
        end        \
    end \
end\
\
--\
-- save scores (text file)\
--\
\
function cfxPlayerScore.saveScores(theText, name)\
    if not _G[\"persistence\"] then \
        trigger.action.outText(\"+++pScr: persistence module required to save scores. Here are the scores that I would have saved to <\" .. name .. \">:\\n\", 30)\
        trigger.action.outText(theText, 30)\
        return\
    end\
    \
    if not persistence.active then \
        trigger.action.outText(\"+++pScr: persistence module can't write. Please ensure that you have desanitized lfs and io for DCS\", 30)\
        return \
    end\
    \
    local append = cfxPlayerScore.incremental\
    local shared = false -- currently not supported\
\
    if cfxPlayerScore.incremental then \
        if cfxPlayerScore.firstSave then \
            theText = \"\\n*** NEW MISSION started.\\n\" .. theText\
        end\
        \
        -- prepend time for score \
        theText = \"\\n\\n====== Mission Time: \" .. dcsCommon.nowString() .. \"\\n\" .. theText\
    end \
    \
    if persistence.saveText(theText, name, shared, append) then \
        if cfxPlayerScore.verbose then \
            trigger.action.outText(\"+++pScr: scores saved to <\" .. persistence.missionDir .. name .. \">\", 30)\
        end\
    else \
        trigger.action.outText(\"+++pScr: unable to save scores to <\" .. persistence.missionDir .. name .. \">\")\
    end\
    \
    cfxPlayerScore.firstSave  = false \
end\
\
function cfxPlayerScore.saveScoreToFile()\
    -- local built score table \
    local ranked = cfxPlayerScore.rankPlayers\
    local theText = cfxPlayerScore.scoreTextForAllPlayers(ranked) \
    \
    -- save to disk \
    cfxPlayerScore.saveScores(theText, cfxPlayerScore.scoreFileName)\
end\
\
function cfxPlayerScore.showScoreToAll()\
    local ranked = cfxPlayerScore.rankPlayers\
    local theText = cfxPlayerScore.scoreTextForAllPlayers(ranked) \
    trigger.action.outText(theText, 30)\
end\
\
--\
-- Update\
--\
function cfxPlayerScore.update()\
    -- re-invoke in 1 second\
    timer.scheduleFunction(cfxPlayerScore.update, {}, timer.getTime() + 1)\
    \
    -- see if someone banged on saveScore\
    if cfxPlayerScore.saveScore then \
        if cfxZones.testZoneFlag(cfxPlayerScore, cfxPlayerScore.saveScore, \"change\", \"lastSaveScore\") then \
            if cfxPlayerScore.verbose then \
                trigger.action.outText(\"+++pScr: saving scores...\", 30)\
            end\
            cfxPlayerScore.saveScoreToFile()\
        end\
    end\
    \
    -- showScore perhaps?\
    if cfxPlayerScore.showScore then \
        if cfxZones.testZoneFlag(cfxPlayerScore, cfxPlayerScore.showScore, \"change\", \"lastShowScore\") then \
            if cfxPlayerScore.verbose then \
                trigger.action.outText(\"+++pScr: showing scores...\", 30)\
            end\
            cfxPlayerScore.showScoreToAll()\
        end\
    end\
    \
    -- check score flags \
    if cfxPlayerScore.blueTriggerFlags then \
        local coa = 2\
        for tName, tVal in pairs(cfxPlayerScore.blueTriggerFlags) do \
            local newVal = trigger.misc.getUserFlag(tName)\
            if tVal ~= newVal then \
                -- score!\
                cfxPlayerScore.coalitionScore[coa] = cfxPlayerScore.coalitionScore[coa] + cfxPlayerScore.blueTriggerScore[tName]\
                cfxPlayerScore.blueTriggerFlags[tName] = newVal\
                if cfxPlayerScore.announcer then\
                    trigger.action.outTextForCoalition(coa, \"BLUE goal [\" .. tName .. \"] achieved, new BLUE coalition score is \" .. cfxPlayerScore.coalitionScore[coa], 30)\
                    trigger.action.outSoundForCoalition(coa, cfxPlayerScore.scoreSound)\
                end\
            end\
        end\
    end\
    if cfxPlayerScore.redTriggerFlags then \
        local coa = 1\
        for tName, tVal in pairs(cfxPlayerScore.redTriggerFlags) do \
            local newVal = trigger.misc.getUserFlag(tName)\
--                trigger.action.outText(\"checking RED flag <\" .. tName .. \">\", 30)\
                if tVal ~= newVal then \
                -- score!\
\
                cfxPlayerScore.coalitionScore[coa] = cfxPlayerScore.coalitionScore[coa] + cfxPlayerScore.redTriggerScore[tName]\
                cfxPlayerScore.redTriggerFlags[tName] = newVal\
                if cfxPlayerScore.announcer then\
                    trigger.action.outTextForCoalition(coa, \"RED goal [\" .. tName .. \"] achieved, new RED coalition score is \" .. cfxPlayerScore.coalitionScore[coa], 30)\
                    trigger.action.outSoundForCoalition(coa, cfxPlayerScore.scoreSound)\
                end\
            end\
        end\
    end\
end\
--\
-- start\
--\
function cfxPlayerScore.start()\
    if not dcsCommon.libCheck(\"cfx Player Score\", \
                              cfxPlayerScore.requiredLibs) \
    then \
        return false \
    end\
    \
    -- read my score table \
    -- identify and process a score table zones\
    local theZone = cfxZones.getZoneByName(\"playerScoreTable\") \
    if not theZone then \
        trigger.action.outText(\"+++scr: no score table!\", 30) \
    else \
        -- read all into my types registry, replacing whatever is there\
        cfxPlayerScore.typeScore = cfxZones.getAllZoneProperties(theZone)\
        trigger.action.outText(\"+++scr: read score table\", 30) \
    end \
    \
    -- read score tiggers and values\
    cfxPlayerScore.redTriggerFlags = nil\
    cfxPlayerScore.blueTriggerFlags = nil\
    local theZone = cfxZones.getZoneByName(\"redScoreFlags\") \
    if theZone then \
        -- read flags into redTriggerScore\
        cfxPlayerScore.redTriggerScore = cfxZones.getAllZoneProperties(theZone, false, true) -- use case, all numbers \
        -- init their flag handlers \
        cfxPlayerScore.redTriggerFlags = {}\
        trigger.action.outText(\"+++pScr: read RED score table\", 30)\
        for tName, tScore in pairs(cfxPlayerScore.redTriggerScore) do \
            if tScore == 0 then \
                trigger.action.outText(\"+++pScr: WARNING - RED triggered score <\" .. tName .. \"> has zero score value!\", 30)\
            end\
            cfxPlayerScore.redTriggerFlags[tName] = trigger.misc.getUserFlag(tName)\
--            trigger.action.outText(\"+++pScr: RED trigger <\" .. tName .. \">, score value (\" .. tScore .. \") inited to <\" .. cfxPlayerScore.redTriggerFlags[tName] .. \">\", 30)\
        end\
    end \
    local theZone = cfxZones.getZoneByName(\"blueScoreFlags\") \
    if theZone then \
        -- read flags into redTriggerScore\
        cfxPlayerScore.blueTriggerScore = cfxZones.getAllZoneProperties(theZone, false, true) -- case sensitive, numbers only\
        -- init their flag handlers \
        cfxPlayerScore.blueTriggerFlags = {}\
        trigger.action.outText(\"+++pScr: read BLUE score table\", 30)\
        for tName, tScore in pairs(cfxPlayerScore.blueTriggerScore) do\
            if tScore == 0 then \
                trigger.action.outText(\"+++pScr: WARNING - BLUE triggered score <\" .. tName .. \"> has zero score value!\", 30)\
            end        \
            cfxPlayerScore.blueTriggerFlags[tName] = trigger.misc.getUserFlag(tName)\
--            trigger.action.outText(\"+++pScr: BLUE trigger <\" .. tName .. \">, score value (\" .. tScore .. \") inited to <\" .. cfxPlayerScore.blueTriggerFlags[tName] .. \">\", 30)\
        end\
    end \
    \
    -- now read my config zone \
    local theZone = cfxZones.getZoneByName(\"playerScoreConfig\") \
    if not theZone then \
        trigger.action.outText(\"+++pScr: no config!\", 30) \
        theZone = cfxZones.createSimpleZone(\"playerScoreConfig\")\
    end \
    cfxPlayerScore.readConfigZone(theZone)\
    --    trigger.action.outText(\"+++scr: read config\", 30) \
     \
    \
    -- read all scoreSafe zones \
    local safeZones = cfxZones.zonesWithProperty(\"scoreSafe\")\
    for k, aZone in pairs(safeZones) do\
        cfxPlayerScore.addSafeZone(aZone)\
    end\
    \
    -- read all feat zones \
    local featZones = cfxZones.zonesWithProperty(\"feat\")\
    for k, aZone in pairs(featZones) do\
        cfxPlayerScore.addFeatZone(aZone)\
    end\
    \
    -- read all kill zones \
    local killZones = cfxZones.zonesWithProperty(\"killZone\")\
    for k, aZone in pairs(killZones) do\
        cfxPlayerScore.addKillZone(aZone)\
    end\
    \
    -- check that deferred has scoreSafe zones \
    if cfxPlayerScore.deferred and dcsCommon.getSizeOfTable(cfxPlayerScore.safeZones) < 1 then \
        trigger.action.outText(\"+++pScr: WARNING - deferred scoring active but no 'scoreSafe' zones set!\", 30)\
    end\
    \
    -- subscribe to events and use dcsCommon's handler structure\
    dcsCommon.addEventHandler(cfxPlayerScore.handlePlayerEvent,\
                              cfxPlayerScore.preProcessor,\
                              cfxPlayerScore.postProcessor)\
                              \
    -- now load all save data and populate map with troops that\
    -- we deployed last save. \
    if persistence then \
        -- sign up for persistence \
        callbacks = {}\
        callbacks.persistData = cfxPlayerScore.saveData\
        persistence.registerModule(\"cfxPlayerScore\", callbacks)\
        -- now load my data \
        cfxPlayerScore.loadData()\
    end\
    \
    -- start update \
    cfxPlayerScore.update()\
        \
    trigger.action.outText(\"cfxPlayerScore v\" .. cfxPlayerScore.version .. \" started\", 30)\
    return true \
end\
\
\
if not cfxPlayerScore.start() then \
    trigger.action.outText(\"+++ aborted cfxPlayerScore v\" .. cfxPlayerScore.version .. \"  -- libcheck failed\", 30)\
    cfxPlayerScore = nil \
end\
\
-- TODO: score mod for weapons type \
-- TODO: player kill score \
\
--[[--\
\
feat zone\
\"feat\" feat type, default is kill, possible other types \
    - landing \
score zones \
    - zones outside of which no scoring counts, but feats are still ok \
    \
- add take off feats\
\
can be extended with other, standalone feat modules that follow the \
same pattern, e.g. enter a zone, detect someone \
\
--]]--\
 ",
                    ["predicate"] = "a_do_script",
                }, -- end of [4]
                [5] = 
                {
                    ["text"] = "radioMenu = {}\
radioMenu.version = \"2.0.1\"\
radioMenu.verbose = false \
radioMenu.ups = 1 \
radioMenu.requiredLibs = {\
    \"dcsCommon\", -- always\
    \"cfxZones\", -- Zones, of course \
}\
radioMenu.menus = {}\
\
--[[--\
    Version History \
    1.0.0 Initial version \
    1.0.1 spelling corrections\
    1.1.0 removeMenu \
          addMenu \
          menuVisible \
    2.0.0 redesign: handles multiple receivers\
          optional MX module \
          group option\
          type option\
          multiple group names \
          multiple types \
          gereric helo type \
          generic plane type \
          type works with coalition \
    2.0.1 corrections to installMenu(), as suggested by GumidekCZ\
\
    \
--]]--\
\
function radioMenu.addRadioMenu(theZone)\
    table.insert(radioMenu.menus, theZone)\
end\
\
function radioMenu.getRadioMenuByName(aName) \
    for idx, aZone in pairs(radioMenu.menus) do \
        if aName == aZone.name then return aZone end \
    end\
    if radioMenu.verbose then \
        trigger.action.outText(\"+++radioMenu: no radioMenu with name <\" .. aName ..\">\", 30)\
    end \
    \
    return nil \
end\
\
--\
-- read zone \
-- \
function radioMenu.filterPlayerIDForType(theZone)\
    -- note: we currently ignore coalition \
    local theIDs = {}\
    local allTypes = {}\
    if dcsCommon.containsString(theZone.menuTypes, \",\") then \
        allTypes = dcsCommon.splitString(theZone.menuTypes, \",\")\
    else \
        table.insert(allTypes, theZone.menuTypes)\
    end\
    \
    -- now iterate all types, and include any player that matches\
    -- note that a player may match twice, so we use a dict instead of an \
    -- array. Since we later iterate ID by idx, that's not an issue\
    \
    for idx, aType in pairs(allTypes) do \
        local theType = dcsCommon.trim(aType)\
        local lowerType = string.lower(theType)\
        \
        for gName, gData in pairs(cfxMX.playerGroupByName) do \
            -- get coalition of group \
            local coa = cfxMX.groupCoalitionByName[gName]\
            if (theZone.coalition == 0 or theZone.coalition == coa) then \
                -- do special types first \
                if dcsCommon.stringStartsWith(lowerType, \"helo\") or dcsCommon.stringStartsWith(lowerType, \"heli\") then \
                    -- we look for all helicoperts\
                    if cfxMX.groupTypeByName[gName] == \"helicopter\" then \
                        theIDs[gName] = gData.groupId\
                        if theZone.verbose or radioMenu.verbose then \
                            trigger.action.outText(\"+++menu: Player Group <\" .. gName .. \"> matches gen-type helicopter\", 30)\
                        end\
                    end\
                elseif lowerType == \"plane\" or lowerType == \"planes\" then \
                    -- we look for all planes \
                    if cfxMX.groupTypeByName[gName] == \"plane\" then \
                        theIDs[gName] = gData.groupId\
                        if theZone.verbose or radioMenu.verbose then \
                            trigger.action.outText(\"+++menu: Player Group <\" .. gName .. \"> matches gen-type plane\", 30)\
                        end\
                    end\
                else\
                    -- we are looking for a particular type, e.g. A-10A\
                    -- since groups do not carry the type, but all player\
                    -- groups are of the same type, we access the first \
                    -- unit. Note that this may later break if ED implement \
                    -- player groups of mixed type \
                    if gData.units and gData.units[1] and gData.units[1].type == theType then \
                        theIDs[gName] = gData.groupId\
                        if theZone.verbose or radioMenu.verbose then \
                            trigger.action.outText(\"+++menu: Player Group <\" .. gName .. \"> matches type <\" .. theType .. \">\", 30)\
                        end\
                    else \
                        \
                    end\
                end\
            else \
                if theZone.verbose or radioMenu.verbose then \
                    trigger.action.outText(\"+++menu: type check failed coalition for <\" .. gName .. \">\", 30)\
                end\
            end\
        end\
    end\
    return theIDs\
end\
\
function radioMenu.filterPlayerIDForGroup(theZone)\
    -- create an iterable list of groups, separated by commas \
    -- note that we could introduce wildcards for groups later\
    local theIDs = {}\
    local allGroups = {}\
    if dcsCommon.containsString(theZone.menuGroup, \",\") then \
        allGroups = dcsCommon.splitString(theZone.menuGroup, \",\")\
    else \
        table.insert(allGroups, theZone.menuGroup)\
    end\
\
    for idx, gName in pairs(allGroups) do \
        gName = dcsCommon.trim(gName)\
        local theGroup = cfxMX.playerGroupByName[gName]\
        if theGroup then \
            local gID = theGroup.groupId\
            table.insert(theIDs, gID)\
            if theZone.verbose or radioMenu.verbose then \
                trigger.action.outText(\"+++menu: Player Group <\" .. gName .. \"> found: <\" .. gID .. \">\", 30)\
            end\
        else \
            trigger.action.outText(\"+++menu: Player Group <\" .. gName .. \"> does not exist\", 30)\
        end\
    end\
\
    return theIDs\
end\
\
function radioMenu.installMenu(theZone)\
--    local theGroup = 0 -- was: nil\
    local gID = nil \
    if theZone.menuGroup then \
        if not cfxMX then \
            trigger.action.outText(\"WARNING: radioMenu's group attribute requires the 'cfxMX' module\", 30)\
            return \
        end\
        -- access cfxMX player info for group ID\
        gID = radioMenu.filterPlayerIDForGroup(theZone)\
    elseif theZone.menuTypes then \
        if not cfxMX then \
            trigger.action.outText(\"WARNING: radioMenu's type attribute requires the 'cfxMX' module\", 30)\
            return \
        end\
        -- access cxfMX player infor with type match for ID\
        gID = radioMenu.filterPlayerIDForType(theZone)\
    end\
    \
    theZone.rootMenu = {}\
    theZone.mcdA = {}\
    theZone.mcdB = {}\
    theZone.mcdC = {}\
    theZone.mcdD = {}\
    theZone.mcdA[0] = 0\
    theZone.mcdB[0] = 0\
    theZone.mcdC[0] = 0\
    theZone.mcdD[0] = 0\
        \
    if theZone.menuGroup or theZone.menuTypes then \
        for idx, grp in pairs(gID) do \
            local aRoot = missionCommands.addSubMenuForGroup(grp, theZone.rootName, nil) \
            theZone.rootMenu[grp] = aRoot\
            theZone.mcdA[grp] = 0\
            theZone.mcdB[grp] = 0\
            theZone.mcdC[grp] = 0\
            theZone.mcdD[grp] = 0\
        end\
    elseif theZone.coalition == 0 then \
        theZone.rootMenu[0] = missionCommands.addSubMenu(theZone.rootName, nil) \
    else \
        theZone.rootMenu[0] = missionCommands.addSubMenuForCoalition(theZone.coalition, theZone.rootName, nil)        \
    end\
    \
    if cfxZones.hasProperty(theZone, \"itemA\") then \
        local menuA = cfxZones.getStringFromZoneProperty(theZone, \"itemA\", \"<no A submenu>\")\
        if theZone.menuGroup or theZone.menuTypes then\
            theZone.menuA = {}\
            for idx, grp in  pairs(gID) do  \
                theZone.menuA[grp] = missionCommands.addCommandForGroup(grp, menuA, theZone.rootMenu[grp], radioMenu.redirectMenuX, {theZone, \"A\", grp}) \
            end\
        elseif theZone.coalition == 0 then \
            theZone.menuA = missionCommands.addCommand(menuA, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, \"A\"})\
        else \
            theZone.menuA = missionCommands.addCommandForCoalition(theZone.coalition, menuA, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, \"A\"})\
        end \
    end \
    \
    if cfxZones.hasProperty(theZone, \"itemB\") then \
        local menuB = cfxZones.getStringFromZoneProperty(theZone, \"itemB\", \"<no B submenu>\")\
        if theZone.menuGroup or theZone.menuTypes then \
            theZone.menuB = {}\
            for idx, grp in  pairs(gID) do \
                theZone.menuB[grp] = missionCommands.addCommandForGroup(grp, menuB, theZone.rootMenu[grp], radioMenu.redirectMenuX, {theZone, \"B\", grp}) \
            end\
        elseif theZone.coalition == 0 then \
            theZone.menuB = missionCommands.addCommand(menuB, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, \"B\"})\
        else \
            theZone.menuB = missionCommands.addCommandForCoalition(theZone.coalition, menuB, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, \"B\"})\
        end\
    end\
\
    if cfxZones.hasProperty(theZone, \"itemC\") then \
        local menuC = cfxZones.getStringFromZoneProperty(theZone, \"itemC\", \"<no C submenu>\")\
        if theZone.menuGroup or theZone.menuTypes then \
            theZone.menuC = {}\
            for idx, grp in  pairs(gID) do \
                theZone.menuC[grp] = missionCommands.addCommandForGroup(grp, menuC, theZone.rootMenu[grp], radioMenu.redirectMenuX, {theZone, \"C\", grp}) \
            end\
        elseif theZone.coalition == 0 then \
            theZone.menuC = missionCommands.addCommand(menuC, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, \"C\"})\
        else \
            theZone.menuC = missionCommands.addCommandForCoalition(theZone.coalition, menuC, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, \"C\"})\
        end\
    end\
    \
    if cfxZones.hasProperty(theZone, \"itemD\") then \
        local menuD = cfxZones.getStringFromZoneProperty(theZone, \"itemD\", \"<no D submenu>\")\
        if theZone.menuGroup or theZone.menuTypes then \
            theZone.menuD = {}\
            for idx, grp in  pairs(gID) do \
                theZone.menuD[grp] = missionCommands.addCommandForGroup(grp, menuD, theZone.rootMenu[grp], radioMenu.redirectMenuX, {theZone, \"D\", grp}) \
            end\
        elseif theZone.coalition == 0 then \
            theZone.menuD = missionCommands.addCommand(menuD, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, \"D\"})\
        else \
            theZone.menuD = missionCommands.addCommandForCoalition(theZone.coalition, menuD, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, \"D\"})\
        end\
    end\
end\
\
function radioMenu.createRadioMenuWithZone(theZone)\
    theZone.rootName = cfxZones.getStringFromZoneProperty(theZone, \"radioMenu\", \"<No Name>\")\
    \
    theZone.coalition = cfxZones.getCoalitionFromZoneProperty(theZone, \"coalition\", 0)\
    -- groups / types \
    if cfxZones.hasProperty(theZone, \"group\") then \
        theZone.menuGroup = cfxZones.getStringFromZoneProperty(theZone, \"group\", \"<none>\")\
        theZone.menuGroup = dcsCommon.trim(theZone.menuGroup)\
    elseif cfxZones.hasProperty(theZone, \"groups\") then \
        theZone.menuGroup = cfxZones.getStringFromZoneProperty(theZone, \"groups\", \"<none>\")\
        theZone.menuGroup = dcsCommon.trim(theZone.menuGroup)\
    elseif cfxZones.hasProperty(theZone, \"type\") then \
        theZone.menuTypes = cfxZones.getStringFromZoneProperty(theZone, \"type\", \"none\")\
    elseif cfxZones.hasProperty(theZone, \"types\") then\
        theZone.menuTypes = cfxZones.getStringFromZoneProperty(theZone, \"types\", \"none\")\
    end    \
    \
    theZone.menuVisible = cfxZones.getBoolFromZoneProperty(theZone, \"menuVisible\", true)\
    \
    -- install menu if not hidden\
    if theZone.menuVisible then \
        radioMenu.installMenu(theZone)\
    end\
\
    -- get the triggers & methods here \
    theZone.radioMethod = cfxZones.getStringFromZoneProperty(theZone, \"method\", \"inc\")\
    if cfxZones.hasProperty(theZone, \"radioMethod\") then \
        theZone.radioMethod = cfxZones.getStringFromZoneProperty(theZone, \"radioMethod\", \"inc\")\
    end\
    \
    theZone.radioTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, \"radioTriggerMethod\", \"change\")\
    \
    theZone.itemAChosen = cfxZones.getStringFromZoneProperty(theZone, \"A!\", \"*<none>\")\
    theZone.cooldownA = cfxZones.getNumberFromZoneProperty(theZone, \"cooldownA\", 0)\
    --theZone.mcdA = 0\
    theZone.busyA = cfxZones.getStringFromZoneProperty(theZone, \"busyA\", \"Please stand by (<s> seconds)\")\
    \
    theZone.itemBChosen = cfxZones.getStringFromZoneProperty(theZone, \"B!\", \"*<none>\")\
    theZone.cooldownB = cfxZones.getNumberFromZoneProperty(theZone, \"cooldownB\", 0)\
    --theZone.mcdB = 0\
    theZone.busyB = cfxZones.getStringFromZoneProperty(theZone, \"busyB\", \"Please stand by (<s> seconds)\")\
    \
    theZone.itemCChosen = cfxZones.getStringFromZoneProperty(theZone, \"C!\", \"*<none>\")\
    theZone.cooldownC = cfxZones.getNumberFromZoneProperty(theZone, \"cooldownC\", 0)\
    --theZone.mcdC = 0\
    theZone.busyC = cfxZones.getStringFromZoneProperty(theZone, \"busyC\", \"Please stand by (<s> seconds)\")\
\
    theZone.itemDChosen = cfxZones.getStringFromZoneProperty(theZone, \"D!\", \"*<none>\")\
    theZone.cooldownD = cfxZones.getNumberFromZoneProperty(theZone, \"cooldownD\", 0)\
    --theZone.mcdD = 0\
    theZone.busyD = cfxZones.getStringFromZoneProperty(theZone, \"busyD\", \"Please stand by (<s> seconds)\")\
    \
    if cfxZones.hasProperty(theZone, \"removeMenu?\") then \
        theZone.removeMenu = cfxZones.getStringFromZoneProperty(theZone, \"removeMenu?\", \"*<none>\")\
        theZone.lastRemoveMenu = cfxZones.getFlagValue(theZone.removeMenu, theZone)\
    end\
    \
    if cfxZones.hasProperty(theZone, \"addMenu?\") then \
        theZone.addMenu = cfxZones.getStringFromZoneProperty(theZone, \"addMenu?\", \"*<none>\")\
        theZone.lastAddMenu = cfxZones.getFlagValue(theZone.addMenu, theZone)\
    end\
    \
    if radioMenu.verbose or theZone.verbose then \
        trigger.action.outText(\"+++radioMenu: new radioMenu zone <\".. theZone.name ..\">\", 30)\
    end\
    \
end\
\
--\
-- Output processing \
--\
function radioMenu.radioOutMessage(theMessage, theZone)\
    if not theZone then return end \
    c = theZone.coalition\
    if c > 0 then \
        trigger.action.outTextForCoalition(c, theMessage, 30)\
    else\
        trigger.action.outText(theMessage, 30)\
    end\
end\
\
function radioMenu.processHMS(msg, delta)\
    -- moved to dcsCommon \
    return dcsCommon.processHMS(msg, delta)\
end\
\
\
--\
-- Menu Branching\
--\
function radioMenu.redirectMenuX(args)\
    -- we use indirection to be able to debug code better\
    timer.scheduleFunction(radioMenu.doMenuX, args, timer.getTime() + 0.1)\
end\
\
function radioMenu.cdByGID(cd, theZone, gID)\
    if not gID then gID = 0 end \
    --if not gID then return cd[0] end \
    return cd[gID]\
end\
\
function radioMenu.setCDByGID(cd, theZone, gID, newVal)\
    if not gID then gID = 0 end\
        --theZone[cd] = newVal \
        -- \
    --end\
    local allCD = theZone[cd]\
    allCD[gID] = newVal\
    theZone[cd] = allCD\
end\
\
function radioMenu.doMenuX(args)\
    theZone = args[1]\
    theItemIndex = args[2] -- A, B , C .. ?\
    theGroup = args[3] -- can be nil or groupID \
    if not theGroup then theGroup = 0 end \
    \
    local cd = radioMenu.cdByGID(theZone.mcdA, theZone, theGroup) --theZone.mcdA\
    local busy = theZone.busyA \
    local theFlag = theZone.itemAChosen\
    \
    -- decode A..X\
    if theItemIndex == \"B\"then \
        cd = radioMenu.cdByGID(theZone.mcdB, theZone, theGroup) -- theZone.mcdB\
        busy = theZone.busyB \
        theFlag = theZone.itemBChosen\
    elseif theItemIndex == \"C\" then \
        cd = radioMenu.cdByGID(theZone.mcdC, theZone, theGroup) -- theZone.mcdC\
        busy = theZone.busyC \
        theFlag = theZone.itemCChosen\
    elseif theItemIndex == \"D\" then \
        cd = radioMenu.cdByGID(theZone.mcdD, theZone, theGroup) -- theZone.mcdD\
        busy = theZone.busyD \
        theFlag = theZone.itemDChosen\
    end\
    \
    -- see if we are on cooldown \
    local now = timer.getTime()\
    if now < cd then \
        -- we are on cooldown.\
        local msg = radioMenu.processHMS(busy, cd - now)\
        radioMenu.radioOutMessage(msg, theZone)\
        return \
    end\
    \
    -- set new cooldown -- needs own decoder A..X\
    if theItemIndex == \"A\" then\
        radioMenu.setCDByGID(\"mcdA\", theZone, theGroup, now + theZone.cooldownA)\
    elseif theItemIndex == \"B\" then\
        radioMenu.setCDByGID(\"mcdB\", theZone, theGroup, now + theZone.cooldownB)\
    elseif theItemIndex == \"C\" then \
        radioMenu.setCDByGID(\"mcdC\", theZone, theGroup, now + theZone.cooldownC)\
    else \
        radioMenu.setCDByGID(\"mcdC\", theZone, theGroup, now + theZone.cooldownC)\
    end\
    \
    cfxZones.pollFlag(theFlag, theZone.radioMethod, theZone)\
    if theZone.verbose or radioMenu.verbose then \
        trigger.action.outText(\"+++menu: banging with <\" .. theZone.radioMethod .. \"> on <\" .. theFlag .. \"> for \" .. theZone.name, 30)\
    end\
\
end\
\
--\
-- Update -- required when we can enable/disable a zone's menu\
--\
function radioMenu.update()\
    -- call me in a second to poll triggers\
    timer.scheduleFunction(radioMenu.update, {}, timer.getTime() + 1/radioMenu.ups)\
    \
    -- iterate all menus\
    for idx, theZone in pairs(radioMenu.menus) do \
        if theZone.removeMenu \
        and cfxZones.testZoneFlag(theZone, theZone.removeMenu, theZone.radioTriggerMethod, \"lastRemoveMenu\") \
        and theZone.menuVisible\
        then             \
            if theZone.menuGroup or theZone.menuTypes then \
                for gID, aRoot in pairs(theZone.rootMenu) do \
                    missionCommands.removeItemForGroup(gID, aRoot) \
                end\
            elseif theZone.coalition == 0 then \
                missionCommands.removeItem(theZone.rootMenu[0]) \
            else \
                missionCommands.removeItemForCoalition(theZone.coalition, theZone.rootMenu[0]) \
            end\
            \
            theZone.menuVisible = false \
        end\
        \
        if theZone.addMenu \
        and cfxZones.testZoneFlag(theZone, theZone.addMenu, theZone.radioTriggerMethod, \"lastAddMenu\") \
        and (not theZone.menuVisible)\
        then \
            if theZone.verbose or radioMenu.verbose then \
                trigger.action.outText(\"+++menu: adding menu from <\" .. theZone.name .. \">\", 30)\
            end \
            \
            radioMenu.installMenu(theZone) -- auto-handles coalition\
            theZone.menuVisible = true \
        end\
    end\
end\
\
\
--\
-- Config & Start\
--\
function radioMenu.readConfigZone()\
    local theZone = cfxZones.getZoneByName(\"radioMenuConfig\") \
    if not theZone then \
        if radioMenu.verbose then \
            trigger.action.outText(\"+++radioMenu: NO config zone!\", 30)\
        end \
        return \
    end \
    \
    radioMenu.verbose = cfxZones.getBoolFromZoneProperty(theZone, \"verbose\", false)\
    \
    if radioMenu.verbose then \
        trigger.action.outText(\"+++radioMenu: read config\", 30)\
    end \
end\
\
function radioMenu.start()\
    -- lib check\
    if not dcsCommon.libCheck then \
        trigger.action.outText(\"cfx radioMenu requires dcsCommon\", 30)\
        return false \
    end \
    if not dcsCommon.libCheck(\"cfx radioMenu\", radioMenu.requiredLibs) then\
        return false \
    end\
    \
    -- read config \
    radioMenu.readConfigZone()\
    \
    -- process radioMenu Zones \
    -- old style\
    local attrZones = cfxZones.getZonesWithAttributeNamed(\"radioMenu\")\
    for k, aZone in pairs(attrZones) do \
        radioMenu.createRadioMenuWithZone(aZone) -- process attributes\
        radioMenu.addRadioMenu(aZone) -- add to list\
    end\
    \
    -- start update \
    radioMenu.update()\
    \
    trigger.action.outText(\"cfx radioMenu v\" .. radioMenu.version .. \" started.\", 30)\
    return true \
end\
\
-- let's go!\
if not radioMenu.start() then \
    trigger.action.outText(\"cfx radioMenu aborted: missing libraries\", 30)\
    radioMenu = nil \
end\
\
--[[--\
    callbacks for the menus  \
    check CD/standby code for multiple groups \
--]]--",
                    ["predicate"] = "a_do_script",
                }, -- end of [5]
                [6] = 
                {
                    ["text"] = "cfxPlayerScoreUI = {}\
cfxPlayerScoreUI.version = \"2.1.0\"\
cfxPlayerScoreUI.verbose = false \
\
--[[-- VERSION HISTORY\
 - 1.0.2 - initial version \
 - 1.0.3 - module check\
 - 2.0.0 - removed cfxPlayer dependency, handles own commands\
 - 2.0.1 - late start capability \
 - 2.1.0 - soundfile cleanup \
         - score summary for side \
         - allowAll\
         \
--]]--\
cfxPlayerScoreUI.requiredLibs = {\
    \"dcsCommon\", -- this is doing score keeping\
    \"cfxZones\", -- zones for config \
    \"cfxPlayerScore\",\
}\
cfxPlayerScoreUI.soundFile = \"Quest Snare 3.wav\"\
cfxPlayerScoreUI.rootCommands = {} -- by unit's GROUP name, for player aircraft\
cfxPlayerScoreUI.allowAll = true \
cfxPlayerScoreUI.ranked = true \
\
-- redirect: avoid the debug environ of missionCommands\
function cfxPlayerScoreUI.redirectCommandX(args)\
    timer.scheduleFunction(cfxPlayerScoreUI.doCommandX, args, timer.getTime() + 0.1)\
end\
\
function cfxPlayerScoreUI.doCommandX(args)\
    local groupName = args[1] \
    local playerName = args[2]\
    local what = args[3] -- \"score\" or other commands\
    local theGroup = Group.getByName(groupName)\
    local gid = theGroup:getID()\
    local coa = theGroup:getCoalition()\
    \
    if not cfxPlayerScore.scoreTextForPlayerNamed then \
        trigger.action.outText(\"***pSGUI: CANNOT FIND PlayerScore MODULE\", 30)\
        return \
    end\
    local desc = \"\"\
    if what == \"score\" then \
        desc = cfxPlayerScore.scoreTextForPlayerNamed(playerName)\
    elseif what == \"allMySide\" then \
        desc = cfxPlayerScore.scoreSummaryForPlayersOfCoalition(coa)\
    elseif what == \"all\" then \
        desc = \"Score Table For All Players:\\n\" .. cfxPlayerScore.scoreTextForAllPlayers(cfxPlayerScoreUI.ranked) \
    else \
        desc = \"PlayerScore UI: unknown command <\" .. what .. \">\"\
    end \
    trigger.action.outTextForGroup(gid, desc, 30)\
    trigger.action.outSoundForGroup(gid, cfxPlayerScoreUI.soundFile)\
end\
\
--\
-- event handling: we are only interested in birth events\
-- for player aircraft \
--\
function cfxPlayerScore.processPlayerUnit(theUnit)\
    if not theUnit.getPlayerName then return end -- no player name, bye!\
    local playerName = theUnit:getPlayerName()\
    if not playerName then return end \
    \
    -- so now we know it's a player plane. get group name \
    local theGroup = theUnit:getGroup()\
    local groupName = theGroup:getName() \
    local gid = theGroup:getID()\
    \
    -- see if this group already has a score command \
    if cfxPlayerScoreUI.rootCommands[groupName] then \
        -- need re-init to store new pilot name \
        if cfxPlayerScoreUI.verbose then \
            trigger.action.outText(\"++pSGui: group <\" .. groupName .. \"> already has score menu, removing.\", 30)\
        end\
        missionCommands.removeItemForGroup(gid, cfxPlayerScoreUI.rootCommands[groupName]) \
        cfxPlayerScoreUI.rootCommands[groupName] = nil \
    end\
    \
    -- we need to install a group menu item for scores. \
    -- will persist through death\
    local commandTxt = \"Show Score / Kills\"\
    local theMenu = missionCommands.addSubMenuForGroup(gid, \"Show Score\", nil)\
    local theCommand =  missionCommands.addCommandForGroup(gid, commandTxt, theMenu, cfxPlayerScoreUI.redirectCommandX,    {groupName, playerName, \"score\"})\
    \
    commandTxt = \"Show my Side Score / Kills\"\
    theCommand =  missionCommands.addCommandForGroup(gid, commandTxt, theMenu, cfxPlayerScoreUI.redirectCommandX, {groupName, playerName, \"allMySide\"})\
\
    if cfxPlayerScoreUI.allowAll then \
        commandTxt = \"Show All Player Scores\"\
        theCommand =  missionCommands.addCommandForGroup(gid, commandTxt, theMenu, cfxPlayerScoreUI.redirectCommandX, {groupName, playerName, \"all\"})\
    end\
\
    cfxPlayerScoreUI.rootCommands[groupName] = theMenu \
    \
    if cfxPlayerScoreUI.verbose then \
        trigger.action.outText(\"++pSGui: installed player score menu for group <\" .. groupName .. \">\", 30)\
    end\
end\
\
function cfxPlayerScoreUI:onEvent(event)\
    if event.id ~= 15 then return end -- only birth \
    if not event.initiator then return end -- no initiator, no joy \
    local theUnit = event.initiator \
    cfxPlayerScore.processPlayerUnit(theUnit)\
end\
\
--\
-- Start \
--\
function cfxPlayerScoreUI.start()    \
    if not dcsCommon.libCheck(\"cfx Player Score UI\", \
                              cfxPlayerScoreUI.requiredLibs) \
    then return false end\
    -- install the event handler for new player planes\
    world.addEventHandler(cfxPlayerScoreUI)\
    -- process all existing players (late start)\
    dcsCommon.iteratePlayers(cfxPlayerScore.processPlayerUnit)\
    trigger.action.outText(\"cf/x cfxPlayerScoreUI v\" .. cfxPlayerScoreUI.version .. \" started\", 30)\
    return true \
end\
\
--\
-- GO GO GO \
--\
if not cfxPlayerScoreUI.start() then \
    cfxPlayerScoreUI = nil\
    trigger.action.outText(\"cf/x PlayerScore UI aborted: missing libraries\", 30)\
end\
",
                    ["predicate"] = "a_do_script",
                }, -- end of [6]
            }, -- end of ["actions"]
            ["comment"] = "Load DML",
        }, -- end of [1]
    }, -- end of ["trigrules"]
    ["currentKey"] = 11392,
    ["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"]
        ["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"]
        ["oil_press_drop"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "oil_press_drop",
            ["mm"] = 0,
        }, -- end of ["oil_press_drop"]
        ["right_wing_leaks"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "right_wing_leaks",
            ["mm"] = 0,
        }, -- end of ["right_wing_leaks"]
        ["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"]
        ["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"]
        ["yaw_damper_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "yaw_damper_fail",
            ["mm"] = 0,
        }, -- end of ["yaw_damper_fail"]
        ["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"]
        ["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"]
        ["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"]
        ["ENG0_TURBINE_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_TURBINE_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ENG0_TURBINE_FAILURE"]
        ["altitude_chain_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "altitude_chain_fail",
            ["mm"] = 0,
        }, -- end of ["altitude_chain_fail"]
        ["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"]
        ["SUCTION_PUMP_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SUCTION_PUMP_FAILURE",
            ["mm"] = 0,
        }, -- end of ["SUCTION_PUMP_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_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"]
        ["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"]
        ["PITOT_HEAT_ELEMENT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PITOT_HEAT_ELEMENT",
            ["mm"] = 0,
        }, -- end of ["PITOT_HEAT_ELEMENT"]
        ["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"]
        ["BATT_FAIL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BATT_FAIL",
            ["mm"] = 0,
        }, -- end of ["BATT_FAIL"]
        ["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"]
        ["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"]
        ["FDU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FDU",
            ["mm"] = 0,
        }, -- end of ["FDU"]
        ["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"]
        ["sas_pitch_left"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "sas_pitch_left",
            ["mm"] = 0,
        }, -- end of ["sas_pitch_left"]
        ["abris_hardware"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "abris_hardware",
            ["mm"] = 0,
        }, -- end of ["abris_hardware"]
        ["hydr2_leaks"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hydr2_leaks",
            ["mm"] = 0,
        }, -- end of ["hydr2_leaks"]
        ["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"]
        ["ap_global_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ap_global_fail",
            ["mm"] = 0,
        }, -- end of ["ap_global_fail"]
        ["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"]
        ["ELEC_MSB_DAMAGED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_MSB_DAMAGED",
            ["mm"] = 0,
        }, -- end of ["ELEC_MSB_DAMAGED"]
        ["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"]
        ["AB_fire"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AB_fire",
            ["mm"] = 0,
        }, -- end of ["AB_fire"]
        ["fuel_gauges_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fuel_gauges_fail",
            ["mm"] = 0,
        }, -- end of ["fuel_gauges_fail"]
        ["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"]
        ["incidometer_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "incidometer_fail",
            ["mm"] = 0,
        }, -- end of ["incidometer_fail"]
        ["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"]
        ["HYD_Flight"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYD_Flight",
            ["mm"] = 0,
        }, -- end of ["HYD_Flight"]
        ["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_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"]
        ["L_ENG_POP_STALL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_ENG_POP_STALL",
            ["mm"] = 0,
        }, -- end of ["L_ENG_POP_STALL"]
        ["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"]
        ["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"]
        ["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"]
        ["gear_lever_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "gear_lever_fail",
            ["mm"] = 0,
        }, -- end of ["gear_lever_fail"]
        ["F2_BOTTOM_CYLINDER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "F2_BOTTOM_CYLINDER",
            ["mm"] = 0,
        }, -- end of ["F2_BOTTOM_CYLINDER"]
        ["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"]
        ["R_ENG_POP_STALL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_ENG_POP_STALL",
            ["mm"] = 0,
        }, -- end of ["R_ENG_POP_STALL"]
        ["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"]
        ["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"]
        ["hs_damage_GainPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hs_damage_GainPump",
            ["mm"] = 0,
        }, -- end of ["hs_damage_GainPump"]
        ["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"]
        ["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"]
        ["electropump_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "electropump_fail",
            ["mm"] = 0,
        }, -- end of ["electropump_fail"]
        ["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"]
        ["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"]
        ["equip_temp_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "equip_temp_fail",
            ["mm"] = 0,
        }, -- end of ["equip_temp_fail"]
        ["alt2_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "alt2_fail",
            ["mm"] = 0,
        }, -- end of ["alt2_fail"]
        ["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"]
        ["IMU_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "IMU_FAILURE",
            ["mm"] = 0,
        }, -- end of ["IMU_FAILURE"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["FUEL_TANK_03_FIRE"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_03_FIRE",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_03_FIRE"]
        ["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"]
        ["L_ENG_SEIZED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_ENG_SEIZED",
            ["mm"] = 0,
        }, -- end of ["L_ENG_SEIZED"]
        ["GSH23_CHARGED_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GSH23_CHARGED_FAILURE",
            ["mm"] = 0,
        }, -- end of ["GSH23_CHARGED_FAILURE"]
        ["R_ENG_SEIZED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_ENG_SEIZED",
            ["mm"] = 0,
        }, -- end of ["R_ENG_SEIZED"]
        ["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"]
        ["LANDINGGEARL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LANDINGGEARL",
            ["mm"] = 0,
        }, -- end of ["LANDINGGEARL"]
        ["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"]
        ["CDU_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CDU_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["CDU_FAILURE_TOTAL"]
        ["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"]
        ["right_airbrake_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "right_airbrake_fail",
            ["mm"] = 0,
        }, -- end of ["right_airbrake_fail"]
        ["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"]
        ["VHF_ANTENNA_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VHF_ANTENNA_FAULT",
            ["mm"] = 0,
        }, -- end of ["VHF_ANTENNA_FAULT"]
        ["es_damage_GeneratorLeft"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_GeneratorLeft",
            ["mm"] = 0,
        }, -- end of ["es_damage_GeneratorLeft"]
        ["antiskid_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "antiskid_fail",
            ["mm"] = 0,
        }, -- end of ["antiskid_fail"]
        ["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"]
        ["anemo_central_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "anemo_central_fail",
            ["mm"] = 0,
        }, -- end of ["anemo_central_fail"]
        ["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,
            ["id"] = "tacan_fail",
            ["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"]
        ["FR22RADIO"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FR22RADIO",
            ["mm"] = 0,
        }, -- end of ["FR22RADIO"]
        ["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"]
        ["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"]
        ["nosecone_stuck_forward"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "nosecone_stuck_forward",
            ["mm"] = 0,
        }, -- end of ["nosecone_stuck_forward"]
        ["trim_yaw_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "trim_yaw_fail",
            ["mm"] = 0,
        }, -- end of ["trim_yaw_fail"]
        ["COOLANT_DEFECTIVE_IND"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COOLANT_DEFECTIVE_IND",
            ["mm"] = 0,
        }, -- end of ["COOLANT_DEFECTIVE_IND"]
        ["eng_computer_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "eng_computer_fail",
            ["mm"] = 0,
        }, -- end of ["eng_computer_fail"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["left_feeder_leaks"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "left_feeder_leaks",
            ["mm"] = 0,
        }, -- end of ["left_feeder_leaks"]
        ["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"]
        ["es_damage_VU1"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "es_damage_VU1",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["es_damage_VU1"]
        ["mlws"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "mlws",
            ["mm"] = 0,
        }, -- end of ["mlws"]
        ["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"]
        ["R_ENG_FIRE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_ENG_FIRE",
            ["mm"] = 0,
        }, -- end of ["R_ENG_FIRE"]
        ["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"]
        ["L_ENG_FIRE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_ENG_FIRE",
            ["mm"] = 0,
        }, -- end of ["L_ENG_FIRE"]
        ["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"]
        ["aoa_limiter"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "aoa_limiter",
            ["mm"] = 0,
        }, -- end of ["aoa_limiter"]
        ["SAR_2_95"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "SAR_2_95",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["SAR_2_95"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["engine_flameout_recoverable"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "engine_flameout_recoverable",
            ["mm"] = 0,
        }, -- end of ["engine_flameout_recoverable"]
        ["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"]
        ["L_ENG_COMPRESSOR_STALL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_ENG_COMPRESSOR_STALL",
            ["mm"] = 0,
        }, -- end of ["L_ENG_COMPRESSOR_STALL"]
        ["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"]
        ["R_ENG_COMPRESSOR_STALL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_ENG_COMPRESSOR_STALL",
            ["mm"] = 0,
        }, -- end of ["R_ENG_COMPRESSOR_STALL"]
        ["partial_comp_stall"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "partial_comp_stall",
            ["mm"] = 0,
        }, -- end of ["partial_comp_stall"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["LeftEngine_ShaveInOil"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LeftEngine_ShaveInOil",
            ["mm"] = 0,
        }, -- end of ["LeftEngine_ShaveInOil"]
        ["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"]
        ["hydro_common"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hydro_common",
            ["mm"] = 0,
        }, -- end of ["hydro_common"]
        ["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"]
        ["CMDISP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CMDISP",
            ["mm"] = 0,
        }, -- end of ["CMDISP"]
        ["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"]
        ["CTRL_LANDING_FLAPS_RH_HOSE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_LANDING_FLAPS_RH_HOSE",
            ["mm"] = 0,
        }, -- end of ["CTRL_LANDING_FLAPS_RH_HOSE"]
        ["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"]
        ["front_central_leaks"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "front_central_leaks",
            ["mm"] = 0,
        }, -- end of ["front_central_leaks"]
        ["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"]
        ["pp_damage_OilSeparator"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pp_damage_OilSeparator",
            ["mm"] = 0,
        }, -- end of ["pp_damage_OilSeparator"]
        ["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"]
        ["FUEL_TANK_03_FIRE_STOPPED"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_03_FIRE_STOPPED",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_03_FIRE_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"]
        ["slat_outer_left_stuck"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "slat_outer_left_stuck",
            ["mm"] = 0,
        }, -- end of ["slat_outer_left_stuck"]
        ["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"]
        ["right_rear_transfer_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "right_rear_transfer_fail",
            ["mm"] = 0,
        }, -- end of ["right_rear_transfer_fail"]
        ["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"]
        ["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"]
        ["ACCSENSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ACCSENSOR",
            ["mm"] = 0,
        }, -- end of ["ACCSENSOR"]
        ["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"]
        ["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"]
        ["es_damage_SpareInverter"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_SpareInverter",
            ["mm"] = 0,
        }, -- end of ["es_damage_SpareInverter"]
        ["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"]
        ["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"]
        ["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"]
        ["FUEL_TANK_03_EXPLODED"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_03_EXPLODED",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_03_EXPLODED"]
        ["hydr1_pump_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hydr1_pump_fail",
            ["mm"] = 0,
        }, -- end of ["hydr1_pump_fail"]
        ["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"]
        ["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"]
        ["as_damage_Depressurization"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "as_damage_Depressurization",
            ["mm"] = 0,
        }, -- end of ["as_damage_Depressurization"]
        ["inverter1_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "inverter1_fail",
            ["mm"] = 0,
        }, -- end of ["inverter1_fail"]
        ["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"]
        ["R_ENG_OIL_LEAK_MODERATE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_ENG_OIL_LEAK_MODERATE",
            ["mm"] = 0,
        }, -- end of ["R_ENG_OIL_LEAK_MODERATE"]
        ["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"]
        ["airbrake_cutout_microsw_malf"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "airbrake_cutout_microsw_malf",
            ["mm"] = 0,
        }, -- end of ["airbrake_cutout_microsw_malf"]
        ["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"]
        ["FUEL_TANK_03_MEDIUM_LEAK"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_03_MEDIUM_LEAK",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_03_MEDIUM_LEAK"]
        ["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"]
        ["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"]
        ["ENG0_WATERRADIATOR1_PIERCED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_WATERRADIATOR1_PIERCED",
            ["mm"] = 0,
        }, -- end of ["ENG0_WATERRADIATOR1_PIERCED"]
        ["chute_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "chute_fail",
            ["mm"] = 0,
        }, -- end of ["chute_fail"]
        ["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"]
        ["fuel_accu_leaks"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fuel_accu_leaks",
            ["mm"] = 0,
        }, -- end of ["fuel_accu_leaks"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["ELEC_ROCKETS_LH_LOOM_SEVERED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_ROCKETS_LH_LOOM_SEVERED",
            ["mm"] = 0,
        }, -- end of ["ELEC_ROCKETS_LH_LOOM_SEVERED"]
        ["sensf_CADC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "sensf_CADC",
            ["mm"] = 0,
        }, -- end of ["sensf_CADC"]
        ["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"]
        ["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"]
        ["slats_stuck"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "slats_stuck",
            ["mm"] = 0,
        }, -- end of ["slats_stuck"]
        ["alt1_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "alt1_fail",
            ["mm"] = 0,
        }, -- end of ["alt1_fail"]
        ["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"]
        ["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"]
        ["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"]
        ["hydr1_leaks"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hydr1_leaks",
            ["mm"] = 0,
        }, -- end of ["hydr1_leaks"]
        ["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"]
        ["R_ENG_AICS_RAMP_FAIL_OPEN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_ENG_AICS_RAMP_FAIL_OPEN",
            ["mm"] = 0,
        }, -- end of ["R_ENG_AICS_RAMP_FAIL_OPEN"]
        ["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"]
        ["TEMPSENSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TEMPSENSOR",
            ["mm"] = 0,
        }, -- end of ["TEMPSENSOR"]
        ["flaps_fault"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "flaps_fault",
            ["mm"] = 0,
        }, -- end of ["flaps_fault"]
        ["L_ENG_AICS_RAMP_FAIL_OPEN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_ENG_AICS_RAMP_FAIL_OPEN",
            ["mm"] = 0,
        }, -- end of ["L_ENG_AICS_RAMP_FAIL_OPEN"]
        ["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"]
        ["hydr2_reserv_leaks"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hydr2_reserv_leaks",
            ["mm"] = 0,
        }, -- end of ["hydr2_reserv_leaks"]
        ["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"]
        ["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"]
        ["BCKPITOT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BCKPITOT",
            ["mm"] = 0,
        }, -- end of ["BCKPITOT"]
        ["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"]
        ["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_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"]
        ["gyros_emergency_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "gyros_emergency_fail",
            ["mm"] = 0,
        }, -- end of ["gyros_emergency_fail"]
        ["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"]
        ["ENG0_TURBINE_LUBRICATION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_TURBINE_LUBRICATION",
            ["mm"] = 0,
        }, -- end of ["ENG0_TURBINE_LUBRICATION"]
        ["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"]
        ["flaps_stuck"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "flaps_stuck",
            ["mm"] = 0,
        }, -- end of ["flaps_stuck"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["ENG0_TURBINE_MALFUNCTION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_TURBINE_MALFUNCTION",
            ["mm"] = 0,
        }, -- end of ["ENG0_TURBINE_MALFUNCTION"]
        ["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"]
        ["SAR_fast"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "SAR_fast",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["SAR_fast"]
        ["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"]
        ["ELEC_BOMBABWGERAT_CHARGING_MALFUNCTION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_BOMBABWGERAT_CHARGING_MALFUNCTION",
            ["mm"] = 0,
        }, -- end of ["ELEC_BOMBABWGERAT_CHARGING_MALFUNCTION"]
        ["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"]
        ["VHF_TOTAL_DAMAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VHF_TOTAL_DAMAGE",
            ["mm"] = 0,
        }, -- end of ["VHF_TOTAL_DAMAGE"]
        ["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"]
        ["A11_CLOCK_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "A11_CLOCK_FAILURE",
            ["mm"] = 0,
        }, -- end of ["A11_CLOCK_FAILURE"]
        ["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"]
        ["SOPLO_FAILURE_PARTIAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SOPLO_FAILURE_PARTIAL",
            ["mm"] = 0,
        }, -- end of ["SOPLO_FAILURE_PARTIAL"]
        ["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"]
        ["mach_chain_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "mach_chain_fail",
            ["mm"] = 0,
        }, -- end of ["mach_chain_fail"]
        ["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"]
        ["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_Gear_NWS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Gear_NWS",
            ["mm"] = 0,
        }, -- end of ["Failure_Gear_NWS"]
        ["gear_left_stuck"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "gear_left_stuck",
            ["mm"] = 0,
        }, -- end of ["gear_left_stuck"]
        ["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"]
        ["SWMMC_FAILURE_IOC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_IOC",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_IOC"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["INST_HUD_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_HUD_FAILURE",
            ["mm"] = 0,
        }, -- end of ["INST_HUD_FAILURE"]
        ["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"]
        ["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"]
        ["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"]
        ["LGear_ret_fault"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LGear_ret_fault",
            ["mm"] = 0,
        }, -- end of ["LGear_ret_fault"]
        ["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"]
        ["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"]
        ["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"]
        ["hydro_main"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hydro_main",
            ["mm"] = 0,
        }, -- end of ["hydro_main"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["hsf_UtilityHydraulic"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hsf_UtilityHydraulic",
            ["mm"] = 0,
        }, -- end of ["hsf_UtilityHydraulic"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["slat_inner_left_stuck"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "slat_inner_left_stuck",
            ["mm"] = 0,
        }, -- end of ["slat_inner_left_stuck"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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_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"]
        ["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"]
        ["FUEL_NITRO_TANK_00_LEAK_STOPPED"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_NITRO_TANK_00_LEAK_STOPPED",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_NITRO_TANK_00_LEAK_STOPPED"]
        ["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"]
        ["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"]
        ["incidometer_blockage_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "incidometer_blockage_fail",
            ["mm"] = 0,
        }, -- end of ["incidometer_blockage_fail"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["right_wing_transfer_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "right_wing_transfer_fail",
            ["mm"] = 0,
        }, -- end of ["right_wing_transfer_fail"]
        ["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"]
        ["right_front_transfer_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "right_front_transfer_fail",
            ["mm"] = 0,
        }, -- end of ["right_front_transfer_fail"]
        ["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"]
        ["oxygen_regulator_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "oxygen_regulator_fail",
            ["mm"] = 0,
        }, -- end of ["oxygen_regulator_fail"]
        ["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"]
        ["UNCR_RH_STRUT_HOSE_PIERCED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UNCR_RH_STRUT_HOSE_PIERCED",
            ["mm"] = 0,
        }, -- end of ["UNCR_RH_STRUT_HOSE_PIERCED"]
        ["es_damage_DMR"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "es_damage_DMR",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["es_damage_DMR"]
        ["trim_elect_supply"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "trim_elect_supply",
            ["mm"] = 0,
        }, -- end of ["trim_elect_supply"]
        ["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"]
        ["detotalizer_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "detotalizer_fail",
            ["mm"] = 0,
        }, -- end of ["detotalizer_fail"]
        ["flap_left_stuck"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "flap_left_stuck",
            ["mm"] = 0,
        }, -- end of ["flap_left_stuck"]
        ["engfail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "engfail",
            ["mm"] = 0,
        }, -- end of ["engfail"]
        ["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"]
        ["FUEL_NITRO_TANK_00_MAJOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_NITRO_TANK_00_MAJOR_LEAK",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_NITRO_TANK_00_MAJOR_LEAK"]
        ["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"]
        ["EMMC_FAILURE_BAU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_BAU",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_BAU"]
        ["ENG0_NITROS_PUMP_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_NITROS_PUMP_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ENG0_NITROS_PUMP_FAILURE"]
        ["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"]
        ["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"]
        ["ef_shutdown"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ef_shutdown",
            ["mm"] = 0,
        }, -- end of ["ef_shutdown"]
        ["EGTSENSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EGTSENSOR",
            ["mm"] = 0,
        }, -- end of ["EGTSENSOR"]
        ["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"]
        ["gear_right_stuck"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "gear_right_stuck",
            ["mm"] = 0,
        }, -- end of ["gear_right_stuck"]
        ["right_fuel_pump_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "right_fuel_pump_fail",
            ["mm"] = 0,
        }, -- end of ["right_fuel_pump_fail"]
        ["tr2_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "tr2_fail",
            ["mm"] = 0,
        }, -- end of ["tr2_fail"]
        ["pilot_aids_2_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pilot_aids_2_fail",
            ["mm"] = 0,
        }, -- end of ["pilot_aids_2_fail"]
        ["gear_down_lock_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "gear_down_lock_fail",
            ["mm"] = 0,
        }, -- end of ["gear_down_lock_fail"]
        ["STATION_6_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STATION_6_FAILURE",
            ["mm"] = 0,
        }, -- end of ["STATION_6_FAILURE"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["ppf_FireRight"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ppf_FireRight",
            ["mm"] = 0,
        }, -- end of ["ppf_FireRight"]
        ["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"]
        ["SWMMC_FAILURE_CTVS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_CTVS",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_CTVS"]
        ["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"]
        ["ELEVONOUTERRIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEVONOUTERRIGHT",
            ["mm"] = 0,
        }, -- end of ["ELEVONOUTERRIGHT"]
        ["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"]
        ["MWMMC_FAILURE_PS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_PS",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_PS"]
        ["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"]
        ["fsf_CrossfeedValve"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fsf_CrossfeedValve",
            ["mm"] = 0,
        }, -- end of ["fsf_CrossfeedValve"]
        ["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"]
        ["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"]
        ["SUPERCHARGER_LIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SUPERCHARGER_LIGHT",
            ["mm"] = 0,
        }, -- end of ["SUPERCHARGER_LIGHT"]
        ["ROCKETS_DEFECTIVE_WIRING"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ROCKETS_DEFECTIVE_WIRING",
            ["mm"] = 0,
        }, -- end of ["ROCKETS_DEFECTIVE_WIRING"]
        ["ELEVONINNERLEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEVONINNERLEFT",
            ["mm"] = 0,
        }, -- end of ["ELEVONINNERLEFT"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["FUELTANK2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUELTANK2",
            ["mm"] = 0,
        }, -- end of ["FUELTANK2"]
        ["SHARS_FAILURE_SENSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SHARS_FAILURE_SENSOR",
            ["mm"] = 0,
        }, -- end of ["SHARS_FAILURE_SENSOR"]
        ["INS_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["INS_FAILURE_TOTAL"]
        ["Failure_Ctrl_Aileron"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Ctrl_Aileron",
            ["mm"] = 0,
        }, -- end of ["Failure_Ctrl_Aileron"]
        ["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"]
        ["RWRANTREAR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWRANTREAR",
            ["mm"] = 0,
        }, -- end of ["RWRANTREAR"]
        ["FAILURE_HYDRAULICS_EMERGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_HYDRAULICS_EMERGE",
            ["mm"] = 0,
        }, -- end of ["FAILURE_HYDRAULICS_EMERGE"]
        ["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"]
        ["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"]
        ["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"]
        ["HUD_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HUD_FAILURE",
            ["mm"] = 0,
        }, -- end of ["HUD_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"]
        ["compressor_damage"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "compressor_damage",
            ["mm"] = 0,
        }, -- end of ["compressor_damage"]
        ["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"]
        ["fuel_leak"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fuel_leak",
            ["mm"] = 0,
        }, -- end of ["fuel_leak"]
        ["EMMC_FAILURE_EMMC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_EMMC",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_EMMC"]
        ["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"]
        ["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"]
        ["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"]
        ["INST_CLOCK_MALFUNCTION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_CLOCK_MALFUNCTION",
            ["mm"] = 0,
        }, -- end of ["INST_CLOCK_MALFUNCTION"]
        ["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"]
        ["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"]
        ["CADC_CSDC_CONNECTION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_CSDC_CONNECTION",
            ["mm"] = 0,
        }, -- end of ["CADC_CSDC_CONNECTION"]
        ["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"]
        ["ILS_FAILURE_ANTENNA"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ILS_FAILURE_ANTENNA",
            ["mm"] = 0,
        }, -- end of ["ILS_FAILURE_ANTENNA"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["nosecone_stuck_backward"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "nosecone_stuck_backward",
            ["mm"] = 0,
        }, -- end of ["nosecone_stuck_backward"]
        ["ppf_RightOil"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ppf_RightOil",
            ["mm"] = 0,
        }, -- end of ["ppf_RightOil"]
        ["FUEL_GAUGE_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_GAUGE_FAULT",
            ["mm"] = 0,
        }, -- end of ["FUEL_GAUGE_FAULT"]
        ["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"]
        ["engine_antiice_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "engine_antiice_fail",
            ["mm"] = 0,
        }, -- end of ["engine_antiice_fail"]
        ["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"]
        ["ENG0_TURBINE_IMPELLER_DAMAGED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_TURBINE_IMPELLER_DAMAGED",
            ["mm"] = 0,
        }, -- end of ["ENG0_TURBINE_IMPELLER_DAMAGED"]
        ["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"]
        ["TGP_FAILURE_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TGP_FAILURE_LEFT",
            ["mm"] = 0,
        }, -- end of ["TGP_FAILURE_LEFT"]
        ["Failure_Comp_MC2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Comp_MC2",
            ["mm"] = 0,
        }, -- end of ["Failure_Comp_MC2"]
        ["loc_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "loc_fail",
            ["mm"] = 0,
        }, -- end of ["loc_fail"]
        ["RDR_FAILURE_TRANSMITTER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RDR_FAILURE_TRANSMITTER",
            ["mm"] = 0,
        }, -- end of ["RDR_FAILURE_TRANSMITTER"]
        ["SWMMC_FAILURE_DMP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_DMP",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_DMP"]
        ["brakes_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "brakes_fail",
            ["mm"] = 0,
        }, -- end of ["brakes_fail"]
        ["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"]
        ["pilot_aids_1_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pilot_aids_1_fail",
            ["mm"] = 0,
        }, -- end of ["pilot_aids_1_fail"]
        ["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"]
        ["RWR_FAILURE_QUAD315"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_QUAD315",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_QUAD315"]
        ["acs"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["mm"] = 0,
        }, -- end of ["acs"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["D2_RIGHT_CYLINDER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "D2_RIGHT_CYLINDER",
            ["mm"] = 0,
        }, -- end of ["D2_RIGHT_CYLINDER"]
        ["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"]
        ["ols_damage_OilPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ols_damage_OilPump",
            ["mm"] = 0,
        }, -- end of ["ols_damage_OilPump"]
        ["pp_damage_MainMaxTempr"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pp_damage_MainMaxTempr",
            ["mm"] = 0,
        }, -- end of ["pp_damage_MainMaxTempr"]
        ["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"]
        ["HYDR1ACC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYDR1ACC",
            ["mm"] = 0,
        }, -- end of ["HYDR1ACC"]
        ["W_S_R"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "W_S_R",
            ["mm"] = 0,
        }, -- end of ["W_S_R"]
        ["STRAKE_RIGHT_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STRAKE_RIGHT_FAILURE",
            ["mm"] = 0,
        }, -- end of ["STRAKE_RIGHT_FAILURE"]
        ["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"]
        ["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"]
        ["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"]
        ["ENG0_JAMMED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_JAMMED",
            ["mm"] = 0,
        }, -- end of ["ENG0_JAMMED"]
        ["ENG0_GOVERNOR_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_GOVERNOR_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ENG0_GOVERNOR_FAILURE"]
        ["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"]
        ["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"]
        ["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"]
        ["AIRBRAKESERVO"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AIRBRAKESERVO",
            ["mm"] = 0,
        }, -- end of ["AIRBRAKESERVO"]
        ["DEFECTIVE_INSTRUMENT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DEFECTIVE_INSTRUMENT",
            ["mm"] = 0,
        }, -- end of ["DEFECTIVE_INSTRUMENT"]
        ["elevator_loss"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "elevator_loss",
            ["mm"] = 0,
        }, -- end of ["elevator_loss"]
        ["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_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"]
        ["ppf_RightGearbox"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ppf_RightGearbox",
            ["mm"] = 0,
        }, -- end of ["ppf_RightGearbox"]
        ["Failure_Fuel_QuantityGaging"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Fuel_QuantityGaging",
            ["mm"] = 0,
        }, -- end of ["Failure_Fuel_QuantityGaging"]
        ["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_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"]
        ["CADC_PRESSURE_SENSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_PRESSURE_SENSOR",
            ["mm"] = 0,
        }, -- end of ["CADC_PRESSURE_SENSOR"]
        ["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"]
        ["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"]
        ["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"]
        ["flap_right_stuck"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "flap_right_stuck",
            ["mm"] = 0,
        }, -- end of ["flap_right_stuck"]
        ["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"]
        ["pp_damage_Ignition"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pp_damage_Ignition",
            ["mm"] = 0,
        }, -- end of ["pp_damage_Ignition"]
        ["CADC_FAILURE_STATIC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_FAILURE_STATIC",
            ["mm"] = 0,
        }, -- end of ["CADC_FAILURE_STATIC"]
        ["Failure_Fuel_Tank4Transfer"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Fuel_Tank4Transfer",
            ["mm"] = 0,
        }, -- end of ["Failure_Fuel_Tank4Transfer"]
        ["trim_roll_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "trim_roll_fail",
            ["mm"] = 0,
        }, -- end of ["trim_roll_fail"]
        ["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"]
        ["STATION_2_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STATION_2_FAILURE",
            ["mm"] = 0,
        }, -- end of ["STATION_2_FAILURE"]
        ["CADC_FAILURE_IAS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_FAILURE_IAS",
            ["mm"] = 0,
        }, -- end of ["CADC_FAILURE_IAS"]
        ["fuel_intercom_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fuel_intercom_fail",
            ["mm"] = 0,
        }, -- end of ["fuel_intercom_fail"]
        ["gs_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "gs_fail",
            ["mm"] = 0,
        }, -- end of ["gs_fail"]
        ["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"]
        ["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"]
        ["asc"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "asc",
            ["mm"] = 0,
        }, -- end of ["asc"]
        ["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"]
        ["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"]
        ["esf_RightRectifier"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "esf_RightRectifier",
            ["mm"] = 0,
        }, -- end of ["esf_RightRectifier"]
        ["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"]
        ["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"]
        ["pp_damage_EmergMaxNormFreq"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pp_damage_EmergMaxNormFreq",
            ["mm"] = 0,
        }, -- end of ["pp_damage_EmergMaxNormFreq"]
        ["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"]
        ["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"]
        ["L_ENG_HPT_OVERSPEED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_ENG_HPT_OVERSPEED",
            ["mm"] = 0,
        }, -- end of ["L_ENG_HPT_OVERSPEED"]
        ["FUELTANK5R"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUELTANK5R",
            ["mm"] = 0,
        }, -- end of ["FUELTANK5R"]
        ["R_ENG_HPT_OVERSPEED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_ENG_HPT_OVERSPEED",
            ["mm"] = 0,
        }, -- end of ["R_ENG_HPT_OVERSPEED"]
        ["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"]
        ["RIGHT_CYLINDER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RIGHT_CYLINDER",
            ["mm"] = 0,
        }, -- end of ["RIGHT_CYLINDER"]
        ["RIGHT_FLAP_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RIGHT_FLAP_FAULT",
            ["mm"] = 0,
        }, -- end of ["RIGHT_FLAP_FAULT"]
        ["engine_chip"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "engine_chip",
            ["mm"] = 0,
        }, -- end of ["engine_chip"]
        ["ppf_LeftOil"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ppf_LeftOil",
            ["mm"] = 0,
        }, -- end of ["ppf_LeftOil"]
        ["engine_flameout_irrecoverable"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "engine_flameout_irrecoverable",
            ["mm"] = 0,
        }, -- end of ["engine_flameout_irrecoverable"]
        ["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_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"]
        ["GTS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GTS",
            ["mm"] = 0,
        }, -- end of ["GTS"]
        ["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"]
        ["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"]
        ["ELEC_BOMBABWGERAT_CHARGING_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_BOMBABWGERAT_CHARGING_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_BOMBABWGERAT_CHARGING_FAILURE"]
        ["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"]
        ["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"]
        ["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"]
        ["HYD_Combined"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYD_Combined",
            ["mm"] = 0,
        }, -- end of ["HYD_Combined"]
        ["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"]
        ["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"]
        ["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_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"]
        ["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"]
        ["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"]
        ["COOLANT_POOR_CONNTECT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COOLANT_POOR_CONNTECT",
            ["mm"] = 0,
        }, -- end of ["COOLANT_POOR_CONNTECT"]
        ["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"]
        ["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"]
        ["INS_PU_REJECTED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_PU_REJECTED",
            ["mm"] = 0,
        }, -- end of ["INS_PU_REJECTED"]
        ["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"]
        ["Failure_PP_LeftPTS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_PP_LeftPTS",
            ["mm"] = 0,
        }, -- end of ["Failure_PP_LeftPTS"]
        ["ppf_RightNozzleControl"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ppf_RightNozzleControl",
            ["mm"] = 0,
        }, -- end of ["ppf_RightNozzleControl"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["dme_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "dme_fail",
            ["mm"] = 0,
        }, -- end of ["dme_fail"]
        ["CANARDSERVORIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CANARDSERVORIGHT",
            ["mm"] = 0,
        }, -- end of ["CANARDSERVORIGHT"]
        ["IMU_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "IMU_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["IMU_FAILURE_TOTAL"]
        ["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_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"]
        ["pitch_trim_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pitch_trim_fail",
            ["mm"] = 0,
        }, -- end of ["pitch_trim_fail"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["main_reductor_chip"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "main_reductor_chip",
            ["mm"] = 0,
        }, -- end of ["main_reductor_chip"]
        ["left_rear_leaks"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "left_rear_leaks",
            ["mm"] = 0,
        }, -- end of ["left_rear_leaks"]
        ["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"]
        ["PITOT_HEAT_WIRING"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PITOT_HEAT_WIRING",
            ["mm"] = 0,
        }, -- end of ["PITOT_HEAT_WIRING"]
        ["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"]
        ["GMC1AE_GYRO_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GMC1AE_GYRO_FAILURE",
            ["mm"] = 0,
        }, -- end of ["GMC1AE_GYRO_FAILURE"]
        ["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"]
        ["cabin_temp_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "cabin_temp_fail",
            ["mm"] = 0,
        }, -- end of ["cabin_temp_fail"]
        ["left_front_transfer_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "left_front_transfer_fail",
            ["mm"] = 0,
        }, -- end of ["left_front_transfer_fail"]
        ["EMMC_FAILURE_LWC"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_LWC",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_LWC"]
        ["fs_damage_TransferPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fs_damage_TransferPump",
            ["mm"] = 0,
        }, -- end of ["fs_damage_TransferPump"]
        ["STARTER_RELAY_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STARTER_RELAY_FAULT",
            ["mm"] = 0,
        }, -- end of ["STARTER_RELAY_FAULT"]
        ["TILS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TILS",
            ["mm"] = 0,
        }, -- end of ["TILS"]
        ["FUEL_BOOSTER_FUEL_PUMP_2_DEGRADED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUEL_BOOSTER_FUEL_PUMP_2_DEGRADED",
            ["mm"] = 0,
        }, -- end of ["FUEL_BOOSTER_FUEL_PUMP_2_DEGRADED"]
        ["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"]
        ["MAINPOWER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MAINPOWER",
            ["mm"] = 0,
        }, -- end of ["MAINPOWER"]
        ["sensf_PITOT_DAMAGE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "sensf_PITOT_DAMAGE",
            ["mm"] = 0,
        }, -- end of ["sensf_PITOT_DAMAGE"]
        ["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"]
        ["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_SMS_PYLON_6"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_SMS_PYLON_6",
            ["mm"] = 0,
        }, -- end of ["FAILURE_SMS_PYLON_6"]
        ["slat_inner_right_stuck"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "slat_inner_right_stuck",
            ["mm"] = 0,
        }, -- end of ["slat_inner_right_stuck"]
        ["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"]
        ["engine_surge_failure"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "engine_surge_failure",
            ["mm"] = 0,
        }, -- end of ["engine_surge_failure"]
        ["RWRANTLEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWRANTLEFT",
            ["mm"] = 0,
        }, -- end of ["RWRANTLEFT"]
        ["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"]
        ["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"]
        ["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"]
        ["right_rear_leaks"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "right_rear_leaks",
            ["mm"] = 0,
        }, -- end of ["right_rear_leaks"]
        ["PILOT_KILLED_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PILOT_KILLED_FAILURE",
            ["mm"] = 0,
        }, -- end of ["PILOT_KILLED_FAILURE"]
        ["Vibration_RightEngine"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "Vibration_RightEngine",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["Vibration_RightEngine"]
        ["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"]
        ["start_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "start_fail",
            ["mm"] = 0,
        }, -- end of ["start_fail"]
        ["BAT_SOLENOID_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BAT_SOLENOID_FAULT",
            ["mm"] = 0,
        }, -- end of ["BAT_SOLENOID_FAULT"]
        ["R_ENG_NOZZLE_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_ENG_NOZZLE_FAILURE",
            ["mm"] = 0,
        }, -- end of ["R_ENG_NOZZLE_FAILURE"]
        ["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"]
        ["JESTER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "JESTER",
            ["mm"] = 0,
        }, -- end of ["JESTER"]
        ["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"]
        ["COM1_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COM1_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["COM1_FAILURE_TOTAL"]
        ["miss_bus_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "miss_bus_fail",
            ["mm"] = 0,
        }, -- end of ["miss_bus_fail"]
        ["GMC_GYRO_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "GMC_GYRO_FAILURE",
            ["mm"] = 0,
        }, -- end of ["GMC_GYRO_FAILURE"]
        ["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"]
        ["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"]
        ["fsf_LeftBoostPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fsf_LeftBoostPump",
            ["mm"] = 0,
        }, -- end of ["fsf_LeftBoostPump"]
        ["UNCR_LH_STRUT_HOSE_PIERCED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UNCR_LH_STRUT_HOSE_PIERCED",
            ["mm"] = 0,
        }, -- end of ["UNCR_LH_STRUT_HOSE_PIERCED"]
        ["SWMMC_FAILURE_HUD"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_HUD",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_HUD"]
        ["COOLANT_SHORT_CIRCUIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COOLANT_SHORT_CIRCUIT",
            ["mm"] = 0,
        }, -- end of ["COOLANT_SHORT_CIRCUIT"]
        ["engine_droop_failure"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "engine_droop_failure",
            ["mm"] = 0,
        }, -- end of ["engine_droop_failure"]
        ["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"]
        ["ignition_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ignition_fail",
            ["mm"] = 0,
        }, -- end of ["ignition_fail"]
        ["L_ENG_TURBINE_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_ENG_TURBINE_FAILURE",
            ["mm"] = 0,
        }, -- end of ["L_ENG_TURBINE_FAILURE"]
        ["SUPERCHARGER_WIRE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SUPERCHARGER_WIRE",
            ["mm"] = 0,
        }, -- end of ["SUPERCHARGER_WIRE"]
        ["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"]
        ["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"]
        ["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"]
        ["discharge_valves_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "discharge_valves_fail",
            ["mm"] = 0,
        }, -- end of ["discharge_valves_fail"]
        ["R_ENG_TURBINE_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_ENG_TURBINE_FAILURE",
            ["mm"] = 0,
        }, -- end of ["R_ENG_TURBINE_FAILURE"]
        ["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"]
        ["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"]
        ["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"]
        ["COMPASS_ERRATIC_INDIACATON"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COMPASS_ERRATIC_INDIACATON",
            ["mm"] = 0,
        }, -- end of ["COMPASS_ERRATIC_INDIACATON"]
        ["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"]
        ["EMERGENCY_GEAR_LEVER_PULLED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMERGENCY_GEAR_LEVER_PULLED",
            ["mm"] = 0,
        }, -- end of ["EMERGENCY_GEAR_LEVER_PULLED"]
        ["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"]
        ["hydr1_reserv_leaks"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hydr1_reserv_leaks",
            ["mm"] = 0,
        }, -- end of ["hydr1_reserv_leaks"]
        ["Failure_Elec_LeftTransformerRectifier"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Elec_LeftTransformerRectifier",
            ["mm"] = 0,
        }, -- end of ["Failure_Elec_LeftTransformerRectifier"]
        ["RGear_ret_fault"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RGear_ret_fault",
            ["mm"] = 0,
        }, -- end of ["RGear_ret_fault"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["oil_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "oil_fail",
            ["mm"] = 0,
        }, -- end of ["oil_fail"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["LANDINGGEARR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LANDINGGEARR",
            ["mm"] = 0,
        }, -- end of ["LANDINGGEARR"]
        ["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"]
        ["trim_pitch_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "trim_pitch_fail",
            ["mm"] = 0,
        }, -- end of ["trim_pitch_fail"]
        ["R_ENG_AICS_RAMP_FAIL_CLOSED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_ENG_AICS_RAMP_FAIL_CLOSED",
            ["mm"] = 0,
        }, -- end of ["R_ENG_AICS_RAMP_FAIL_CLOSED"]
        ["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"]
        ["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"]
        ["hydr_serv_leaks"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hydr_serv_leaks",
            ["mm"] = 0,
        }, -- end of ["hydr_serv_leaks"]
        ["R_ENG_OIL_LEAK_SEVERE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_ENG_OIL_LEAK_SEVERE",
            ["mm"] = 0,
        }, -- end of ["R_ENG_OIL_LEAK_SEVERE"]
        ["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"]
        ["gear_nose_stuck"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "gear_nose_stuck",
            ["mm"] = 0,
        }, -- end of ["gear_nose_stuck"]
        ["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"]
        ["CTRL_LANDING_FLAPS_LH_HOSE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CTRL_LANDING_FLAPS_LH_HOSE",
            ["mm"] = 0,
        }, -- end of ["CTRL_LANDING_FLAPS_LH_HOSE"]
        ["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"]
        ["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"]
        ["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"]
        ["asc_p"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "asc_p",
            ["mm"] = 0,
        }, -- end of ["asc_p"]
        ["RPMFault_RightEngine"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "RPMFault_RightEngine",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["RPMFault_RightEngine"]
        ["INS_WIND_INVALID"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_WIND_INVALID",
            ["mm"] = 0,
        }, -- end of ["INS_WIND_INVALID"]
        ["RB05ANT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RB05ANT",
            ["mm"] = 0,
        }, -- end of ["RB05ANT"]
        ["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"]
        ["TACAN_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TACAN_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["TACAN_FAILURE_TOTAL"]
        ["apus"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "apus",
            ["mm"] = 0,
        }, -- end of ["apus"]
        ["l_gen"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "l_gen",
            ["mm"] = 0,
        }, -- end of ["l_gen"]
        ["Surge_RightEngine"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Surge_RightEngine",
            ["mm"] = 0,
        }, -- end of ["Surge_RightEngine"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["L_ENG_OIL_LEAK_SEVERE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_ENG_OIL_LEAK_SEVERE",
            ["mm"] = 0,
        }, -- end of ["L_ENG_OIL_LEAK_SEVERE"]
        ["TACAN_FAILURE_RECEIVER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TACAN_FAILURE_RECEIVER",
            ["mm"] = 0,
        }, -- end of ["TACAN_FAILURE_RECEIVER"]
        ["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"]
        ["MWMMC_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE"]
        ["APU_Fire"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "APU_Fire",
            ["mm"] = 0,
        }, -- end of ["APU_Fire"]
        ["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"]
        ["hs_damage_MainAutoUnload"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hs_damage_MainAutoUnload",
            ["mm"] = 0,
        }, -- end of ["hs_damage_MainAutoUnload"]
        ["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"]
        ["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"]
        ["Failure_RightEngine"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_RightEngine",
            ["mm"] = 0,
        }, -- end of ["Failure_RightEngine"]
        ["right_front_leaks"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "right_front_leaks",
            ["mm"] = 0,
        }, -- end of ["right_front_leaks"]
        ["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"]
        ["DMT_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DMT_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["DMT_FAILURE_TOTAL"]
        ["OIL_RADIATOR_WIRING"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OIL_RADIATOR_WIRING",
            ["mm"] = 0,
        }, -- end of ["OIL_RADIATOR_WIRING"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["vor_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "vor_fail",
            ["mm"] = 0,
        }, -- end of ["vor_fail"]
        ["LeftEngine_LowOilPressure"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LeftEngine_LowOilPressure",
            ["mm"] = 0,
        }, -- end of ["LeftEngine_LowOilPressure"]
        ["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"]
        ["RADARDISPL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RADARDISPL",
            ["mm"] = 0,
        }, -- end of ["RADARDISPL"]
        ["ELEC_ROCKETS_CIRCUITRY_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_ROCKETS_CIRCUITRY_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_ROCKETS_CIRCUITRY_FAILURE"]
        ["PUMP_FAILS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PUMP_FAILS",
            ["mm"] = 0,
        }, -- end of ["PUMP_FAILS"]
        ["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"]
        ["pitch_chain_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pitch_chain_fail",
            ["mm"] = 0,
        }, -- end of ["pitch_chain_fail"]
        ["total_comp_stall"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "total_comp_stall",
            ["mm"] = 0,
        }, -- end of ["total_comp_stall"]
        ["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"]
        ["SAR_1_101"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SAR_1_101",
            ["mm"] = 0,
        }, -- end of ["SAR_1_101"]
        ["MainReductor_LowOilPressure"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MainReductor_LowOilPressure",
            ["mm"] = 0,
        }, -- end of ["MainReductor_LowOilPressure"]
        ["RWR_FAILURE_BLANKER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_BLANKER",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_BLANKER"]
        ["STATION_4_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STATION_4_FAILURE",
            ["mm"] = 0,
        }, -- end of ["STATION_4_FAILURE"]
        ["esf_RightGenerator"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "esf_RightGenerator",
            ["mm"] = 0,
        }, -- end of ["esf_RightGenerator"]
        ["COOLANT_BREAK_BULB"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COOLANT_BREAK_BULB",
            ["mm"] = 0,
        }, -- end of ["COOLANT_BREAK_BULB"]
        ["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"]
        ["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_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"]
        ["CNI_FAILURE_RALT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CNI_FAILURE_RALT",
            ["mm"] = 0,
        }, -- end of ["CNI_FAILURE_RALT"]
        ["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"]
        ["slat_outer_right_stuck"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "slat_outer_right_stuck",
            ["mm"] = 0,
        }, -- end of ["slat_outer_right_stuck"]
        ["INSUF_FUEL_PRES"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INSUF_FUEL_PRES",
            ["mm"] = 0,
        }, -- end of ["INSUF_FUEL_PRES"]
        ["ENG0_TURBINE_OIL_TANK_PIERCED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENG0_TURBINE_OIL_TANK_PIERCED",
            ["mm"] = 0,
        }, -- end of ["ENG0_TURBINE_OIL_TANK_PIERCED"]
        ["ILS_FAILURE_DECODER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ILS_FAILURE_DECODER",
            ["mm"] = 0,
        }, -- end of ["ILS_FAILURE_DECODER"]
        ["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"]
        ["ENGINE_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENGINE_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ENGINE_FAILURE"]
        ["Failure_Fuel_Tank1Transfer"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Fuel_Tank1Transfer",
            ["mm"] = 0,
        }, -- end of ["Failure_Fuel_Tank1Transfer"]
        ["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_STARTER_RELAY_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_STARTER_RELAY_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_STARTER_RELAY_FAILURE"]
        ["EXT_TANK_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EXT_TANK_LEAK",
            ["mm"] = 0,
        }, -- end of ["EXT_TANK_LEAK"]
        ["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"]
        ["gyros_main_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "gyros_main_fail",
            ["mm"] = 0,
        }, -- end of ["gyros_main_fail"]
        ["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"]
        ["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"]
        ["HYDR_PUMP_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYDR_PUMP_FAILURE",
            ["mm"] = 0,
        }, -- end of ["HYDR_PUMP_FAILURE"]
        ["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"]
        ["TGP_FAILURE_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TGP_FAILURE_RIGHT",
            ["mm"] = 0,
        }, -- end of ["TGP_FAILURE_RIGHT"]
        ["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"]
        ["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"]
        ["TailRotorControlFailure"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TailRotorControlFailure",
            ["mm"] = 0,
        }, -- end of ["TailRotorControlFailure"]
        ["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"]
        ["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"]
        ["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"]
        ["STATION_1_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STATION_1_FAILURE",
            ["mm"] = 0,
        }, -- end of ["STATION_1_FAILURE"]
        ["left_rear_transfer_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "left_rear_transfer_fail",
            ["mm"] = 0,
        }, -- end of ["left_rear_transfer_fail"]
        ["RUDDER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RUDDER",
            ["mm"] = 0,
        }, -- end of ["RUDDER"]
        ["CADC_FAILURE_TAS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CADC_FAILURE_TAS",
            ["mm"] = 0,
        }, -- end of ["CADC_FAILURE_TAS"]
        ["ELEC_ROCKETS_STEP_MOTOR_MALFUNCTION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_ROCKETS_STEP_MOTOR_MALFUNCTION",
            ["mm"] = 0,
        }, -- end of ["ELEC_ROCKETS_STEP_MOTOR_MALFUNCTION"]
        ["RWR_FAILURE_SENSOR_TAIL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_SENSOR_TAIL",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_SENSOR_TAIL"]
        ["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"]
        ["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"]
        ["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"]
        ["es_damage_Starter"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "es_damage_Starter",
            ["mm"] = 0,
        }, -- end of ["es_damage_Starter"]
        ["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"]
        ["nosecone_stuck"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "nosecone_stuck",
            ["mm"] = 0,
        }, -- end of ["nosecone_stuck"]
        ["MWMMC_FAILURE_MBI"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MWMMC_FAILURE_MBI",
            ["mm"] = 0,
        }, -- end of ["MWMMC_FAILURE_MBI"]
        ["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"]
        ["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"]
        ["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"]
        ["l_engine"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "l_engine",
            ["mm"] = 0,
        }, -- end of ["l_engine"]
        ["gyros_general_BSM_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "gyros_general_BSM_fail",
            ["mm"] = 0,
        }, -- end of ["gyros_general_BSM_fail"]
        ["SWMMC_FAILURE_MBI"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_MBI",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_MBI"]
        ["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"]
        ["ELECTRIC_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELECTRIC_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELECTRIC_FAILURE"]
        ["LEFT_CYLINDER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LEFT_CYLINDER",
            ["mm"] = 0,
        }, -- end of ["LEFT_CYLINDER"]
        ["TCN_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "TCN_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["TCN_FAILURE_TOTAL"]
        ["front_central_transfer_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "front_central_transfer_fail",
            ["mm"] = 0,
        }, -- end of ["front_central_transfer_fail"]
        ["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"]
        ["INS_FAILURE_GYRO"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_FAILURE_GYRO",
            ["mm"] = 0,
        }, -- end of ["INS_FAILURE_GYRO"]
        ["HYDR2PUMP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HYDR2PUMP",
            ["mm"] = 0,
        }, -- end of ["HYDR2PUMP"]
        ["MAINGENERATOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MAINGENERATOR",
            ["mm"] = 0,
        }, -- end of ["MAINGENERATOR"]
        ["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"]
        ["overspeed_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "overspeed_fail",
            ["mm"] = 0,
        }, -- end of ["overspeed_fail"]
        ["R_ENG_OIL_LEAK_SLOW"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_ENG_OIL_LEAK_SLOW",
            ["mm"] = 0,
        }, -- end of ["R_ENG_OIL_LEAK_SLOW"]
        ["EGI_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EGI_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["EGI_FAILURE_TOTAL"]
        ["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"]
        ["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"]
        ["ELEC_STARTER_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_STARTER_FAILURE",
            ["mm"] = 0,
        }, -- end of ["ELEC_STARTER_FAILURE"]
        ["AHRS_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AHRS_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["AHRS_FAILURE_TOTAL"]
        ["engine_flameout"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "engine_flameout",
            ["mm"] = 0,
        }, -- end of ["engine_flameout"]
        ["broken_guards"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "broken_guards",
            ["mm"] = 0,
        }, -- end of ["broken_guards"]
        ["L_ENG_OIL_LEAK_SLOW"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_ENG_OIL_LEAK_SLOW",
            ["mm"] = 0,
        }, -- end of ["L_ENG_OIL_LEAK_SLOW"]
        ["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"]
        ["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"]
        ["CNI_FAILURE_COM1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CNI_FAILURE_COM1",
            ["mm"] = 0,
        }, -- end of ["CNI_FAILURE_COM1"]
        ["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"]
        ["RightEngine_LowOilPressure"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RightEngine_LowOilPressure",
            ["mm"] = 0,
        }, -- end of ["RightEngine_LowOilPressure"]
        ["SWMMC_FAILURE_CSU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_CSU",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_CSU"]
        ["radar"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "radar",
            ["mm"] = 0,
        }, -- end of ["radar"]
        ["DOPPLER_UNIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DOPPLER_UNIT",
            ["mm"] = 0,
        }, -- end of ["DOPPLER_UNIT"]
        ["SWMMC_FAILURE_AAP"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_AAP",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_AAP"]
        ["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"]
        ["PNEM_COMPRESSOR_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PNEM_COMPRESSOR_FAILURE",
            ["mm"] = 0,
        }, -- end of ["PNEM_COMPRESSOR_FAILURE"]
        ["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"]
        ["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"]
        ["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"]
        ["esf_StaticInverter"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "esf_StaticInverter",
            ["mm"] = 0,
        }, -- end of ["esf_StaticInverter"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["Failure_ECS_Valve"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_ECS_Valve",
            ["mm"] = 0,
        }, -- end of ["Failure_ECS_Valve"]
        ["Failure_Fuel_RightBoostPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Fuel_RightBoostPump",
            ["mm"] = 0,
        }, -- end of ["Failure_Fuel_RightBoostPump"]
        ["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"]
        ["PITOT_HEAT_FAULT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "PITOT_HEAT_FAULT",
            ["mm"] = 0,
        }, -- end of ["PITOT_HEAT_FAULT"]
        ["EZ42_MOTOR_DEFECTIVE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EZ42_MOTOR_DEFECTIVE",
            ["mm"] = 0,
        }, -- end of ["EZ42_MOTOR_DEFECTIVE"]
        ["FAULTY_ROCKET_LEFT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAULTY_ROCKET_LEFT",
            ["mm"] = 0,
        }, -- end of ["FAULTY_ROCKET_LEFT"]
        ["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"]
        ["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"]
        ["BAT_SOLENOID_DEFECTIVE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BAT_SOLENOID_DEFECTIVE",
            ["mm"] = 0,
        }, -- end of ["BAT_SOLENOID_DEFECTIVE"]
        ["FUELTANK3L"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUELTANK3L",
            ["mm"] = 0,
        }, -- end of ["FUELTANK3L"]
        ["FUEL_TANK_03_LEAK_STOPPED"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_03_LEAK_STOPPED",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_03_LEAK_STOPPED"]
        ["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"]
        ["pp_damage_OilPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pp_damage_OilPump",
            ["mm"] = 0,
        }, -- end of ["pp_damage_OilPump"]
        ["left_front_leaks"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "left_front_leaks",
            ["mm"] = 0,
        }, -- end of ["left_front_leaks"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["COMPRESSOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COMPRESSOR",
            ["mm"] = 0,
        }, -- end of ["COMPRESSOR"]
        ["BURNER"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BURNER",
            ["mm"] = 0,
        }, -- end of ["BURNER"]
        ["MainReducer_Fire"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MainReducer_Fire",
            ["mm"] = 0,
        }, -- end of ["MainReducer_Fire"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["CARBAIR_SHORT_CIRCUIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CARBAIR_SHORT_CIRCUIT",
            ["mm"] = 0,
        }, -- end of ["CARBAIR_SHORT_CIRCUIT"]
        ["STARTER_RELAY"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "STARTER_RELAY",
            ["mm"] = 0,
        }, -- end of ["STARTER_RELAY"]
        ["R_ENG_AICS_RAMP_FAIL_IN_POS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_ENG_AICS_RAMP_FAIL_IN_POS",
            ["mm"] = 0,
        }, -- end of ["R_ENG_AICS_RAMP_FAIL_IN_POS"]
        ["left_fuel_pump_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "left_fuel_pump_fail",
            ["mm"] = 0,
        }, -- end of ["left_fuel_pump_fail"]
        ["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"]
        ["COM2_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COM2_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["COM2_FAILURE_TOTAL"]
        ["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"]
        ["Failure_Sens_RightPitotHeater"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Sens_RightPitotHeater",
            ["mm"] = 0,
        }, -- end of ["Failure_Sens_RightPitotHeater"]
        ["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"]
        ["HAW"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "HAW",
            ["mm"] = 0,
        }, -- end of ["HAW"]
        ["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"]
        ["SWMMC_FAILURE_AVI"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SWMMC_FAILURE_AVI",
            ["mm"] = 0,
        }, -- end of ["SWMMC_FAILURE_AVI"]
        ["OXYGEN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "OXYGEN",
            ["mm"] = 0,
        }, -- end of ["OXYGEN"]
        ["LEFT_MFCD_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "LEFT_MFCD_FAILURE",
            ["mm"] = 0,
        }, -- end of ["LEFT_MFCD_FAILURE"]
        ["pitot_heat_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pitot_heat_fail",
            ["mm"] = 0,
        }, -- end of ["pitot_heat_fail"]
        ["battery_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "battery_fail",
            ["mm"] = 0,
        }, -- end of ["battery_fail"]
        ["CNI_FAILURE_COM2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CNI_FAILURE_COM2",
            ["mm"] = 0,
        }, -- end of ["CNI_FAILURE_COM2"]
        ["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"]
        ["DOORS_TVC_BROKEN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DOORS_TVC_BROKEN",
            ["mm"] = 0,
        }, -- end of ["DOORS_TVC_BROKEN"]
        ["BOOSTER_COIL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BOOSTER_COIL",
            ["mm"] = 0,
        }, -- end of ["BOOSTER_COIL"]
        ["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"]
        ["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"]
        ["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"]
        ["DNS_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DNS_FAILURE",
            ["mm"] = 0,
        }, -- end of ["DNS_FAILURE"]
        ["L_ENG_NOZZLE_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_ENG_NOZZLE_FAILURE",
            ["mm"] = 0,
        }, -- end of ["L_ENG_NOZZLE_FAILURE"]
        ["ENGINE_JAM"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ENGINE_JAM",
            ["mm"] = 0,
        }, -- end of ["ENGINE_JAM"]
        ["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"]
        ["MAGNETO_2"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "MAGNETO_2",
            ["mm"] = 0,
        }, -- end of ["MAGNETO_2"]
        ["L_ENG_AICS_RAMP_FAIL_CLOSED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_ENG_AICS_RAMP_FAIL_CLOSED",
            ["mm"] = 0,
        }, -- end of ["L_ENG_AICS_RAMP_FAIL_CLOSED"]
        ["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"]
        ["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_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"]
        ["RWRANTRIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWRANTRIGHT",
            ["mm"] = 0,
        }, -- end of ["RWRANTRIGHT"]
        ["RWR_FAILURE_MBE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_MBE",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_MBE"]
        ["FUEL_TANK_03_MAJOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_03_MAJOR_LEAK",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_03_MAJOR_LEAK"]
        ["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"]
        ["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"]
        ["UNCR_C_STRUT_HOSE_PIERCED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "UNCR_C_STRUT_HOSE_PIERCED",
            ["mm"] = 0,
        }, -- end of ["UNCR_C_STRUT_HOSE_PIERCED"]
        ["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"]
        ["FUELTANK5L"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FUELTANK5L",
            ["mm"] = 0,
        }, -- end of ["FUELTANK5L"]
        ["Failure_Elec_UtilityBattery"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Elec_UtilityBattery",
            ["mm"] = 0,
        }, -- end of ["Failure_Elec_UtilityBattery"]
        ["EEC_Failure_LeftEngine"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EEC_Failure_LeftEngine",
            ["mm"] = 0,
        }, -- end of ["EEC_Failure_LeftEngine"]
        ["FUEL_NITRO_TANK_00_MINOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_NITRO_TANK_00_MINOR_LEAK",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_NITRO_TANK_00_MINOR_LEAK"]
        ["IFFCC_FAILURE_GUN"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "IFFCC_FAILURE_GUN",
            ["mm"] = 0,
        }, -- end of ["IFFCC_FAILURE_GUN"]
        ["hydr2_pump_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hydr2_pump_fail",
            ["mm"] = 0,
        }, -- end of ["hydr2_pump_fail"]
        ["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"]
        ["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"]
        ["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"]
        ["CICU_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CICU_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["CICU_FAILURE_TOTAL"]
        ["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"]
        ["L_ENG_OIL_LEAK_MODERATE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_ENG_OIL_LEAK_MODERATE",
            ["mm"] = 0,
        }, -- end of ["L_ENG_OIL_LEAK_MODERATE"]
        ["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"]
        ["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"]
        ["BACKUPGENERATOR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "BACKUPGENERATOR",
            ["mm"] = 0,
        }, -- end of ["BACKUPGENERATOR"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["hs_damage_MainHydro"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "hs_damage_MainHydro",
            ["mm"] = 0,
        }, -- end of ["hs_damage_MainHydro"]
        ["tr1_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "tr1_fail",
            ["mm"] = 0,
        }, -- end of ["tr1_fail"]
        ["FUEL_TANK_03_MINOR_LEAK"] = 
        {
            ["hh"] = 0,
            ["id"] = "FUEL_TANK_03_MINOR_LEAK",
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["FUEL_TANK_03_MINOR_LEAK"]
        ["ELEC_ROCKETS_RH_LOOM_SEVERED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ELEC_ROCKETS_RH_LOOM_SEVERED",
            ["mm"] = 0,
        }, -- end of ["ELEC_ROCKETS_RH_LOOM_SEVERED"]
        ["INS_PART_FAIL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_PART_FAIL",
            ["mm"] = 0,
        }, -- end of ["INS_PART_FAIL"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["rotor"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "rotor",
            ["mm"] = 0,
        }, -- end of ["rotor"]
        ["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"]
        ["RADIO_FAILURE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RADIO_FAILURE",
            ["mm"] = 0,
        }, -- end of ["RADIO_FAILURE"]
        ["left_wing_transfer_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "left_wing_transfer_fail",
            ["mm"] = 0,
        }, -- end of ["left_wing_transfer_fail"]
        ["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"]
        ["RADARALTUNIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RADARALTUNIT",
            ["mm"] = 0,
        }, -- end of ["RADARALTUNIT"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["TransitionalReductor_LowOilPressure"] = 
        {
            ["hh"] = 0,
            ["enable"] = false,
            ["prob"] = 100,
            ["id"] = "TransitionalReductor_LowOilPressure",
            ["mmint"] = 1,
            ["hidden"] = true,
            ["mm"] = 0,
        }, -- end of ["TransitionalReductor_LowOilPressure"]
        ["SUPERCHARGER_SOLENOID"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SUPERCHARGER_SOLENOID",
            ["mm"] = 0,
        }, -- end of ["SUPERCHARGER_SOLENOID"]
        ["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"]
        ["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"]
        ["R_ENG_AFTC_PRI_FAILED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "R_ENG_AFTC_PRI_FAILED",
            ["mm"] = 0,
        }, -- end of ["R_ENG_AFTC_PRI_FAILED"]
        ["generator_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "generator_fail",
            ["mm"] = 0,
        }, -- end of ["generator_fail"]
        ["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"]
        ["L_ENG_AICS_RAMP_FAIL_IN_POS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_ENG_AICS_RAMP_FAIL_IN_POS",
            ["mm"] = 0,
        }, -- end of ["L_ENG_AICS_RAMP_FAIL_IN_POS"]
        ["NGear_ext_fault"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "NGear_ext_fault",
            ["mm"] = 0,
        }, -- end of ["NGear_ext_fault"]
        ["INS_FAILURE_ALGNMENT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_FAILURE_ALGNMENT",
            ["mm"] = 0,
        }, -- end of ["INS_FAILURE_ALGNMENT"]
        ["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"]
        ["L_ENG_AFTC_PRI_FAILED"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "L_ENG_AFTC_PRI_FAILED",
            ["mm"] = 0,
        }, -- end of ["L_ENG_AFTC_PRI_FAILED"]
        ["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"]
        ["INST_VARIOMETR_DEPRESSURIZATION"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INST_VARIOMETR_DEPRESSURIZATION",
            ["mm"] = 0,
        }, -- end of ["INST_VARIOMETR_DEPRESSURIZATION"]
        ["Failure_Fuel_ExtTankTransferR"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Fuel_ExtTankTransferR",
            ["mm"] = 0,
        }, -- end of ["Failure_Fuel_ExtTankTransferR"]
        ["VHF_CRYSTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VHF_CRYSTAL",
            ["mm"] = 0,
        }, -- end of ["VHF_CRYSTAL"]
        ["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"]
        ["DEFECTIVE_MECHANISM"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "DEFECTIVE_MECHANISM",
            ["mm"] = 0,
        }, -- end of ["DEFECTIVE_MECHANISM"]
        ["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"]
        ["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"]
        ["inverter2_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "inverter2_fail",
            ["mm"] = 0,
        }, -- end of ["inverter2_fail"]
        ["RWRUNIT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWRUNIT",
            ["mm"] = 0,
        }, -- end of ["RWRUNIT"]
        ["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"]
        ["ppf_LeftGearbox"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ppf_LeftGearbox",
            ["mm"] = 0,
        }, -- end of ["ppf_LeftGearbox"]
        ["INS_GYROS_FAIL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "INS_GYROS_FAIL",
            ["mm"] = 0,
        }, -- end of ["INS_GYROS_FAIL"]
        ["fs_damage_FuelBoosterPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fs_damage_FuelBoosterPump",
            ["mm"] = 0,
        }, -- end of ["fs_damage_FuelBoosterPump"]
        ["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"]
        ["triphase_inv_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "triphase_inv_fail",
            ["mm"] = 0,
        }, -- end of ["triphase_inv_fail"]
        ["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"]
        ["K14_MOTOR_DEFECTIVE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "K14_MOTOR_DEFECTIVE",
            ["mm"] = 0,
        }, -- end of ["K14_MOTOR_DEFECTIVE"]
        ["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"]
        ["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"]
        ["autopilot"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "autopilot",
            ["mm"] = 0,
        }, -- end of ["autopilot"]
        ["ecf"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["mm"] = 0,
        }, -- end of ["ecf"]
        ["VDI_FAILURE_TOTAL"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "VDI_FAILURE_TOTAL",
            ["mm"] = 0,
        }, -- end of ["VDI_FAILURE_TOTAL"]
        ["ef_fire"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ef_fire",
            ["mm"] = 0,
        }, -- end of ["ef_fire"]
        ["COOLANT_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "COOLANT_LEAK",
            ["mm"] = 0,
        }, -- end of ["COOLANT_LEAK"]
        ["right_feeder_leaks"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "right_feeder_leaks",
            ["mm"] = 0,
        }, -- end of ["right_feeder_leaks"]
        ["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"]
        ["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"]
        ["left_wing_leaks"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "left_wing_leaks",
            ["mm"] = 0,
        }, -- end of ["left_wing_leaks"]
        ["fs_damage_MainPump"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "fs_damage_MainPump",
            ["mm"] = 0,
        }, -- end of ["fs_damage_MainPump"]
        ["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"]
        ["CNI_FAILURE_ILS"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CNI_FAILURE_ILS",
            ["mm"] = 0,
        }, -- end of ["CNI_FAILURE_ILS"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["engine_fire"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "engine_fire",
            ["mm"] = 0,
        }, -- end of ["engine_fire"]
        ["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"]
        ["EXT_HYDRO_LEAK"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EXT_HYDRO_LEAK",
            ["mm"] = 0,
        }, -- end of ["EXT_HYDRO_LEAK"]
        ["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"]
        ["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"]
        ["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"]
        ["RWR_FAILURE_QUAD135"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "RWR_FAILURE_QUAD135",
            ["mm"] = 0,
        }, -- end of ["RWR_FAILURE_QUAD135"]
        ["AHRS_FAILURE_MAD"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "AHRS_FAILURE_MAD",
            ["mm"] = 0,
        }, -- end of ["AHRS_FAILURE_MAD"]
        ["ROCKETS_INTERVALOMETER_SEQ"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "ROCKETS_INTERVALOMETER_SEQ",
            ["mm"] = 0,
        }, -- end of ["ROCKETS_INTERVALOMETER_SEQ"]
        ["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"]
        ["Failure_Elec_RightTransformerRectifier"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Elec_RightTransformerRectifier",
            ["mm"] = 0,
        }, -- end of ["Failure_Elec_RightTransformerRectifier"]
        ["SAR_2_101"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "SAR_2_101",
            ["mm"] = 0,
        }, -- end of ["SAR_2_101"]
        ["EMMC_FAILURE_TRU"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "EMMC_FAILURE_TRU",
            ["mm"] = 0,
        }, -- end of ["EMMC_FAILURE_TRU"]
        ["pp_damage_EmergMaxFreq"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "pp_damage_EmergMaxFreq",
            ["mm"] = 0,
        }, -- end of ["pp_damage_EmergMaxFreq"]
        ["FAULTY_ROCKET_RIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAULTY_ROCKET_RIGHT",
            ["mm"] = 0,
        }, -- end of ["FAULTY_ROCKET_RIGHT"]
        ["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"]
        ["Failure_Comp_MC1"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "Failure_Comp_MC1",
            ["mm"] = 0,
        }, -- end of ["Failure_Comp_MC1"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["left_airbrake_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "left_airbrake_fail",
            ["mm"] = 0,
        }, -- end of ["left_airbrake_fail"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["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"]
        ["external_tanks_transfer_fail"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "external_tanks_transfer_fail",
            ["mm"] = 0,
        }, -- end of ["external_tanks_transfer_fail"]
        ["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"]
        ["FAILURE_SNS_CABLE"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "FAILURE_SNS_CABLE",
            ["mm"] = 0,
        }, -- end of ["FAILURE_SNS_CABLE"]
        ["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"]
        ["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"]
        ["CANARDFLAPRIGHT"] = 
        {
            ["hh"] = 0,
            ["prob"] = 100,
            ["enable"] = false,
            ["mmint"] = 1,
            ["id"] = "CANARDFLAPRIGHT",
            ["mm"] = 0,
        }, -- end of ["CANARDFLAPRIGHT"]
        ["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"]
    ["forcedOptions"] = 
    {
        ["fuel"] = false,
        ["miniHUD"] = false,
        ["accidental_failures"] = false,
        ["optionsView"] = "optview_all",
        ["permitCrash"] = true,
        ["immortal"] = false,
        ["easyCommunication"] = true,
        ["wakeTurbulence"] = false,
        ["easyFlight"] = false,
        ["radio"] = false,
        ["labels"] = 3,
        ["birds"] = 0,
        ["padlock"] = false,
        ["unrestrictedSATNAV"] = false,
        ["userMarks"] = true,
        ["RBDAI"] = true,
        ["externalViews"] = true,
        ["cockpitVisualRM"] = false,
        ["civTraffic"] = "",
        ["weapons"] = false,
        ["cockpitStatusBarAllowed"] = false,
        ["geffect"] = "realistic",
    }, -- end of ["forcedOptions"]
    ["start_time"] = 28800,
} -- end of mission
