{
  "ok": true,
  "tool": "webftr-js8-source-bitpath-extract-pack",
  "tool_version": "step54-source-bitpath-extract-pack",
  "source_dir": "/decoders/js8_decoder/runtime/src/JS8Call-improved",
  "rx_only_guard": {
    "tx": false,
    "ptt": false,
    "tune": false,
    "send": false,
    "js8call_runtime_control": false
  },
  "no_gui_runtime_started": true,
  "purpose": "Extract focused JS8Call-Improved RX-core snippets for source-derived bitpath implementation in JS8Lab.",
  "scanned_target_files": 12,
  "existing_target_files": 12,
  "missing_target_files": [],
  "phase_top_files": {
    "timing_submode": [
      {
        "path": "JS8_Mode/JS8Submode.cpp",
        "score": 26,
        "sha256": "10d60fcdd5c908d8"
      },
      {
        "path": "JS8_Mode/JS8.cpp",
        "score": 5,
        "sha256": "b72787f6e6473919"
      },
      {
        "path": "JS8_Include/commons.h",
        "score": 3,
        "sha256": "d7abc3090fcf5516"
      }
    ],
    "symbol_to_soft_bits": [
      {
        "path": "JS8_JSC/JSC_map.cpp",
        "score": 590,
        "sha256": "ab2bd62ef594f462"
      },
      {
        "path": "JS8_JSC/JSC_list.cpp",
        "score": 590,
        "sha256": "993811813f1cd6e0"
      },
      {
        "path": "JS8_Mode/JS8.cpp",
        "score": 184,
        "sha256": "b72787f6e6473919"
      },
      {
        "path": "JS8_Mode/whitening_processor.h",
        "score": 112,
        "sha256": "bcd61a557030caba"
      },
      {
        "path": "JS8_Mode/soft_combiner.h",
        "score": 109,
        "sha256": "59a2c7dafab922a1"
      },
      {
        "path": "JS8_Mode/ldpc_feedback.h",
        "score": 50,
        "sha256": "c9bb4ccc8f3def26"
      },
      {
        "path": "JS8_Mode/JS8Submode.cpp",
        "score": 41,
        "sha256": "10d60fcdd5c908d8"
      },
      {
        "path": "JS8_Include/commons.h",
        "score": 6,
        "sha256": "d7abc3090fcf5516"
      }
    ],
    "bit_order_interleaver": [
      {
        "path": "JS8_JSC/JSC_map.cpp",
        "score": 398,
        "sha256": "ab2bd62ef594f462"
      },
      {
        "path": "JS8_JSC/JSC_list.cpp",
        "score": 398,
        "sha256": "993811813f1cd6e0"
      },
      {
        "path": "JS8_Main/Varicode.cpp",
        "score": 231,
        "sha256": "2b4a877e7dae1a3f"
      },
      {
        "path": "JS8_Mode/JS8.cpp",
        "score": 110,
        "sha256": "b72787f6e6473919"
      },
      {
        "path": "JS8_Main/Varicode.h",
        "score": 32,
        "sha256": "dd7b8bf50466d0d2"
      },
      {
        "path": "JS8_Mode/DecodedText.cpp",
        "score": 24,
        "sha256": "1f3d3a687a0bae5a"
      },
      {
        "path": "JS8_Mode/soft_combiner.h",
        "score": 5,
        "sha256": "59a2c7dafab922a1"
      },
      {
        "path": "JS8_Mode/ldpc_feedback.h",
        "score": 4,
        "sha256": "c9bb4ccc8f3def26"
      }
    ],
    "whitening_erasure": [
      {
        "path": "JS8_JSC/JSC_map.cpp",
        "score": 119,
        "sha256": "ab2bd62ef594f462"
      },
      {
        "path": "JS8_JSC/JSC_list.cpp",
        "score": 119,
        "sha256": "993811813f1cd6e0"
      },
      {
        "path": "JS8_Mode/whitening_processor.h",
        "score": 57,
        "sha256": "bcd61a557030caba"
      },
      {
        "path": "JS8_Mode/JS8.cpp",
        "score": 27,
        "sha256": "b72787f6e6473919"
      },
      {
        "path": "JS8_Main/Varicode.cpp",
        "score": 11,
        "sha256": "2b4a877e7dae1a3f"
      },
      {
        "path": "JS8_Mode/soft_combiner.h",
        "score": 4,
        "sha256": "59a2c7dafab922a1"
      }
    ],
    "ldpc_decode": [
      {
        "path": "JS8_Mode/JS8.cpp",
        "score": 54,
        "sha256": "b72787f6e6473919"
      },
      {
        "path": "JS8_Mode/ldpc_feedback.h",
        "score": 24,
        "sha256": "c9bb4ccc8f3def26"
      },
      {
        "path": "JS8_JSC/JSC_map.cpp",
        "score": 6,
        "sha256": "ab2bd62ef594f462"
      },
      {
        "path": "JS8_JSC/JSC_list.cpp",
        "score": 6,
        "sha256": "993811813f1cd6e0"
      }
    ],
    "message91_crc_text": [
      {
        "path": "JS8_Main/Varicode.cpp",
        "score": 734,
        "sha256": "2b4a877e7dae1a3f"
      },
      {
        "path": "JS8_JSC/JSC_list.cpp",
        "score": 153,
        "sha256": "993811813f1cd6e0"
      },
      {
        "path": "JS8_JSC/JSC_map.cpp",
        "score": 152,
        "sha256": "ab2bd62ef594f462"
      },
      {
        "path": "JS8_Mode/DecodedText.cpp",
        "score": 108,
        "sha256": "1f3d3a687a0bae5a"
      },
      {
        "path": "JS8_Mode/JS8.cpp",
        "score": 88,
        "sha256": "b72787f6e6473919"
      },
      {
        "path": "JS8_Main/Varicode.h",
        "score": 85,
        "sha256": "dd7b8bf50466d0d2"
      },
      {
        "path": "JS8_Mode/JS8Submode.cpp",
        "score": 7,
        "sha256": "10d60fcdd5c908d8"
      }
    ]
  },
  "files": [
    {
      "path": "JS8_Mode/JS8.cpp",
      "exists": true,
      "bytes": 113531,
      "sha256": "b72787f6e6473919872103997ef5dc9847810ff3e7783124a3961a2da2a86bf1",
      "line_count": 2913,
      "phase_hits": {
        "timing_submode": 5,
        "symbol_to_soft_bits": 184,
        "bit_order_interleaver": 110,
        "whitening_erasure": 27,
        "ldpc_decode": 54,
        "message91_crc_text": 88
      },
      "function_blocks": [
        {
          "function": "cos_approx",
          "line": 101,
          "signature": "constexpr double cos_approx(double x) {",
          "snippet": {
            "start_line": 87,
            "end_line": 115,
            "lines": [
              {
                "line": 87,
                "text": "//      expected, look at the Fortran code and compare the array indexing;"
              },
              {
                "line": 88,
                "text": "//      would not be surprised in the least to have off-by-one errors here."
              },
              {
                "line": 89,
                "text": ""
              },
              {
                "line": 90,
                "text": "/******************************************************************************/"
              },
              {
                "line": 91,
                "text": "// Compilation Utilities"
              },
              {
                "line": 92,
                "text": "/******************************************************************************/"
              },
              {
                "line": 93,
                "text": ""
              },
              {
                "line": 94,
                "text": "namespace {"
              },
              {
                "line": 95,
                "text": "// Full-range cosine function using symmetries of cos(x). std::cos"
              },
              {
                "line": 96,
                "text": "// isn't constexpr until C++20, and we're targeting C++17 at the"
              },
              {
                "line": 97,
                "text": "// moment. We only use this function during compilation; std::cos"
              },
              {
                "line": 98,
                "text": "// is the better choice at runtime. Once we move to requiring a"
              },
              {
                "line": 99,
                "text": "// C++20 compiler, we can just use std::cos."
              },
              {
                "line": 100,
                "text": ""
              },
              {
                "line": 101,
                "text": "constexpr double cos_approx(double x) {"
              },
              {
                "line": 102,
                "text": "    constexpr auto RAD_360 = std::numbers::pi * 2;"
              },
              {
                "line": 103,
                "text": "    constexpr auto RAD_180 = std::numbers::pi;"
              },
              {
                "line": 104,
                "text": "    constexpr auto RAD_90 = std::numbers::pi / 2;"
              },
              {
                "line": 105,
                "text": ""
              },
              {
                "line": 106,
                "text": "    // Polynomial approximation of cos(x) for x in [0, RAD_90],"
              },
              {
                "line": 107,
                "text": "    // Accuracy here in theory is 1e-18, but double precision"
              },
              {
                "line": 108,
                "text": "    // itself is only 1-e16, so within the domain of doubles,"
              },
              {
                "line": 109,
                "text": "    // this should be extremely accurate."
              },
              {
                "line": 110,
                "text": ""
              },
              {
                "line": 111,
                "text": "    constexpr auto poly = [](double const x) {"
              },
              {
                "line": 112,
                "text": "        constexpr std::array coefficients = {"
              },
              {
                "line": 113,
                "text": "            1.0,                           // Coefficient for x^0"
              },
              {
                "line": 114,
                "text": "            -0.49999999999999994,          // Coefficient for x^2"
              },
              {
                "line": 115,
                "text": "            0.041666666666666664,          // Coefficient for x^4"
              }
            ]
          }
        },
        {
          "function": "CRC12",
          "line": 891,
          "signature": "template <typename T> std::uint16_t CRC12(T const &range) {",
          "snippet": {
            "start_line": 877,
            "end_line": 905,
            "lines": [
              {
                "line": 877,
                "text": "        }"
              },
              {
                "line": 878,
                "text": ""
              },
              {
                "line": 879,
                "text": "        throw std::runtime_error(\"Invalid character in message\");"
              },
              {
                "line": 880,
                "text": "    };"
              },
              {
                "line": 881,
                "text": "}();"
              },
              {
                "line": 882,
                "text": ""
              },
              {
                "line": 883,
                "text": "// Sanity check key bounds of the 6-bit encoding table."
              },
              {
                "line": 884,
                "text": ""
              },
              {
                "line": 885,
                "text": "static_assert(alphabetWord('0') == 0);"
              },
              {
                "line": 886,
                "text": "static_assert(alphabetWord('A') == 10);"
              },
              {
                "line": 887,
                "text": "static_assert(alphabetWord('a') == 36);"
              },
              {
                "line": 888,
                "text": "static_assert(alphabetWord('-') == 62);"
              },
              {
                "line": 889,
                "text": "static_assert(alphabetWord('+') == 63);"
              },
              {
                "line": 890,
                "text": ""
              },
              {
                "line": 891,
                "text": "template <typename T> std::uint16_t CRC12(T const &range) {"
              },
              {
                "line": 892,
                "text": "    return boost::augmented_crc<12, 0xc06>(range.data(), range.size()) ^ 42;"
              },
              {
                "line": 893,
                "text": "}"
              },
              {
                "line": 894,
                "text": ""
              },
              {
                "line": 895,
                "text": "bool checkCRC12(std::array<std::int8_t, KK> const &decoded) {"
              },
              {
                "line": 896,
                "text": "    std::array<uint8_t, 11> bits = {};"
              },
              {
                "line": 897,
                "text": ""
              },
              {
                "line": 898,
                "text": "    for (std::size_t i = 0; i < decoded.size(); ++i) {"
              },
              {
                "line": 899,
                "text": "        if (decoded[i])"
              },
              {
                "line": 900,
                "text": "            bits[i / 8] |= (1 << (7 - (i % 8)));"
              },
              {
                "line": 901,
                "text": "    }"
              },
              {
                "line": 902,
                "text": ""
              },
              {
                "line": 903,
                "text": "    // Extract the received CRC-12."
              },
              {
                "line": 904,
                "text": ""
              },
              {
                "line": 905,
                "text": "    uint16_t crc = (static_cast<uint16_t>(bits[9] & 0x1F) << 7) |"
              }
            ]
          }
        },
        {
          "function": "checkCRC12",
          "line": 895,
          "signature": "bool checkCRC12(std::array<std::int8_t, KK> const &decoded) {",
          "snippet": {
            "start_line": 881,
            "end_line": 909,
            "lines": [
              {
                "line": 881,
                "text": "}();"
              },
              {
                "line": 882,
                "text": ""
              },
              {
                "line": 883,
                "text": "// Sanity check key bounds of the 6-bit encoding table."
              },
              {
                "line": 884,
                "text": ""
              },
              {
                "line": 885,
                "text": "static_assert(alphabetWord('0') == 0);"
              },
              {
                "line": 886,
                "text": "static_assert(alphabetWord('A') == 10);"
              },
              {
                "line": 887,
                "text": "static_assert(alphabetWord('a') == 36);"
              },
              {
                "line": 888,
                "text": "static_assert(alphabetWord('-') == 62);"
              },
              {
                "line": 889,
                "text": "static_assert(alphabetWord('+') == 63);"
              },
              {
                "line": 890,
                "text": ""
              },
              {
                "line": 891,
                "text": "template <typename T> std::uint16_t CRC12(T const &range) {"
              },
              {
                "line": 892,
                "text": "    return boost::augmented_crc<12, 0xc06>(range.data(), range.size()) ^ 42;"
              },
              {
                "line": 893,
                "text": "}"
              },
              {
                "line": 894,
                "text": ""
              },
              {
                "line": 895,
                "text": "bool checkCRC12(std::array<std::int8_t, KK> const &decoded) {"
              },
              {
                "line": 896,
                "text": "    std::array<uint8_t, 11> bits = {};"
              },
              {
                "line": 897,
                "text": ""
              },
              {
                "line": 898,
                "text": "    for (std::size_t i = 0; i < decoded.size(); ++i) {"
              },
              {
                "line": 899,
                "text": "        if (decoded[i])"
              },
              {
                "line": 900,
                "text": "            bits[i / 8] |= (1 << (7 - (i % 8)));"
              },
              {
                "line": 901,
                "text": "    }"
              },
              {
                "line": 902,
                "text": ""
              },
              {
                "line": 903,
                "text": "    // Extract the received CRC-12."
              },
              {
                "line": 904,
                "text": ""
              },
              {
                "line": 905,
                "text": "    uint16_t crc = (static_cast<uint16_t>(bits[9] & 0x1F) << 7) |"
              },
              {
                "line": 906,
                "text": "                   (static_cast<uint16_t>(bits[10]) >> 1);"
              },
              {
                "line": 907,
                "text": ""
              },
              {
                "line": 908,
                "text": "    // Clear bits that correspond to the CRC in the last bytes."
              },
              {
                "line": 909,
                "text": ""
              }
            ]
          }
        },
        {
          "function": "extractmessage174",
          "line": 918,
          "signature": "std::string extractmessage174(std::array<int8_t, KK> const &decoded) {",
          "snippet": {
            "start_line": 904,
            "end_line": 932,
            "lines": [
              {
                "line": 904,
                "text": ""
              },
              {
                "line": 905,
                "text": "    uint16_t crc = (static_cast<uint16_t>(bits[9] & 0x1F) << 7) |"
              },
              {
                "line": 906,
                "text": "                   (static_cast<uint16_t>(bits[10]) >> 1);"
              },
              {
                "line": 907,
                "text": ""
              },
              {
                "line": 908,
                "text": "    // Clear bits that correspond to the CRC in the last bytes."
              },
              {
                "line": 909,
                "text": ""
              },
              {
                "line": 910,
                "text": "    bits[9] &= 0xE0;"
              },
              {
                "line": 911,
                "text": "    bits[10] = 0x00;"
              },
              {
                "line": 912,
                "text": ""
              },
              {
                "line": 913,
                "text": "    // Compute CRC and indicate if we have a match."
              },
              {
                "line": 914,
                "text": ""
              },
              {
                "line": 915,
                "text": "    return crc == CRC12(bits);"
              },
              {
                "line": 916,
                "text": "}"
              },
              {
                "line": 917,
                "text": ""
              },
              {
                "line": 918,
                "text": "std::string extractmessage174(std::array<int8_t, KK> const &decoded) {"
              },
              {
                "line": 919,
                "text": "    std::string message;"
              },
              {
                "line": 920,
                "text": ""
              },
              {
                "line": 921,
                "text": "    // Ensure received CRC matches computed CRC."
              },
              {
                "line": 922,
                "text": ""
              },
              {
                "line": 923,
                "text": "    if (checkCRC12(decoded)) {"
              },
              {
                "line": 924,
                "text": "        message.reserve(12);"
              },
              {
                "line": 925,
                "text": ""
              },
              {
                "line": 926,
                "text": "        // Decode the message from the 72 data bits"
              },
              {
                "line": 927,
                "text": ""
              },
              {
                "line": 928,
                "text": "        std::array<uint8_t, 12> words;"
              },
              {
                "line": 929,
                "text": ""
              },
              {
                "line": 930,
                "text": "        for (std::size_t i = 0; i < 12; ++i) {"
              },
              {
                "line": 931,
                "text": "            words[i] = (decoded[i * 6 + 0] << 5) | (decoded[i * 6 + 1] << 4) |"
              },
              {
                "line": 932,
                "text": "                       (decoded[i * 6 + 2] << 3) | (decoded[i * 6 + 3] << 2) |"
              }
            ]
          }
        },
        {
          "function": "evaluate",
          "line": 1126,
          "signature": "inline auto evaluate(float const x) const {",
          "snippet": {
            "start_line": 1112,
            "end_line": 1140,
            "lines": [
              {
                "line": 1112,
                "text": "    using Points = Eigen::Matrix<double, BASELINE_NODES.size(), 2>;"
              },
              {
                "line": 1113,
                "text": "    using Vandermonde ="
              },
              {
                "line": 1114,
                "text": "        Eigen::Matrix<double, BASELINE_NODES.size(), BASELINE_NODES.size()>;"
              },
              {
                "line": 1115,
                "text": "    using Coefficients = Eigen::Vector<double, BASELINE_NODES.size()>;"
              },
              {
                "line": 1116,
                "text": ""
              },
              {
                "line": 1117,
                "text": "    Points p;"
              },
              {
                "line": 1118,
                "text": "    Vandermonde V;"
              },
              {
                "line": 1119,
                "text": "    Coefficients c;"
              },
              {
                "line": 1120,
                "text": ""
              },
              {
                "line": 1121,
                "text": "    // Polynomial evaluation using Estrin's method, loop is unrolled at"
              },
              {
                "line": 1122,
                "text": "    // compile time. A compiler should emit SIMD instructions from what"
              },
              {
                "line": 1123,
                "text": "    // it sees here when the optimizer is involved, but even without it,"
              },
              {
                "line": 1124,
                "text": "    // we'll likely see fused multiply-add instructions."
              },
              {
                "line": 1125,
                "text": ""
              },
              {
                "line": 1126,
                "text": "    inline auto evaluate(float const x) const {"
              },
              {
                "line": 1127,
                "text": "        return [this]<Eigen::Index... I>("
              },
              {
                "line": 1128,
                "text": "                   float const x, std::integer_sequence<Eigen::Index, I...>) {"
              },
              {
                "line": 1129,
                "text": "            auto baseline = 0.0;"
              },
              {
                "line": 1130,
                "text": "            auto exponent = 1.0;"
              },
              {
                "line": 1131,
                "text": ""
              },
              {
                "line": 1132,
                "text": "            ((baseline += (c[I * 2] + c[I * 2 + 1] * x) * exponent,"
              },
              {
                "line": 1133,
                "text": "              exponent *= x * x),"
              },
              {
                "line": 1134,
                "text": "             ...);"
              },
              {
                "line": 1135,
                "text": ""
              },
              {
                "line": 1136,
                "text": "            return static_cast<float>(baseline);"
              },
              {
                "line": 1137,
                "text": "        }(x, std::make_integer_sequence<Eigen::Index,"
              },
              {
                "line": 1138,
                "text": "                                        Coefficients::SizeAtCompileTime / 2>{});"
              },
              {
                "line": 1139,
                "text": "    }"
              },
              {
                "line": 1140,
                "text": ""
              }
            ]
          }
        },
        {
          "function": "if",
          "line": 1612,
          "signature": "else if (ipass == 4)",
          "snippet": {
            "start_line": 1598,
            "end_line": 1626,
            "lines": [
              {
                "line": 1598,
                "text": "            }"
              },
              {
                "line": 1599,
                "text": ""
              },
              {
                "line": 1600,
                "text": "            return std::nullopt;"
              },
              {
                "line": 1601,
                "text": "        };"
              },
              {
                "line": 1602,
                "text": ""
              },
              {
                "line": 1603,
                "text": "        // Loop over decoding passes"
              },
              {
                "line": 1604,
                "text": "        for (int ipass = 1; ipass <= 4 && totalLdpcPasses < m_maxLdpcPasses;"
              },
              {
                "line": 1605,
                "text": "             ++ipass) {"
              },
              {
                "line": 1606,
                "text": "            auto &llr = ipass == 2 ? llr1Combined : llr0Combined;"
              },
              {
                "line": 1607,
                "text": ""
              },
              {
                "line": 1608,
                "text": "            // Zero ranges for certain passes to mirror legacy behavior."
              },
              {
                "line": 1609,
                "text": "            if (ipass == 3)"
              },
              {
                "line": 1610,
                "text": "                std::fill(llr0Combined.begin(), llr0Combined.begin() + 24,"
              },
              {
                "line": 1611,
                "text": "                          0.0f);"
              },
              {
                "line": 1612,
                "text": "            else if (ipass == 4)"
              },
              {
                "line": 1613,
                "text": "                std::fill(llr0Combined.begin() + 24, llr0Combined.begin() + 48,"
              },
              {
                "line": 1614,
                "text": "                          0.0f);"
              },
              {
                "line": 1615,
                "text": ""
              },
              {
                "line": 1616,
                "text": "            std::array<float, N> llrPrimary = llr;"
              },
              {
                "line": 1617,
                "text": "            if (auto result = tryDecode(llrPrimary, ipass)) {"
              },
              {
                "line": 1618,
                "text": "                ++totalLdpcPasses;"
              },
              {
                "line": 1619,
                "text": "                return result;"
              },
              {
                "line": 1620,
                "text": "            }"
              },
              {
                "line": 1621,
                "text": "            ++totalLdpcPasses;"
              },
              {
                "line": 1622,
                "text": ""
              },
              {
                "line": 1623,
                "text": "            // Feedback refinement and second attempt, if enabled and budget"
              },
              {
                "line": 1624,
                "text": "            // allows."
              },
              {
                "line": 1625,
                "text": "            if (m_enableLdpcFeedback && totalLdpcPasses < m_maxLdpcPasses) {"
              },
              {
                "line": 1626,
                "text": "                std::array<float, N> llrRefined;"
              }
            ]
          }
        },
        {
          "function": "baselinejs8",
          "line": 1695,
          "signature": "void baselinejs8(int const ia, int const ib) {",
          "snippet": {
            "start_line": 1681,
            "end_line": 1709,
            "lines": [
              {
                "line": 1681,
                "text": "    // ill-conditioned; we're just looking for a low-order polynomial"
              },
              {
                "line": 1682,
                "text": "    // here, and a massively tall matrix isn't in general going to be"
              },
              {
                "line": 1683,
                "text": "    // helpful there. Additionally, the methodology seemed to be very"
              },
              {
                "line": 1684,
                "text": "    // susceptible to Runge's phenomenon."
              },
              {
                "line": 1685,
                "text": "    //"
              },
              {
                "line": 1686,
                "text": "    // This approach instead uses a number of Chebyshev nodes proportional"
              },
              {
                "line": 1687,
                "text": "    // to the polynomial degree, and we evaluate 2 kHz of `savg`, centered"
              },
              {
                "line": 1688,
                "text": "    // around 1.5 kHz, to determine the polynomial, figuring that that's"
              },
              {
                "line": 1689,
                "text": "    // going to be an optimal place to measure the 10% noise floor. We then"
              },
              {
                "line": 1690,
                "text": "    // map the [ia, ib] range to the domain of the polynomial to compute"
              },
              {
                "line": 1691,
                "text": "    // the baseline. Since `savg` would otherwise no longer be referenced"
              },
              {
                "line": 1692,
                "text": "    // beyond this function, we dispense with `sbase` and instead overwrite"
              },
              {
                "line": 1693,
                "text": "    // `savg` with the baseline."
              },
              {
                "line": 1694,
                "text": ""
              },
              {
                "line": 1695,
                "text": "    void baselinejs8(int const ia, int const ib) {"
              },
              {
                "line": 1696,
                "text": "        // Data referenced in savg is defined by the closed range [bmin, bmax]."
              },
              {
                "line": 1697,
                "text": "        // From this we can derive the size of the closed range and the number"
              },
              {
                "line": 1698,
                "text": "        // of points in each of the arms on either side of a node. All of these"
              },
              {
                "line": 1699,
                "text": "        // values can be computed at compile time."
              },
              {
                "line": 1700,
                "text": ""
              },
              {
                "line": 1701,
                "text": "        using boost::math::ccmath::round;"
              },
              {
                "line": 1702,
                "text": ""
              },
              {
                "line": 1703,
                "text": "        constexpr auto bmin ="
              },
              {
                "line": 1704,
                "text": "            static_cast<std::size_t>(round(BASELINE_MIN / Mode::DF));"
              },
              {
                "line": 1705,
                "text": "        constexpr auto bmax ="
              },
              {
                "line": 1706,
                "text": "            static_cast<std::size_t>(round(BASELINE_MAX / Mode::DF));"
              },
              {
                "line": 1707,
                "text": "        constexpr auto size = bmax - bmin + 1;"
              },
              {
                "line": 1708,
                "text": "        constexpr auto arm = size / (2 * BASELINE_NODES.size());"
              },
              {
                "line": 1709,
                "text": ""
              }
            ]
          }
        },
        {
          "function": "js8_downsample",
          "line": 1807,
          "signature": "void js8_downsample(float const f0) {",
          "snippet": {
            "start_line": 1793,
            "end_line": 1821,
            "lines": [
              {
                "line": 1793,
                "text": "        // a remainder."
              },
              {
                "line": 1794,
                "text": ""
              },
              {
                "line": 1795,
                "text": "        std::copy(dd.begin(), dd.end(), fftw_real);"
              },
              {
                "line": 1796,
                "text": "        std::fill(fftw_real + dd.size(), fftw_real + Mode::NDFFT1, 0.0f);"
              },
              {
                "line": 1797,
                "text": ""
              },
              {
                "line": 1798,
                "text": "        fftwf_execute(plans[Plan::BB]);"
              },
              {
                "line": 1799,
                "text": "    }"
              },
              {
                "line": 1800,
                "text": ""
              },
              {
                "line": 1801,
                "text": "    // This function extracts a narrow frequency band around the target"
              },
              {
                "line": 1802,
                "text": "    // frequency f0, applies tapering to reduce spectral artifacts, aligns the"
              },
              {
                "line": 1803,
                "text": "    // signal to the center frequency, performs an inverse FFT to convert the"
              },
              {
                "line": 1804,
                "text": "    // data back into the time domain, and normalizes the result for further"
              },
              {
                "line": 1805,
                "text": "    // processing in the JS8 decoding pipeline."
              },
              {
                "line": 1806,
                "text": ""
              },
              {
                "line": 1807,
                "text": "    void js8_downsample(float const f0) {"
              },
              {
                "line": 1808,
                "text": "        // Frequency band extraction; identifies a narrow frequency band around"
              },
              {
                "line": 1809,
                "text": "        // the target frequency (f0) based on a predefined range (8.5 baud above"
              },
              {
                "line": 1810,
                "text": "        // and 1.5 baud below). The indices of this range in the"
              },
              {
                "line": 1811,
                "text": "        // frequency-domain representation (ds_cx) are calculated (ib and it),"
              },
              {
                "line": 1812,
                "text": "        // and the relevant frequency-domain samples are extracted into cd0."
              },
              {
                "line": 1813,
                "text": ""
              },
              {
                "line": 1814,
                "text": "        constexpr float DF = 12000.0f / Mode::NDFFT1;"
              },
              {
                "line": 1815,
                "text": "        constexpr float BAUD = 12000.0f / Mode::NSPS;"
              },
              {
                "line": 1816,
                "text": ""
              },
              {
                "line": 1817,
                "text": "        float const ft = f0 + 8.5f * BAUD;"
              },
              {
                "line": 1818,
                "text": "        float const fb = f0 - 1.5f * BAUD;"
              },
              {
                "line": 1819,
                "text": "        int const i0 = static_cast<int>(std::round(f0 / DF));"
              },
              {
                "line": 1820,
                "text": "        int const it ="
              },
              {
                "line": 1821,
                "text": "            std::min(static_cast<int>(std::round(ft / DF)), Mode::NDFFT1 / 2);"
              }
            ]
          }
        },
        {
          "function": "syncjs8",
          "line": 1940,
          "signature": "std::vector<Sync> syncjs8(int nfa, int nfb) {",
          "snippet": {
            "start_line": 1926,
            "end_line": 1954,
            "lines": [
              {
                "line": 1926,
                "text": "    // 7.  Output:"
              },
              {
                "line": 1927,
                "text": "    //"
              },
              {
                "line": 1928,
                "text": "    //\t   - Returns a vector of the most promising signal candidates, sorted by"
              },
              {
                "line": 1929,
                "text": "    // their"
              },
              {
                "line": 1930,
                "text": "    //       synchronization power. It's expected that these will be re-sorted"
              },
              {
                "line": 1931,
                "text": "    //       by the caller into a desirable order, but synchronization power"
              },
              {
                "line": 1932,
                "text": "    //       order facilitates debugging this function."
              },
              {
                "line": 1933,
                "text": "    //"
              },
              {
                "line": 1934,
                "text": "    // Note: The Fortran version of this routine would normalize `s` at the end"
              },
              {
                "line": 1935,
                "text": "    // of this"
              },
              {
                "line": 1936,
                "text": "    //       function, but I'm unsure why; nothing beyond this function"
              },
              {
                "line": 1937,
                "text": "    //       references `s`, so it was effectively a somewhat expensive dead"
              },
              {
                "line": 1938,
                "text": "    //       store. It's been eliminated in this version."
              },
              {
                "line": 1939,
                "text": ""
              },
              {
                "line": 1940,
                "text": "    std::vector<Sync> syncjs8(int nfa, int nfb) {"
              },
              {
                "line": 1941,
                "text": "        // Compute symbol spectra"
              },
              {
                "line": 1942,
                "text": ""
              },
              {
                "line": 1943,
                "text": "        savg.fill(0.0f);"
              },
              {
                "line": 1944,
                "text": ""
              },
              {
                "line": 1945,
                "text": "        for (int j = 0; j < Mode::NHSYM; ++j) {"
              },
              {
                "line": 1946,
                "text": "            int const ia = j * Mode::NSTEP;"
              },
              {
                "line": 1947,
                "text": "            int const ib = ia + Mode::NFFT1;"
              },
              {
                "line": 1948,
                "text": ""
              },
              {
                "line": 1949,
                "text": "            if (ib > Mode::NMAX)"
              },
              {
                "line": 1950,
                "text": "                break;"
              },
              {
                "line": 1951,
                "text": ""
              },
              {
                "line": 1952,
                "text": "            std::transform(dd.begin() + ia, dd.begin() + ib, nuttal.begin(),"
              },
              {
                "line": 1953,
                "text": "                           reinterpret_cast<float *>(sd.data()),"
              },
              {
                "line": 1954,
                "text": "                           std::multiplies<float>{});"
              }
            ]
          }
        },
        {
          "function": "syncjs8d",
          "line": 2115,
          "signature": "float syncjs8d(int const i0, float const delf) {",
          "snippet": {
            "start_line": 2101,
            "end_line": 2129,
            "lines": [
              {
                "line": 2101,
                "text": "            // to the index begin in the loop increment condition."
              },
              {
                "line": 2102,
                "text": ""
              },
              {
                "line": 2103,
                "text": "            freqIndex.erase(freqIndex.lower_bound(it->freq - Mode::AZ),"
              },
              {
                "line": 2104,
                "text": "                            freqIndex.upper_bound(it->freq + Mode::AZ));"
              },
              {
                "line": 2105,
                "text": "        }"
              },
              {
                "line": 2106,
                "text": ""
              },
              {
                "line": 2107,
                "text": "        return candidates;"
              },
              {
                "line": 2108,
                "text": "    }"
              },
              {
                "line": 2109,
                "text": ""
              },
              {
                "line": 2110,
                "text": "    // Returns the total synchronization power, which is a measure of how well"
              },
              {
                "line": 2111,
                "text": "    // the signal aligns with the Costas sequence after accounting for the"
              },
              {
                "line": 2112,
                "text": "    // frequency adjustment. Used to identify the best alignment for further"
              },
              {
                "line": 2113,
                "text": "    // decoding."
              },
              {
                "line": 2114,
                "text": ""
              },
              {
                "line": 2115,
                "text": "    float syncjs8d(int const i0, float const delf) {"
              },
              {
                "line": 2116,
                "text": "        constexpr float BASE_DPHI = TAU * (1.0f / (12000.0f / Mode::NDOWN));"
              },
              {
                "line": 2117,
                "text": ""
              },
              {
                "line": 2118,
                "text": "        // If delta frequency is non-zero, compute the frequency"
              },
              {
                "line": 2119,
                "text": "        // adjustment array, otherwise, use what'll be an identity"
              },
              {
                "line": 2120,
                "text": "        // transfrom when multiplied."
              },
              {
                "line": 2121,
                "text": ""
              },
              {
                "line": 2122,
                "text": "        std::array<std::complex<float>, Mode::NDOWNSPS> freqAdjust;"
              },
              {
                "line": 2123,
                "text": ""
              },
              {
                "line": 2124,
                "text": "        if (delf != 0.0f) {"
              },
              {
                "line": 2125,
                "text": "            float const dphi = BASE_DPHI * delf;"
              },
              {
                "line": 2126,
                "text": "            float phi = 0.0f;"
              },
              {
                "line": 2127,
                "text": ""
              },
              {
                "line": 2128,
                "text": "            // std::fmod() is almost like Fortran's mod(), but not quite;"
              },
              {
                "line": 2129,
                "text": "            // Since delf can be negative, we must ensure that phi stays"
              }
            ]
          }
        },
        {
          "function": "makeDecodeEntry",
          "line": 2615,
          "signature": "DecodeEntry makeDecodeEntry(int shift, int &kpos, int &ksz) {",
          "snippet": {
            "start_line": 2601,
            "end_line": 2629,
            "lines": [
              {
                "line": 2601,
                "text": "            DecodeEntry(std::in_place_type_t<DecodeModeType>, int mode,"
              },
              {
                "line": 2602,
                "text": "                        int &kpos, int &ksz)"
              },
              {
                "line": 2603,
                "text": "                : decode(std::in_place_type<DecodeModeType>), mode(mode),"
              },
              {
                "line": 2604,
                "text": "                  kpos(kpos), ksz(ksz) {}"
              },
              {
                "line": 2605,
                "text": "        };"
              },
              {
                "line": 2606,
                "text": ""
              },
              {
                "line": 2607,
                "text": "        // Since a strategy can be neither moved nor copied, we must"
              },
              {
                "line": 2608,
                "text": "        // instantiate them in-place. Note that with the advent of the"
              },
              {
                "line": 2609,
                "text": "        // multi-decoder, mode identifiers became a bitset instead of"
              },
              {
                "line": 2610,
                "text": "        // integral values. The order defined here is the order that"
              },
              {
                "line": 2611,
                "text": "        // the decode loop will run in; we're matching the Fortran"
              },
              {
                "line": 2612,
                "text": "        // version here in terms of faster modes first."
              },
              {
                "line": 2613,
                "text": ""
              },
              {
                "line": 2614,
                "text": "        template <typename ModeType>"
              },
              {
                "line": 2615,
                "text": "        DecodeEntry makeDecodeEntry(int shift, int &kpos, int &ksz) {"
              },
              {
                "line": 2616,
                "text": "            return DecodeEntry(std::in_place_type<DecodeMode<ModeType>>,"
              },
              {
                "line": 2617,
                "text": "                               1 << shift, kpos, ksz);"
              },
              {
                "line": 2618,
                "text": "        }"
              },
              {
                "line": 2619,
                "text": ""
              },
              {
                "line": 2620,
                "text": "        std::array<DecodeEntry, 5> m_decodes = {"
              },
              {
                "line": 2621,
                "text": "            {makeDecodeEntry<ModeI>(4, m_data.params.kposI, m_data.params.kszI),"
              },
              {
                "line": 2622,
                "text": "             makeDecodeEntry<ModeE>(3, m_data.params.kposE, m_data.params.kszE),"
              },
              {
                "line": 2623,
                "text": "             makeDecodeEntry<ModeC>(2, m_data.params.kposC, m_data.params.kszC),"
              },
              {
                "line": 2624,
                "text": "             makeDecodeEntry<ModeB>(1, m_data.params.kposB, m_data.params.kszB),"
              },
              {
                "line": 2625,
                "text": "             makeDecodeEntry<ModeA>(0, m_data.params.kposA,"
              },
              {
                "line": 2626,
                "text": "                                    m_data.params.kszA)}};"
              },
              {
                "line": 2627,
                "text": ""
              },
              {
                "line": 2628,
                "text": "      public:"
              },
              {
                "line": 2629,
                "text": "        // Constructor"
              }
            ]
          }
        },
        {
          "function": "Impl",
          "line": 2631,
          "signature": "explicit Impl(struct dec_data &data) : m_data(data) {}",
          "snippet": {
            "start_line": 2617,
            "end_line": 2645,
            "lines": [
              {
                "line": 2617,
                "text": "                               1 << shift, kpos, ksz);"
              },
              {
                "line": 2618,
                "text": "        }"
              },
              {
                "line": 2619,
                "text": ""
              },
              {
                "line": 2620,
                "text": "        std::array<DecodeEntry, 5> m_decodes = {"
              },
              {
                "line": 2621,
                "text": "            {makeDecodeEntry<ModeI>(4, m_data.params.kposI, m_data.params.kszI),"
              },
              {
                "line": 2622,
                "text": "             makeDecodeEntry<ModeE>(3, m_data.params.kposE, m_data.params.kszE),"
              },
              {
                "line": 2623,
                "text": "             makeDecodeEntry<ModeC>(2, m_data.params.kposC, m_data.params.kszC),"
              },
              {
                "line": 2624,
                "text": "             makeDecodeEntry<ModeB>(1, m_data.params.kposB, m_data.params.kszB),"
              },
              {
                "line": 2625,
                "text": "             makeDecodeEntry<ModeA>(0, m_data.params.kposA,"
              },
              {
                "line": 2626,
                "text": "                                    m_data.params.kszA)}};"
              },
              {
                "line": 2627,
                "text": ""
              },
              {
                "line": 2628,
                "text": "      public:"
              },
              {
                "line": 2629,
                "text": "        // Constructor"
              },
              {
                "line": 2630,
                "text": ""
              },
              {
                "line": 2631,
                "text": "        explicit Impl(struct dec_data &data) : m_data(data) {}"
              },
              {
                "line": 2632,
                "text": ""
              },
              {
                "line": 2633,
                "text": "        // Execute a decoding pass, using the supplied event emitter to"
              },
              {
                "line": 2634,
                "text": "        // emit events as they occur."
              },
              {
                "line": 2635,
                "text": ""
              },
              {
                "line": 2636,
                "text": "        void operator()(::JS8::Event::Emitter emitEvent) {"
              },
              {
                "line": 2637,
                "text": "            // The multi-decoder can provide data for multiple modes at"
              },
              {
                "line": 2638,
                "text": "            // the same time; specific decodes to be performed for this"
              },
              {
                "line": 2639,
                "text": "            // pass are in the `nsubmodes` bitset."
              },
              {
                "line": 2640,
                "text": ""
              },
              {
                "line": 2641,
                "text": "            auto const set = m_data.params.nsubmodes;"
              },
              {
                "line": 2642,
                "text": "            std::size_t sum = 0;"
              },
              {
                "line": 2643,
                "text": ""
              },
              {
                "line": 2644,
                "text": "            // Let any interested parties know that we've started a run"
              },
              {
                "line": 2645,
                "text": "            // for the set of modes requested."
              }
            ]
          }
        }
      ],
      "keyword_snippets": [
        {
          "line": 11,
          "matches": [
            "whiten"
          ],
          "snippet": {
            "start_line": 5,
            "end_line": 17,
            "lines": [
              {
                "line": 5,
                "text": " * (C) 2025 Allan Bazinet <w6baz@arrl.net> - All Rights Reserved"
              },
              {
                "line": 6,
                "text": " */"
              },
              {
                "line": 7,
                "text": ""
              },
              {
                "line": 8,
                "text": "#include \"JS8.h\""
              },
              {
                "line": 9,
                "text": "#include \"JS8_Include/commons.h\""
              },
              {
                "line": 10,
                "text": "#include \"JS8_Mode/FrequencyTracker.h\""
              },
              {
                "line": 11,
                "text": "#include \"JS8_Mode/whitening_processor.h\""
              },
              {
                "line": 12,
                "text": "#include \"ldpc_feedback.h\""
              },
              {
                "line": 13,
                "text": "#include \"soft_combiner.h\""
              },
              {
                "line": 14,
                "text": ""
              },
              {
                "line": 15,
                "text": "#include <QDebug>"
              },
              {
                "line": 16,
                "text": "#include <QLoggingCategory>"
              },
              {
                "line": 17,
                "text": "#include <QtGlobal>"
              }
            ]
          }
        },
        {
          "line": 21,
          "matches": [
            "crc"
          ],
          "snippet": {
            "start_line": 15,
            "end_line": 27,
            "lines": [
              {
                "line": 15,
                "text": "#include <QDebug>"
              },
              {
                "line": 16,
                "text": "#include <QLoggingCategory>"
              },
              {
                "line": 17,
                "text": "#include <QtGlobal>"
              },
              {
                "line": 18,
                "text": ""
              },
              {
                "line": 19,
                "text": "#include <algorithm>"
              },
              {
                "line": 20,
                "text": "#include <atomic>"
              },
              {
                "line": 21,
                "text": "#include <boost/crc.hpp>"
              },
              {
                "line": 22,
                "text": "#include <boost/math/ccmath/round.hpp>"
              },
              {
                "line": 23,
                "text": "#include <boost/multi_index/key.hpp>"
              },
              {
                "line": 24,
                "text": "#include <boost/multi_index/ordered_index.hpp>"
              },
              {
                "line": 25,
                "text": "#include <boost/multi_index/ranked_index.hpp>"
              },
              {
                "line": 26,
                "text": "#include <boost/multi_index_container.hpp>"
              },
              {
                "line": 27,
                "text": "#include <chrono>"
              }
            ]
          }
        },
        {
          "line": 50,
          "matches": [
            "decode"
          ],
          "snippet": {
            "start_line": 44,
            "end_line": 56,
            "lines": [
              {
                "line": 44,
                "text": "#include <string_view>"
              },
              {
                "line": 45,
                "text": "#include <unordered_map>"
              },
              {
                "line": 46,
                "text": "#include <utility>"
              },
              {
                "line": 47,
                "text": "#include <vector>"
              },
              {
                "line": 48,
                "text": "#include <vendor/Eigen/Dense>"
              },
              {
                "line": 49,
                "text": ""
              },
              {
                "line": 50,
                "text": "Q_DECLARE_LOGGING_CATEGORY(decoder_js8);"
              },
              {
                "line": 51,
                "text": ""
              },
              {
                "line": 52,
                "text": "// A C++ conversion of the Fortran JS8 encoding and decoder function."
              },
              {
                "line": 53,
                "text": "// Some notes on the conversion:"
              },
              {
                "line": 54,
                "text": "//"
              },
              {
                "line": 55,
                "text": "//   1. Names of variables and functions as much as possible match those"
              },
              {
                "line": 56,
                "text": "//      of the Fortran routines, for ease in cross-referencing during the"
              }
            ]
          }
        },
        {
          "line": 52,
          "matches": [
            "decode"
          ],
          "snippet": {
            "start_line": 46,
            "end_line": 58,
            "lines": [
              {
                "line": 46,
                "text": "#include <utility>"
              },
              {
                "line": 47,
                "text": "#include <vector>"
              },
              {
                "line": 48,
                "text": "#include <vendor/Eigen/Dense>"
              },
              {
                "line": 49,
                "text": ""
              },
              {
                "line": 50,
                "text": "Q_DECLARE_LOGGING_CATEGORY(decoder_js8);"
              },
              {
                "line": 51,
                "text": ""
              },
              {
                "line": 52,
                "text": "// A C++ conversion of the Fortran JS8 encoding and decoder function."
              },
              {
                "line": 53,
                "text": "// Some notes on the conversion:"
              },
              {
                "line": 54,
                "text": "//"
              },
              {
                "line": 55,
                "text": "//   1. Names of variables and functions as much as possible match those"
              },
              {
                "line": 56,
                "text": "//      of the Fortran routines, for ease in cross-referencing during the"
              },
              {
                "line": 57,
                "text": "//      debug comparison phase of testing. You don't have to like them; I"
              },
              {
                "line": 58,
                "text": "//      don't like them either, frankly, but it's the reasonable approach"
              }
            ]
          }
        },
        {
          "line": 61,
          "matches": [
            "decode"
          ],
          "snippet": {
            "start_line": 55,
            "end_line": 67,
            "lines": [
              {
                "line": 55,
                "text": "//   1. Names of variables and functions as much as possible match those"
              },
              {
                "line": 56,
                "text": "//      of the Fortran routines, for ease in cross-referencing during the"
              },
              {
                "line": 57,
                "text": "//      debug comparison phase of testing. You don't have to like them; I"
              },
              {
                "line": 58,
                "text": "//      don't like them either, frankly, but it's the reasonable approach"
              },
              {
                "line": 59,
                "text": "//      to the problem as of this writing; we can make 'em pretty later."
              },
              {
                "line": 60,
                "text": "//"
              },
              {
                "line": 61,
                "text": "//   2. The BP decoder should be a faithful reproduction of the Fortran"
              },
              {
                "line": 62,
                "text": "//      version, albeit modified for the column-major vs. row-major"
              },
              {
                "line": 63,
                "text": "//      differences between the two languages."
              },
              {
                "line": 64,
                "text": "//"
              },
              {
                "line": 65,
                "text": "//   3. The OSD decoder is no longer used, and the depth is now fixed at"
              },
              {
                "line": 66,
                "text": "//      2, instead of being variable 1 to 4."
              },
              {
                "line": 67,
                "text": "//"
              }
            ]
          }
        },
        {
          "line": 83,
          "matches": [
            "decode"
          ],
          "snippet": {
            "start_line": 77,
            "end_line": 89,
            "lines": [
              {
                "line": 77,
                "text": "//      a number of Chebyshev nodes proportional to the desired polynomial"
              },
              {
                "line": 78,
                "text": "//      terms."
              },
              {
                "line": 79,
                "text": "//"
              },
              {
                "line": 80,
                "text": "//   6. The Fortran version normalized `s1` by dividing by the median in"
              },
              {
                "line": 81,
                "text": "//      js8dec(), but did so in a naive manner, not checking for a median"
              },
              {
                "line": 82,
                "text": "//      of zero. Testing indicates that the normalization does not appear"
              },
              {
                "line": 83,
                "text": "//      to contribute to decoder yield, so it's been removed."
              },
              {
                "line": 84,
                "text": "//"
              },
              {
                "line": 85,
                "text": "//   7. Translating array indices from the world of Fortran to that of C++"
              },
              {
                "line": 86,
                "text": "//      is no one's fun task. If you see things that aren't behaving as"
              },
              {
                "line": 87,
                "text": "//      expected, look at the Fortran code and compare the array indexing;"
              },
              {
                "line": 88,
                "text": "//      would not be surprised in the least to have off-by-one errors here."
              },
              {
                "line": 89,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 164,
          "matches": [
            "crc"
          ],
          "snippet": {
            "start_line": 158,
            "end_line": 170,
            "lines": [
              {
                "line": 158,
                "text": ""
              },
              {
                "line": 159,
                "text": "namespace {"
              },
              {
                "line": 160,
                "text": "/* COMMON PARAMETERS */"
              },
              {
                "line": 161,
                "text": ""
              },
              {
                "line": 162,
                "text": "// !Common"
              },
              {
                "line": 163,
                "text": "//"
              },
              {
                "line": 164,
                "text": "// parameter (KK=87)                     !Information bits (75 + CRC12)"
              },
              {
                "line": 165,
                "text": "// parameter (ND=58)                     !Data symbols"
              },
              {
                "line": 166,
                "text": "// parameter (NS=21)                     !Sync symbols (3 @ Costas 7x7)"
              },
              {
                "line": 167,
                "text": "// parameter (NN=NS+ND)                  !Total channel symbols (79)"
              },
              {
                "line": 168,
                "text": "// parameter (ASYNCMIN=1.5)              !Minimum Sync"
              },
              {
                "line": 169,
                "text": "// parameter (NFSRCH=5)                  !Search frequency range in Hz (i.e.,"
              },
              {
                "line": 170,
                "text": "// +/- 2.5 Hz) parameter (NMAXCAND=300)              !Maximum number of"
              }
            ]
          }
        },
        {
          "line": 166,
          "matches": [
            "symbol"
          ],
          "snippet": {
            "start_line": 160,
            "end_line": 172,
            "lines": [
              {
                "line": 160,
                "text": "/* COMMON PARAMETERS */"
              },
              {
                "line": 161,
                "text": ""
              },
              {
                "line": 162,
                "text": "// !Common"
              },
              {
                "line": 163,
                "text": "//"
              },
              {
                "line": 164,
                "text": "// parameter (KK=87)                     !Information bits (75 + CRC12)"
              },
              {
                "line": 165,
                "text": "// parameter (ND=58)                     !Data symbols"
              },
              {
                "line": 166,
                "text": "// parameter (NS=21)                     !Sync symbols (3 @ Costas 7x7)"
              },
              {
                "line": 167,
                "text": "// parameter (NN=NS+ND)                  !Total channel symbols (79)"
              },
              {
                "line": 168,
                "text": "// parameter (ASYNCMIN=1.5)              !Minimum Sync"
              },
              {
                "line": 169,
                "text": "// parameter (NFSRCH=5)                  !Search frequency range in Hz (i.e.,"
              },
              {
                "line": 170,
                "text": "// +/- 2.5 Hz) parameter (NMAXCAND=300)              !Maximum number of"
              },
              {
                "line": 171,
                "text": "// candidate signals"
              },
              {
                "line": 172,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 174,
          "matches": [
            "message",
            "crc"
          ],
          "snippet": {
            "start_line": 168,
            "end_line": 180,
            "lines": [
              {
                "line": 168,
                "text": "// parameter (ASYNCMIN=1.5)              !Minimum Sync"
              },
              {
                "line": 169,
                "text": "// parameter (NFSRCH=5)                  !Search frequency range in Hz (i.e.,"
              },
              {
                "line": 170,
                "text": "// +/- 2.5 Hz) parameter (NMAXCAND=300)              !Maximum number of"
              },
              {
                "line": 171,
                "text": "// candidate signals"
              },
              {
                "line": 172,
                "text": ""
              },
              {
                "line": 173,
                "text": "// Parameter\tValue\tDescription"
              },
              {
                "line": 174,
                "text": "// KK\t87\tNumber of information bits (75 message bits + 12 CRC bits)."
              },
              {
                "line": 175,
                "text": "// ND\t58\tNumber of data symbols in the JS8 transmission."
              },
              {
                "line": 176,
                "text": "// NS\t21\tNumber of synchronization symbols (3 Costas arrays of size 7)."
              },
              {
                "line": 177,
                "text": "// NN\t79\tTotal number of channel symbols (NN = NS + ND)."
              },
              {
                "line": 178,
                "text": "// ASYNCMIN\t1.5\tMinimum sync value for successful decoding."
              },
              {
                "line": 179,
                "text": "// NFSRCH\t5\tSearch frequency range in Hz (±2.5 Hz)."
              },
              {
                "line": 180,
                "text": "// NMAXCAND\t300\tMaximum number of candidate signals."
              }
            ]
          }
        },
        {
          "line": 176,
          "matches": [
            "symbol"
          ],
          "snippet": {
            "start_line": 170,
            "end_line": 182,
            "lines": [
              {
                "line": 170,
                "text": "// +/- 2.5 Hz) parameter (NMAXCAND=300)              !Maximum number of"
              },
              {
                "line": 171,
                "text": "// candidate signals"
              },
              {
                "line": 172,
                "text": ""
              },
              {
                "line": 173,
                "text": "// Parameter\tValue\tDescription"
              },
              {
                "line": 174,
                "text": "// KK\t87\tNumber of information bits (75 message bits + 12 CRC bits)."
              },
              {
                "line": 175,
                "text": "// ND\t58\tNumber of data symbols in the JS8 transmission."
              },
              {
                "line": 176,
                "text": "// NS\t21\tNumber of synchronization symbols (3 Costas arrays of size 7)."
              },
              {
                "line": 177,
                "text": "// NN\t79\tTotal number of channel symbols (NN = NS + ND)."
              },
              {
                "line": 178,
                "text": "// ASYNCMIN\t1.5\tMinimum sync value for successful decoding."
              },
              {
                "line": 179,
                "text": "// NFSRCH\t5\tSearch frequency range in Hz (±2.5 Hz)."
              },
              {
                "line": 180,
                "text": "// NMAXCAND\t300\tMaximum number of candidate signals."
              },
              {
                "line": 181,
                "text": ""
              },
              {
                "line": 182,
                "text": "constexpr int N = 174;           // Total bits"
              }
            ]
          }
        },
        {
          "line": 183,
          "matches": [
            "message"
          ],
          "snippet": {
            "start_line": 177,
            "end_line": 189,
            "lines": [
              {
                "line": 177,
                "text": "// NN\t79\tTotal number of channel symbols (NN = NS + ND)."
              },
              {
                "line": 178,
                "text": "// ASYNCMIN\t1.5\tMinimum sync value for successful decoding."
              },
              {
                "line": 179,
                "text": "// NFSRCH\t5\tSearch frequency range in Hz (±2.5 Hz)."
              },
              {
                "line": 180,
                "text": "// NMAXCAND\t300\tMaximum number of candidate signals."
              },
              {
                "line": 181,
                "text": ""
              },
              {
                "line": 182,
                "text": "constexpr int N = 174;           // Total bits"
              },
              {
                "line": 183,
                "text": "constexpr int K = 87;            // Message bits"
              },
              {
                "line": 184,
                "text": "constexpr int M = N - K;         // Check bits"
              },
              {
                "line": 185,
                "text": "constexpr int KK = 87;           // Information bits (75 + CRC12)"
              },
              {
                "line": 186,
                "text": "constexpr int ND = 58;           // Data symbols"
              },
              {
                "line": 187,
                "text": "constexpr int NS = 21;           // Sync symbols (3 @ Costas 7x7)"
              },
              {
                "line": 188,
                "text": "constexpr int NN = NS + ND;      // Total channel symbols (79)"
              },
              {
                "line": 189,
                "text": "constexpr float ASYNCMIN = 1.5f; // Minimum sync"
              }
            ]
          }
        },
        {
          "line": 186,
          "matches": [
            "symbol"
          ],
          "snippet": {
            "start_line": 180,
            "end_line": 192,
            "lines": [
              {
                "line": 180,
                "text": "// NMAXCAND\t300\tMaximum number of candidate signals."
              },
              {
                "line": 181,
                "text": ""
              },
              {
                "line": 182,
                "text": "constexpr int N = 174;           // Total bits"
              },
              {
                "line": 183,
                "text": "constexpr int K = 87;            // Message bits"
              },
              {
                "line": 184,
                "text": "constexpr int M = N - K;         // Check bits"
              },
              {
                "line": 185,
                "text": "constexpr int KK = 87;           // Information bits (75 + CRC12)"
              },
              {
                "line": 186,
                "text": "constexpr int ND = 58;           // Data symbols"
              },
              {
                "line": 187,
                "text": "constexpr int NS = 21;           // Sync symbols (3 @ Costas 7x7)"
              },
              {
                "line": 188,
                "text": "constexpr int NN = NS + ND;      // Total channel symbols (79)"
              },
              {
                "line": 189,
                "text": "constexpr float ASYNCMIN = 1.5f; // Minimum sync"
              },
              {
                "line": 190,
                "text": "constexpr int NFSRCH = 5; // Search frequency range in Hz (i.e., +/- 2.5 Hz)"
              },
              {
                "line": 191,
                "text": "constexpr std::size_t NMAXCAND = 300; // Maxiumum number of candidate signals"
              },
              {
                "line": 192,
                "text": "constexpr int NFILT = 1400;           // Filter length"
              }
            ]
          }
        },
        {
          "line": 207,
          "matches": [
            "symbol"
          ],
          "snippet": {
            "start_line": 201,
            "end_line": 213,
            "lines": [
              {
                "line": 201,
                "text": "// Key for the constants that follow:"
              },
              {
                "line": 202,
                "text": "//"
              },
              {
                "line": 203,
                "text": "//   NSUBMODE - ID of the submode"
              },
              {
                "line": 204,
                "text": "//   NCOSTAS  - Which JS8 Costas Arrays to use"
              },
              {
                "line": 205,
                "text": "//   NSPS     - Number of samples per second"
              },
              {
                "line": 206,
                "text": "//   NTXDUR   - Duration of the transmission in seconds."
              },
              {
                "line": 207,
                "text": "//   NDOWNSPS - Number of samples per symbol after downsampling."
              },
              {
                "line": 208,
                "text": "//   NDD      - Parameter used in waveform tapering and related calculations."
              },
              {
                "line": 209,
                "text": "//   XXX JZ       - Range of symbol offsets considered during decoding. ASTART"
              },
              {
                "line": 210,
                "text": "//   - Start delay in seconds for decoding. BASESUB  - XXX NMAX     - Samples in"
              },
              {
                "line": 211,
                "text": "//   input wave NSTEP    - Rough time-sync step size NHSYM    - Number of symbol"
              },
              {
                "line": 212,
                "text": "//   spectra (1/4-sym steps) NDOW     - Downsample factor to 32 samples per"
              },
              {
                "line": 213,
                "text": "//   symbol NQSYMBOL - Downsample factor of a quarter symbol"
              }
            ]
          }
        },
        {
          "line": 211,
          "matches": [
            "symbol"
          ],
          "snippet": {
            "start_line": 205,
            "end_line": 217,
            "lines": [
              {
                "line": 205,
                "text": "//   NSPS     - Number of samples per second"
              },
              {
                "line": 206,
                "text": "//   NTXDUR   - Duration of the transmission in seconds."
              },
              {
                "line": 207,
                "text": "//   NDOWNSPS - Number of samples per symbol after downsampling."
              },
              {
                "line": 208,
                "text": "//   NDD      - Parameter used in waveform tapering and related calculations."
              },
              {
                "line": 209,
                "text": "//   XXX JZ       - Range of symbol offsets considered during decoding. ASTART"
              },
              {
                "line": 210,
                "text": "//   - Start delay in seconds for decoding. BASESUB  - XXX NMAX     - Samples in"
              },
              {
                "line": 211,
                "text": "//   input wave NSTEP    - Rough time-sync step size NHSYM    - Number of symbol"
              },
              {
                "line": 212,
                "text": "//   spectra (1/4-sym steps) NDOW     - Downsample factor to 32 samples per"
              },
              {
                "line": 213,
                "text": "//   symbol NQSYMBOL - Downsample factor of a quarter symbol"
              },
              {
                "line": 214,
                "text": ""
              },
              {
                "line": 215,
                "text": "/* A MODE DECODER */"
              },
              {
                "line": 216,
                "text": ""
              },
              {
                "line": 217,
                "text": "struct ModeA {"
              }
            ]
          }
        },
        {
          "line": 221,
          "matches": [
            "symbol"
          ],
          "snippet": {
            "start_line": 215,
            "end_line": 227,
            "lines": [
              {
                "line": 215,
                "text": "/* A MODE DECODER */"
              },
              {
                "line": 216,
                "text": ""
              },
              {
                "line": 217,
                "text": "struct ModeA {"
              },
              {
                "line": 218,
                "text": "    // Static constants"
              },
              {
                "line": 219,
                "text": "    inline static constexpr int NSUBMODE = 0;"
              },
              {
                "line": 220,
                "text": "    inline static constexpr auto NCOSTAS = JS8::Costas::Type::ORIGINAL;"
              },
              {
                "line": 221,
                "text": "    inline static constexpr int NSPS = JS8A_SYMBOL_SAMPLES;"
              },
              {
                "line": 222,
                "text": "    inline static constexpr int NTXDUR = JS8A_TX_SECONDS;"
              },
              {
                "line": 223,
                "text": "    inline static constexpr int NDOWNSPS = 32;"
              },
              {
                "line": 224,
                "text": "    inline static constexpr int NDD = 100;"
              },
              {
                "line": 225,
                "text": "    inline static constexpr int JZ = 62;"
              },
              {
                "line": 226,
                "text": "    inline static constexpr float ASTART = 0.5f;"
              },
              {
                "line": 227,
                "text": "    inline static constexpr float BASESUB = 40.0f;"
              }
            ]
          }
        },
        {
          "line": 236,
          "matches": [
            "symbol"
          ],
          "snippet": {
            "start_line": 230,
            "end_line": 242,
            "lines": [
              {
                "line": 230,
                "text": "    inline static constexpr float AZ = (12000.0f / NSPS) * 0.64f;"
              },
              {
                "line": 231,
                "text": "    inline static constexpr int NMAX = NTXDUR * JS8_RX_SAMPLE_RATE;"
              },
              {
                "line": 232,
                "text": "    inline static constexpr int NFFT1 = NSPS * NFOS;"
              },
              {
                "line": 233,
                "text": "    inline static constexpr int NSTEP = NSPS / NSSY;"
              },
              {
                "line": 234,
                "text": "    inline static constexpr int NHSYM = NMAX / NSTEP - 3;"
              },
              {
                "line": 235,
                "text": "    inline static constexpr int NDOWN = NSPS / NDOWNSPS;"
              },
              {
                "line": 236,
                "text": "    inline static constexpr int NQSYMBOL = NDOWNSPS / 4;"
              },
              {
                "line": 237,
                "text": "    inline static constexpr int NDFFT1 = NSPS * NDD;"
              },
              {
                "line": 238,
                "text": "    inline static constexpr int NDFFT2 = NDFFT1 / NDOWN;"
              },
              {
                "line": 239,
                "text": "    inline static constexpr int NP2 = NN * NDOWNSPS;"
              },
              {
                "line": 240,
                "text": "    inline static constexpr float TSTEP = NSTEP / 12000.0f;"
              },
              {
                "line": 241,
                "text": "    inline static constexpr int JSTRT = ASTART / TSTEP;"
              },
              {
                "line": 242,
                "text": "    inline static constexpr float DF = 12000.0f / NFFT1;"
              }
            ]
          }
        },
        {
          "line": 245,
          "matches": [
            "decode"
          ],
          "snippet": {
            "start_line": 239,
            "end_line": 251,
            "lines": [
              {
                "line": 239,
                "text": "    inline static constexpr int NP2 = NN * NDOWNSPS;"
              },
              {
                "line": 240,
                "text": "    inline static constexpr float TSTEP = NSTEP / 12000.0f;"
              },
              {
                "line": 241,
                "text": "    inline static constexpr int JSTRT = ASTART / TSTEP;"
              },
              {
                "line": 242,
                "text": "    inline static constexpr float DF = 12000.0f / NFFT1;"
              },
              {
                "line": 243,
                "text": "};"
              },
              {
                "line": 244,
                "text": ""
              },
              {
                "line": 245,
                "text": "/* B MODE DECODER */"
              },
              {
                "line": 246,
                "text": ""
              },
              {
                "line": 247,
                "text": "struct ModeB {"
              },
              {
                "line": 248,
                "text": "    // Static constants"
              },
              {
                "line": 249,
                "text": "    inline static constexpr int NSUBMODE = 1;"
              },
              {
                "line": 250,
                "text": "    inline static constexpr auto NCOSTAS = JS8::Costas::Type::MODIFIED;"
              },
              {
                "line": 251,
                "text": "    inline static constexpr int NSPS = JS8B_SYMBOL_SAMPLES;"
              }
            ]
          }
        },
        {
          "line": 251,
          "matches": [
            "symbol"
          ],
          "snippet": {
            "start_line": 245,
            "end_line": 257,
            "lines": [
              {
                "line": 245,
                "text": "/* B MODE DECODER */"
              },
              {
                "line": 246,
                "text": ""
              },
              {
                "line": 247,
                "text": "struct ModeB {"
              },
              {
                "line": 248,
                "text": "    // Static constants"
              },
              {
                "line": 249,
                "text": "    inline static constexpr int NSUBMODE = 1;"
              },
              {
                "line": 250,
                "text": "    inline static constexpr auto NCOSTAS = JS8::Costas::Type::MODIFIED;"
              },
              {
                "line": 251,
                "text": "    inline static constexpr int NSPS = JS8B_SYMBOL_SAMPLES;"
              },
              {
                "line": 252,
                "text": "    inline static constexpr int NTXDUR = JS8B_TX_SECONDS;"
              },
              {
                "line": 253,
                "text": "    inline static constexpr int NDOWNSPS = 20;"
              },
              {
                "line": 254,
                "text": "    inline static constexpr int NDD = 100;"
              },
              {
                "line": 255,
                "text": "    inline static constexpr int JZ = 144;"
              },
              {
                "line": 256,
                "text": "    inline static constexpr float ASTART = 0.2f;"
              },
              {
                "line": 257,
                "text": "    inline static constexpr float BASESUB = 39.0f;"
              }
            ]
          }
        },
        {
          "line": 266,
          "matches": [
            "symbol"
          ],
          "snippet": {
            "start_line": 260,
            "end_line": 272,
            "lines": [
              {
                "line": 260,
                "text": "    inline static constexpr float AZ = (12000.0f / NSPS) * 0.8f;"
              },
              {
                "line": 261,
                "text": "    inline static constexpr int NMAX = NTXDUR * JS8_RX_SAMPLE_RATE;"
              },
              {
                "line": 262,
                "text": "    inline static constexpr int NFFT1 = NSPS * NFOS;"
              },
              {
                "line": 263,
                "text": "    inline static constexpr int NSTEP = NSPS / NSSY;"
              },
              {
                "line": 264,
                "text": "    inline static constexpr int NHSYM = NMAX / NSTEP - 3;"
              },
              {
                "line": 265,
                "text": "    inline static constexpr int NDOWN = NSPS / NDOWNSPS;"
              },
              {
                "line": 266,
                "text": "    inline static constexpr int NQSYMBOL = NDOWNSPS / 4;"
              },
              {
                "line": 267,
                "text": "    inline static constexpr int NDFFT1 = NSPS * NDD;"
              },
              {
                "line": 268,
                "text": "    inline static constexpr int NDFFT2 = NDFFT1 / NDOWN;"
              },
              {
                "line": 269,
                "text": "    inline static constexpr int NP2 = NN * NDOWNSPS;"
              },
              {
                "line": 270,
                "text": "    inline static constexpr float TSTEP = NSTEP / 12000.0f;"
              },
              {
                "line": 271,
                "text": "    inline static constexpr int JSTRT = ASTART / TSTEP;"
              },
              {
                "line": 272,
                "text": "    inline static constexpr float DF = 12000.0f / NFFT1;"
              }
            ]
          }
        },
        {
          "line": 275,
          "matches": [
            "decode"
          ],
          "snippet": {
            "start_line": 269,
            "end_line": 281,
            "lines": [
              {
                "line": 269,
                "text": "    inline static constexpr int NP2 = NN * NDOWNSPS;"
              },
              {
                "line": 270,
                "text": "    inline static constexpr float TSTEP = NSTEP / 12000.0f;"
              },
              {
                "line": 271,
                "text": "    inline static constexpr int JSTRT = ASTART / TSTEP;"
              },
              {
                "line": 272,
                "text": "    inline static constexpr float DF = 12000.0f / NFFT1;"
              },
              {
                "line": 273,
                "text": "};"
              },
              {
                "line": 274,
                "text": ""
              },
              {
                "line": 275,
                "text": "/* C MODE DECODER */"
              },
              {
                "line": 276,
                "text": ""
              },
              {
                "line": 277,
                "text": "struct ModeC {"
              },
              {
                "line": 278,
                "text": "    // Static constants"
              },
              {
                "line": 279,
                "text": "    inline static constexpr int NSUBMODE = 2;"
              },
              {
                "line": 280,
                "text": "    inline static constexpr auto NCOSTAS = JS8::Costas::Type::MODIFIED;"
              },
              {
                "line": 281,
                "text": "    inline static constexpr int NSPS = JS8C_SYMBOL_SAMPLES;"
              }
            ]
          }
        },
        {
          "line": 281,
          "matches": [
            "symbol"
          ],
          "snippet": {
            "start_line": 275,
            "end_line": 287,
            "lines": [
              {
                "line": 275,
                "text": "/* C MODE DECODER */"
              },
              {
                "line": 276,
                "text": ""
              },
              {
                "line": 277,
                "text": "struct ModeC {"
              },
              {
                "line": 278,
                "text": "    // Static constants"
              },
              {
                "line": 279,
                "text": "    inline static constexpr int NSUBMODE = 2;"
              },
              {
                "line": 280,
                "text": "    inline static constexpr auto NCOSTAS = JS8::Costas::Type::MODIFIED;"
              },
              {
                "line": 281,
                "text": "    inline static constexpr int NSPS = JS8C_SYMBOL_SAMPLES;"
              },
              {
                "line": 282,
                "text": "    inline static constexpr int NTXDUR = JS8C_TX_SECONDS;"
              },
              {
                "line": 283,
                "text": "    inline static constexpr int NDOWNSPS = 12;"
              },
              {
                "line": 284,
                "text": "    inline static constexpr int NDD = 120;"
              },
              {
                "line": 285,
                "text": "    inline static constexpr int JZ = 172;"
              },
              {
                "line": 286,
                "text": "    inline static constexpr float ASTART = 0.1f;"
              },
              {
                "line": 287,
                "text": "    inline static constexpr float BASESUB = 38.0f;"
              }
            ]
          }
        },
        {
          "line": 296,
          "matches": [
            "symbol"
          ],
          "snippet": {
            "start_line": 290,
            "end_line": 302,
            "lines": [
              {
                "line": 290,
                "text": "    inline static constexpr float AZ = (12000.0f / NSPS) * 0.6f;"
              },
              {
                "line": 291,
                "text": "    inline static constexpr int NMAX = NTXDUR * JS8_RX_SAMPLE_RATE;"
              },
              {
                "line": 292,
                "text": "    inline static constexpr int NFFT1 = NSPS * NFOS;"
              },
              {
                "line": 293,
                "text": "    inline static constexpr int NSTEP = NSPS / NSSY;"
              },
              {
                "line": 294,
                "text": "    inline static constexpr int NHSYM = NMAX / NSTEP - 3;"
              },
              {
                "line": 295,
                "text": "    inline static constexpr int NDOWN = NSPS / NDOWNSPS;"
              },
              {
                "line": 296,
                "text": "    inline static constexpr int NQSYMBOL = NDOWNSPS / 4;"
              },
              {
                "line": 297,
                "text": "    inline static constexpr int NDFFT1 = NSPS * NDD;"
              },
              {
                "line": 298,
                "text": "    inline static constexpr int NDFFT2 = NDFFT1 / NDOWN;"
              },
              {
                "line": 299,
                "text": "    inline static constexpr int NP2 = NN * NDOWNSPS;"
              },
              {
                "line": 300,
                "text": "    inline static constexpr float TSTEP = NSTEP / 12000.0f;"
              },
              {
                "line": 301,
                "text": "    inline static constexpr int JSTRT = ASTART / TSTEP;"
              },
              {
                "line": 302,
                "text": "    inline static constexpr float DF = 12000.0f / NFFT1;"
              }
            ]
          }
        }
      ]
    },
    {
      "path": "JS8_Mode/Decoder.cpp",
      "exists": true,
      "bytes": 3646,
      "sha256": "9662f0bb9c739aad5b4e3031f2c4707b9c5f15746ae1739830c78fbbcf1d66d1",
      "line_count": 139,
      "phase_hits": {
        "timing_submode": 0,
        "symbol_to_soft_bits": 0,
        "bit_order_interleaver": 0,
        "whitening_erasure": 0,
        "ldpc_decode": 0,
        "message91_crc_text": 0
      },
      "function_blocks": [
        {
          "function": "Decoder::lock",
          "line": 24,
          "signature": "void Decoder::lock() {",
          "snippet": {
            "start_line": 10,
            "end_line": 38,
            "lines": [
              {
                "line": 10,
                "text": "#include <QLoggingCategory>"
              },
              {
                "line": 11,
                "text": "#include <QTimer>"
              },
              {
                "line": 12,
                "text": ""
              },
              {
                "line": 13,
                "text": "Q_DECLARE_LOGGING_CATEGORY(decoder_js8)"
              },
              {
                "line": 14,
                "text": ""
              },
              {
                "line": 15,
                "text": "Do not let youself be confused"
              },
              {
                "line": 16,
                "text": "    : This source file does not presently take part in the build."
              },
              {
                "line": 17,
                "text": ""
              },
              {
                "line": 18,
                "text": "      Decoder::Decoder(QObject * parent)"
              },
              {
                "line": 19,
                "text": "    : QObject(parent) {}"
              },
              {
                "line": 20,
                "text": ""
              },
              {
                "line": 21,
                "text": "Decoder::~Decoder() {}"
              },
              {
                "line": 22,
                "text": ""
              },
              {
                "line": 23,
                "text": "//"
              },
              {
                "line": 24,
                "text": "void Decoder::lock() {"
              },
              {
                "line": 25,
                "text": "    // NOOP"
              },
              {
                "line": 26,
                "text": "}"
              },
              {
                "line": 27,
                "text": ""
              },
              {
                "line": 28,
                "text": "//"
              },
              {
                "line": 29,
                "text": "void Decoder::unlock() {"
              },
              {
                "line": 30,
                "text": "    // NOOP"
              },
              {
                "line": 31,
                "text": "}"
              },
              {
                "line": 32,
                "text": ""
              },
              {
                "line": 33,
                "text": "//"
              },
              {
                "line": 34,
                "text": "Worker *Decoder::createWorker() {"
              },
              {
                "line": 35,
                "text": "    auto worker = new Worker();"
              },
              {
                "line": 36,
                "text": "    worker->moveToThread(&m_thread);"
              },
              {
                "line": 37,
                "text": "    connect(&m_thread, &QThread::finished, worker, &QObject::deleteLater);"
              },
              {
                "line": 38,
                "text": "    connect(this, &Decoder::startWorker, worker, &Worker::start);"
              }
            ]
          }
        },
        {
          "function": "Decoder::unlock",
          "line": 29,
          "signature": "void Decoder::unlock() {",
          "snippet": {
            "start_line": 15,
            "end_line": 43,
            "lines": [
              {
                "line": 15,
                "text": "Do not let youself be confused"
              },
              {
                "line": 16,
                "text": "    : This source file does not presently take part in the build."
              },
              {
                "line": 17,
                "text": ""
              },
              {
                "line": 18,
                "text": "      Decoder::Decoder(QObject * parent)"
              },
              {
                "line": 19,
                "text": "    : QObject(parent) {}"
              },
              {
                "line": 20,
                "text": ""
              },
              {
                "line": 21,
                "text": "Decoder::~Decoder() {}"
              },
              {
                "line": 22,
                "text": ""
              },
              {
                "line": 23,
                "text": "//"
              },
              {
                "line": 24,
                "text": "void Decoder::lock() {"
              },
              {
                "line": 25,
                "text": "    // NOOP"
              },
              {
                "line": 26,
                "text": "}"
              },
              {
                "line": 27,
                "text": ""
              },
              {
                "line": 28,
                "text": "//"
              },
              {
                "line": 29,
                "text": "void Decoder::unlock() {"
              },
              {
                "line": 30,
                "text": "    // NOOP"
              },
              {
                "line": 31,
                "text": "}"
              },
              {
                "line": 32,
                "text": ""
              },
              {
                "line": 33,
                "text": "//"
              },
              {
                "line": 34,
                "text": "Worker *Decoder::createWorker() {"
              },
              {
                "line": 35,
                "text": "    auto worker = new Worker();"
              },
              {
                "line": 36,
                "text": "    worker->moveToThread(&m_thread);"
              },
              {
                "line": 37,
                "text": "    connect(&m_thread, &QThread::finished, worker, &QObject::deleteLater);"
              },
              {
                "line": 38,
                "text": "    connect(this, &Decoder::startWorker, worker, &Worker::start);"
              },
              {
                "line": 39,
                "text": "    connect(this, &Decoder::quitWorker, worker, &Worker::quit);"
              },
              {
                "line": 40,
                "text": "    connect(worker, &Worker::ready, this, &Decoder::processReady);"
              },
              {
                "line": 41,
                "text": "    connect(worker, &Worker::error, this, &Decoder::processError);"
              },
              {
                "line": 42,
                "text": "    connect(worker, &Worker::finished, this, &Decoder::processFinished);"
              },
              {
                "line": 43,
                "text": "    return worker;"
              }
            ]
          }
        },
        {
          "function": "Decoder::start",
          "line": 47,
          "signature": "void Decoder::start(QThread::Priority priority) { m_thread.start(priority); }",
          "snippet": {
            "start_line": 33,
            "end_line": 61,
            "lines": [
              {
                "line": 33,
                "text": "//"
              },
              {
                "line": 34,
                "text": "Worker *Decoder::createWorker() {"
              },
              {
                "line": 35,
                "text": "    auto worker = new Worker();"
              },
              {
                "line": 36,
                "text": "    worker->moveToThread(&m_thread);"
              },
              {
                "line": 37,
                "text": "    connect(&m_thread, &QThread::finished, worker, &QObject::deleteLater);"
              },
              {
                "line": 38,
                "text": "    connect(this, &Decoder::startWorker, worker, &Worker::start);"
              },
              {
                "line": 39,
                "text": "    connect(this, &Decoder::quitWorker, worker, &Worker::quit);"
              },
              {
                "line": 40,
                "text": "    connect(worker, &Worker::ready, this, &Decoder::processReady);"
              },
              {
                "line": 41,
                "text": "    connect(worker, &Worker::error, this, &Decoder::processError);"
              },
              {
                "line": 42,
                "text": "    connect(worker, &Worker::finished, this, &Decoder::processFinished);"
              },
              {
                "line": 43,
                "text": "    return worker;"
              },
              {
                "line": 44,
                "text": "}"
              },
              {
                "line": 45,
                "text": ""
              },
              {
                "line": 46,
                "text": "//"
              },
              {
                "line": 47,
                "text": "void Decoder::start(QThread::Priority priority) { m_thread.start(priority); }"
              },
              {
                "line": 48,
                "text": ""
              },
              {
                "line": 49,
                "text": "//"
              },
              {
                "line": 50,
                "text": "void Decoder::quit() { m_thread.quit(); }"
              },
              {
                "line": 51,
                "text": ""
              },
              {
                "line": 52,
                "text": "//"
              },
              {
                "line": 53,
                "text": "bool Decoder::wait() { return m_thread.wait(); }"
              },
              {
                "line": 54,
                "text": ""
              },
              {
                "line": 55,
                "text": "//"
              },
              {
                "line": 56,
                "text": "void Decoder::processStart(QString path, QStringList args) {"
              },
              {
                "line": 57,
                "text": "    if (m_worker.isNull()) {"
              },
              {
                "line": 58,
                "text": "        m_worker = createWorker();"
              },
              {
                "line": 59,
                "text": "    }"
              },
              {
                "line": 60,
                "text": ""
              },
              {
                "line": 61,
                "text": "    emit startWorker(path, args);"
              }
            ]
          }
        },
        {
          "function": "Decoder::quit",
          "line": 50,
          "signature": "void Decoder::quit() { m_thread.quit(); }",
          "snippet": {
            "start_line": 36,
            "end_line": 64,
            "lines": [
              {
                "line": 36,
                "text": "    worker->moveToThread(&m_thread);"
              },
              {
                "line": 37,
                "text": "    connect(&m_thread, &QThread::finished, worker, &QObject::deleteLater);"
              },
              {
                "line": 38,
                "text": "    connect(this, &Decoder::startWorker, worker, &Worker::start);"
              },
              {
                "line": 39,
                "text": "    connect(this, &Decoder::quitWorker, worker, &Worker::quit);"
              },
              {
                "line": 40,
                "text": "    connect(worker, &Worker::ready, this, &Decoder::processReady);"
              },
              {
                "line": 41,
                "text": "    connect(worker, &Worker::error, this, &Decoder::processError);"
              },
              {
                "line": 42,
                "text": "    connect(worker, &Worker::finished, this, &Decoder::processFinished);"
              },
              {
                "line": 43,
                "text": "    return worker;"
              },
              {
                "line": 44,
                "text": "}"
              },
              {
                "line": 45,
                "text": ""
              },
              {
                "line": 46,
                "text": "//"
              },
              {
                "line": 47,
                "text": "void Decoder::start(QThread::Priority priority) { m_thread.start(priority); }"
              },
              {
                "line": 48,
                "text": ""
              },
              {
                "line": 49,
                "text": "//"
              },
              {
                "line": 50,
                "text": "void Decoder::quit() { m_thread.quit(); }"
              },
              {
                "line": 51,
                "text": ""
              },
              {
                "line": 52,
                "text": "//"
              },
              {
                "line": 53,
                "text": "bool Decoder::wait() { return m_thread.wait(); }"
              },
              {
                "line": 54,
                "text": ""
              },
              {
                "line": 55,
                "text": "//"
              },
              {
                "line": 56,
                "text": "void Decoder::processStart(QString path, QStringList args) {"
              },
              {
                "line": 57,
                "text": "    if (m_worker.isNull()) {"
              },
              {
                "line": 58,
                "text": "        m_worker = createWorker();"
              },
              {
                "line": 59,
                "text": "    }"
              },
              {
                "line": 60,
                "text": ""
              },
              {
                "line": 61,
                "text": "    emit startWorker(path, args);"
              },
              {
                "line": 62,
                "text": "}"
              },
              {
                "line": 63,
                "text": ""
              },
              {
                "line": 64,
                "text": "//"
              }
            ]
          }
        },
        {
          "function": "Decoder::wait",
          "line": 53,
          "signature": "bool Decoder::wait() { return m_thread.wait(); }",
          "snippet": {
            "start_line": 39,
            "end_line": 67,
            "lines": [
              {
                "line": 39,
                "text": "    connect(this, &Decoder::quitWorker, worker, &Worker::quit);"
              },
              {
                "line": 40,
                "text": "    connect(worker, &Worker::ready, this, &Decoder::processReady);"
              },
              {
                "line": 41,
                "text": "    connect(worker, &Worker::error, this, &Decoder::processError);"
              },
              {
                "line": 42,
                "text": "    connect(worker, &Worker::finished, this, &Decoder::processFinished);"
              },
              {
                "line": 43,
                "text": "    return worker;"
              },
              {
                "line": 44,
                "text": "}"
              },
              {
                "line": 45,
                "text": ""
              },
              {
                "line": 46,
                "text": "//"
              },
              {
                "line": 47,
                "text": "void Decoder::start(QThread::Priority priority) { m_thread.start(priority); }"
              },
              {
                "line": 48,
                "text": ""
              },
              {
                "line": 49,
                "text": "//"
              },
              {
                "line": 50,
                "text": "void Decoder::quit() { m_thread.quit(); }"
              },
              {
                "line": 51,
                "text": ""
              },
              {
                "line": 52,
                "text": "//"
              },
              {
                "line": 53,
                "text": "bool Decoder::wait() { return m_thread.wait(); }"
              },
              {
                "line": 54,
                "text": ""
              },
              {
                "line": 55,
                "text": "//"
              },
              {
                "line": 56,
                "text": "void Decoder::processStart(QString path, QStringList args) {"
              },
              {
                "line": 57,
                "text": "    if (m_worker.isNull()) {"
              },
              {
                "line": 58,
                "text": "        m_worker = createWorker();"
              },
              {
                "line": 59,
                "text": "    }"
              },
              {
                "line": 60,
                "text": ""
              },
              {
                "line": 61,
                "text": "    emit startWorker(path, args);"
              },
              {
                "line": 62,
                "text": "}"
              },
              {
                "line": 63,
                "text": ""
              },
              {
                "line": 64,
                "text": "//"
              },
              {
                "line": 65,
                "text": "void Decoder::processReady(QByteArray t) { emit ready(t); }"
              },
              {
                "line": 66,
                "text": ""
              },
              {
                "line": 67,
                "text": "//"
              }
            ]
          }
        },
        {
          "function": "Decoder::processStart",
          "line": 56,
          "signature": "void Decoder::processStart(QString path, QStringList args) {",
          "snippet": {
            "start_line": 42,
            "end_line": 70,
            "lines": [
              {
                "line": 42,
                "text": "    connect(worker, &Worker::finished, this, &Decoder::processFinished);"
              },
              {
                "line": 43,
                "text": "    return worker;"
              },
              {
                "line": 44,
                "text": "}"
              },
              {
                "line": 45,
                "text": ""
              },
              {
                "line": 46,
                "text": "//"
              },
              {
                "line": 47,
                "text": "void Decoder::start(QThread::Priority priority) { m_thread.start(priority); }"
              },
              {
                "line": 48,
                "text": ""
              },
              {
                "line": 49,
                "text": "//"
              },
              {
                "line": 50,
                "text": "void Decoder::quit() { m_thread.quit(); }"
              },
              {
                "line": 51,
                "text": ""
              },
              {
                "line": 52,
                "text": "//"
              },
              {
                "line": 53,
                "text": "bool Decoder::wait() { return m_thread.wait(); }"
              },
              {
                "line": 54,
                "text": ""
              },
              {
                "line": 55,
                "text": "//"
              },
              {
                "line": 56,
                "text": "void Decoder::processStart(QString path, QStringList args) {"
              },
              {
                "line": 57,
                "text": "    if (m_worker.isNull()) {"
              },
              {
                "line": 58,
                "text": "        m_worker = createWorker();"
              },
              {
                "line": 59,
                "text": "    }"
              },
              {
                "line": 60,
                "text": ""
              },
              {
                "line": 61,
                "text": "    emit startWorker(path, args);"
              },
              {
                "line": 62,
                "text": "}"
              },
              {
                "line": 63,
                "text": ""
              },
              {
                "line": 64,
                "text": "//"
              },
              {
                "line": 65,
                "text": "void Decoder::processReady(QByteArray t) { emit ready(t); }"
              },
              {
                "line": 66,
                "text": ""
              },
              {
                "line": 67,
                "text": "//"
              },
              {
                "line": 68,
                "text": "void Decoder::processQuit() { emit quitWorker(); }"
              },
              {
                "line": 69,
                "text": ""
              },
              {
                "line": 70,
                "text": "//"
              }
            ]
          }
        },
        {
          "function": "Decoder::processReady",
          "line": 65,
          "signature": "void Decoder::processReady(QByteArray t) { emit ready(t); }",
          "snippet": {
            "start_line": 51,
            "end_line": 79,
            "lines": [
              {
                "line": 51,
                "text": ""
              },
              {
                "line": 52,
                "text": "//"
              },
              {
                "line": 53,
                "text": "bool Decoder::wait() { return m_thread.wait(); }"
              },
              {
                "line": 54,
                "text": ""
              },
              {
                "line": 55,
                "text": "//"
              },
              {
                "line": 56,
                "text": "void Decoder::processStart(QString path, QStringList args) {"
              },
              {
                "line": 57,
                "text": "    if (m_worker.isNull()) {"
              },
              {
                "line": 58,
                "text": "        m_worker = createWorker();"
              },
              {
                "line": 59,
                "text": "    }"
              },
              {
                "line": 60,
                "text": ""
              },
              {
                "line": 61,
                "text": "    emit startWorker(path, args);"
              },
              {
                "line": 62,
                "text": "}"
              },
              {
                "line": 63,
                "text": ""
              },
              {
                "line": 64,
                "text": "//"
              },
              {
                "line": 65,
                "text": "void Decoder::processReady(QByteArray t) { emit ready(t); }"
              },
              {
                "line": 66,
                "text": ""
              },
              {
                "line": 67,
                "text": "//"
              },
              {
                "line": 68,
                "text": "void Decoder::processQuit() { emit quitWorker(); }"
              },
              {
                "line": 69,
                "text": ""
              },
              {
                "line": 70,
                "text": "//"
              },
              {
                "line": 71,
                "text": "void Decoder::processError(int errorCode, QString errorString) {"
              },
              {
                "line": 72,
                "text": "    qCDebug(decoder_js8) << \"decoder process error\" << errorCode << errorString;"
              },
              {
                "line": 73,
                "text": "    emit error(errorCode, errorString);"
              },
              {
                "line": 74,
                "text": "}"
              },
              {
                "line": 75,
                "text": ""
              },
              {
                "line": 76,
                "text": "//"
              },
              {
                "line": 77,
                "text": "void Decoder::processFinished(int exitCode, int statusCode,"
              },
              {
                "line": 78,
                "text": "                              QString errorString) {"
              },
              {
                "line": 79,
                "text": "    qCDebug(decoder_js8) << \"decoder process finished\" << exitCode << statusCode"
              }
            ]
          }
        },
        {
          "function": "Decoder::processQuit",
          "line": 68,
          "signature": "void Decoder::processQuit() { emit quitWorker(); }",
          "snippet": {
            "start_line": 54,
            "end_line": 82,
            "lines": [
              {
                "line": 54,
                "text": ""
              },
              {
                "line": 55,
                "text": "//"
              },
              {
                "line": 56,
                "text": "void Decoder::processStart(QString path, QStringList args) {"
              },
              {
                "line": 57,
                "text": "    if (m_worker.isNull()) {"
              },
              {
                "line": 58,
                "text": "        m_worker = createWorker();"
              },
              {
                "line": 59,
                "text": "    }"
              },
              {
                "line": 60,
                "text": ""
              },
              {
                "line": 61,
                "text": "    emit startWorker(path, args);"
              },
              {
                "line": 62,
                "text": "}"
              },
              {
                "line": 63,
                "text": ""
              },
              {
                "line": 64,
                "text": "//"
              },
              {
                "line": 65,
                "text": "void Decoder::processReady(QByteArray t) { emit ready(t); }"
              },
              {
                "line": 66,
                "text": ""
              },
              {
                "line": 67,
                "text": "//"
              },
              {
                "line": 68,
                "text": "void Decoder::processQuit() { emit quitWorker(); }"
              },
              {
                "line": 69,
                "text": ""
              },
              {
                "line": 70,
                "text": "//"
              },
              {
                "line": 71,
                "text": "void Decoder::processError(int errorCode, QString errorString) {"
              },
              {
                "line": 72,
                "text": "    qCDebug(decoder_js8) << \"decoder process error\" << errorCode << errorString;"
              },
              {
                "line": 73,
                "text": "    emit error(errorCode, errorString);"
              },
              {
                "line": 74,
                "text": "}"
              },
              {
                "line": 75,
                "text": ""
              },
              {
                "line": 76,
                "text": "//"
              },
              {
                "line": 77,
                "text": "void Decoder::processFinished(int exitCode, int statusCode,"
              },
              {
                "line": 78,
                "text": "                              QString errorString) {"
              },
              {
                "line": 79,
                "text": "    qCDebug(decoder_js8) << \"decoder process finished\" << exitCode << statusCode"
              },
              {
                "line": 80,
                "text": "                         << errorString;"
              },
              {
                "line": 81,
                "text": "    emit finished(exitCode, statusCode, errorString);"
              },
              {
                "line": 82,
                "text": "}"
              }
            ]
          }
        },
        {
          "function": "Decoder::processError",
          "line": 71,
          "signature": "void Decoder::processError(int errorCode, QString errorString) {",
          "snippet": {
            "start_line": 57,
            "end_line": 85,
            "lines": [
              {
                "line": 57,
                "text": "    if (m_worker.isNull()) {"
              },
              {
                "line": 58,
                "text": "        m_worker = createWorker();"
              },
              {
                "line": 59,
                "text": "    }"
              },
              {
                "line": 60,
                "text": ""
              },
              {
                "line": 61,
                "text": "    emit startWorker(path, args);"
              },
              {
                "line": 62,
                "text": "}"
              },
              {
                "line": 63,
                "text": ""
              },
              {
                "line": 64,
                "text": "//"
              },
              {
                "line": 65,
                "text": "void Decoder::processReady(QByteArray t) { emit ready(t); }"
              },
              {
                "line": 66,
                "text": ""
              },
              {
                "line": 67,
                "text": "//"
              },
              {
                "line": 68,
                "text": "void Decoder::processQuit() { emit quitWorker(); }"
              },
              {
                "line": 69,
                "text": ""
              },
              {
                "line": 70,
                "text": "//"
              },
              {
                "line": 71,
                "text": "void Decoder::processError(int errorCode, QString errorString) {"
              },
              {
                "line": 72,
                "text": "    qCDebug(decoder_js8) << \"decoder process error\" << errorCode << errorString;"
              },
              {
                "line": 73,
                "text": "    emit error(errorCode, errorString);"
              },
              {
                "line": 74,
                "text": "}"
              },
              {
                "line": 75,
                "text": ""
              },
              {
                "line": 76,
                "text": "//"
              },
              {
                "line": 77,
                "text": "void Decoder::processFinished(int exitCode, int statusCode,"
              },
              {
                "line": 78,
                "text": "                              QString errorString) {"
              },
              {
                "line": 79,
                "text": "    qCDebug(decoder_js8) << \"decoder process finished\" << exitCode << statusCode"
              },
              {
                "line": 80,
                "text": "                         << errorString;"
              },
              {
                "line": 81,
                "text": "    emit finished(exitCode, statusCode, errorString);"
              },
              {
                "line": 82,
                "text": "}"
              },
              {
                "line": 83,
                "text": ""
              },
              {
                "line": 84,
                "text": "////////////////////////////////////////"
              },
              {
                "line": 85,
                "text": "//////////////// WORKER ////////////////"
              }
            ]
          }
        },
        {
          "function": "Worker::setProcess",
          "line": 92,
          "signature": "void Worker::setProcess(QProcess *proc, int msecs) {",
          "snippet": {
            "start_line": 78,
            "end_line": 106,
            "lines": [
              {
                "line": 78,
                "text": "                              QString errorString) {"
              },
              {
                "line": 79,
                "text": "    qCDebug(decoder_js8) << \"decoder process finished\" << exitCode << statusCode"
              },
              {
                "line": 80,
                "text": "                         << errorString;"
              },
              {
                "line": 81,
                "text": "    emit finished(exitCode, statusCode, errorString);"
              },
              {
                "line": 82,
                "text": "}"
              },
              {
                "line": 83,
                "text": ""
              },
              {
                "line": 84,
                "text": "////////////////////////////////////////"
              },
              {
                "line": 85,
                "text": "//////////////// WORKER ////////////////"
              },
              {
                "line": 86,
                "text": "////////////////////////////////////////"
              },
              {
                "line": 87,
                "text": ""
              },
              {
                "line": 88,
                "text": "//"
              },
              {
                "line": 89,
                "text": "Worker::~Worker() {}"
              },
              {
                "line": 90,
                "text": ""
              },
              {
                "line": 91,
                "text": "//"
              },
              {
                "line": 92,
                "text": "void Worker::setProcess(QProcess *proc, int msecs) {"
              },
              {
                "line": 93,
                "text": "    if (!m_proc.isNull()) {"
              },
              {
                "line": 94,
                "text": "        bool b = m_proc->waitForFinished(msecs);"
              },
              {
                "line": 95,
                "text": "        if (!b)"
              },
              {
                "line": 96,
                "text": "            m_proc->close();"
              },
              {
                "line": 97,
                "text": "        m_proc.reset();"
              },
              {
                "line": 98,
                "text": "    }"
              },
              {
                "line": 99,
                "text": ""
              },
              {
                "line": 100,
                "text": "    if (proc) {"
              },
              {
                "line": 101,
                "text": "        m_proc.reset(proc);"
              },
              {
                "line": 102,
                "text": "    }"
              },
              {
                "line": 103,
                "text": "}"
              },
              {
                "line": 104,
                "text": ""
              },
              {
                "line": 105,
                "text": "//"
              },
              {
                "line": 106,
                "text": "void Worker::start(QString path, QStringList args) {"
              }
            ]
          }
        },
        {
          "function": "Worker::start",
          "line": 106,
          "signature": "void Worker::start(QString path, QStringList args) {",
          "snippet": {
            "start_line": 92,
            "end_line": 120,
            "lines": [
              {
                "line": 92,
                "text": "void Worker::setProcess(QProcess *proc, int msecs) {"
              },
              {
                "line": 93,
                "text": "    if (!m_proc.isNull()) {"
              },
              {
                "line": 94,
                "text": "        bool b = m_proc->waitForFinished(msecs);"
              },
              {
                "line": 95,
                "text": "        if (!b)"
              },
              {
                "line": 96,
                "text": "            m_proc->close();"
              },
              {
                "line": 97,
                "text": "        m_proc.reset();"
              },
              {
                "line": 98,
                "text": "    }"
              },
              {
                "line": 99,
                "text": ""
              },
              {
                "line": 100,
                "text": "    if (proc) {"
              },
              {
                "line": 101,
                "text": "        m_proc.reset(proc);"
              },
              {
                "line": 102,
                "text": "    }"
              },
              {
                "line": 103,
                "text": "}"
              },
              {
                "line": 104,
                "text": ""
              },
              {
                "line": 105,
                "text": "//"
              },
              {
                "line": 106,
                "text": "void Worker::start(QString path, QStringList args) {"
              },
              {
                "line": 107,
                "text": "    qCDebug(decoder_js8) << \"decoder process starting...\";"
              },
              {
                "line": 108,
                "text": ""
              },
              {
                "line": 109,
                "text": "    auto proc = new QProcess(this);"
              },
              {
                "line": 110,
                "text": ""
              },
              {
                "line": 111,
                "text": "    connect(proc, &QProcess::readyReadStandardOutput, [this, proc]() {"
              },
              {
                "line": 112,
                "text": "        while (proc->canReadLine()) {"
              },
              {
                "line": 113,
                "text": "            emit ready(proc->readLine());"
              },
              {
                "line": 114,
                "text": "        }"
              },
              {
                "line": 115,
                "text": "    });"
              },
              {
                "line": 116,
                "text": ""
              },
              {
                "line": 117,
                "text": "    connect(proc, &QProcess::errorOccurred,"
              },
              {
                "line": 118,
                "text": "            [this, proc](QProcess::ProcessError errorCode) {"
              },
              {
                "line": 119,
                "text": "                emit error(int(errorCode), proc->errorString());"
              },
              {
                "line": 120,
                "text": "            });"
              }
            ]
          }
        },
        {
          "function": "Worker::quit",
          "line": 137,
          "signature": "void Worker::quit() { setProcess(nullptr); }",
          "snippet": {
            "start_line": 123,
            "end_line": 139,
            "lines": [
              {
                "line": 123,
                "text": "            [this, proc](int exitCode, QProcess::ExitStatus status) {"
              },
              {
                "line": 124,
                "text": "                emit finished(exitCode, int(status),"
              },
              {
                "line": 125,
                "text": "                              QString{proc->readAllStandardError()});"
              },
              {
                "line": 126,
                "text": "            });"
              },
              {
                "line": 127,
                "text": ""
              },
              {
                "line": 128,
                "text": "    QProcessEnvironment env{QProcessEnvironment::systemEnvironment()};"
              },
              {
                "line": 129,
                "text": "    env.insert(\"OMP_STACKSIZE\", \"4M\");"
              },
              {
                "line": 130,
                "text": "    proc->setProcessEnvironment(env);"
              },
              {
                "line": 131,
                "text": "    proc->start(path, args, QIODevice::ReadWrite | QIODevice::Unbuffered);"
              },
              {
                "line": 132,
                "text": ""
              },
              {
                "line": 133,
                "text": "    setProcess(proc);"
              },
              {
                "line": 134,
                "text": "}"
              },
              {
                "line": 135,
                "text": ""
              },
              {
                "line": 136,
                "text": "//"
              },
              {
                "line": 137,
                "text": "void Worker::quit() { setProcess(nullptr); }"
              },
              {
                "line": 138,
                "text": ""
              },
              {
                "line": 139,
                "text": "Q_LOGGING_CATEGORY(decoder_js8, \"decoder.js8\", QtWarningMsg)"
              }
            ]
          }
        }
      ],
      "keyword_snippets": [
        {
          "line": 2,
          "matches": [
            "decode"
          ],
          "snippet": {
            "start_line": 1,
            "end_line": 8,
            "lines": [
              {
                "line": 1,
                "text": "/**"
              },
              {
                "line": 2,
                "text": " * @file Decoder.cpp"
              },
              {
                "line": 3,
                "text": " * @brief Implementation of the JS8 decoder and worker classes"
              },
              {
                "line": 4,
                "text": " * (C) 2019 Jordan Sherer <kn4crd@gmail.com> - All Rights Reserved"
              },
              {
                "line": 5,
                "text": " */"
              },
              {
                "line": 6,
                "text": ""
              },
              {
                "line": 7,
                "text": "#include \"Decoder.h\""
              },
              {
                "line": 8,
                "text": "#include \"JS8_Include/commons.h\""
              }
            ]
          }
        },
        {
          "line": 7,
          "matches": [
            "decode"
          ],
          "snippet": {
            "start_line": 1,
            "end_line": 13,
            "lines": [
              {
                "line": 1,
                "text": "/**"
              },
              {
                "line": 2,
                "text": " * @file Decoder.cpp"
              },
              {
                "line": 3,
                "text": " * @brief Implementation of the JS8 decoder and worker classes"
              },
              {
                "line": 4,
                "text": " * (C) 2019 Jordan Sherer <kn4crd@gmail.com> - All Rights Reserved"
              },
              {
                "line": 5,
                "text": " */"
              },
              {
                "line": 6,
                "text": ""
              },
              {
                "line": 7,
                "text": "#include \"Decoder.h\""
              },
              {
                "line": 8,
                "text": "#include \"JS8_Include/commons.h\""
              },
              {
                "line": 9,
                "text": ""
              },
              {
                "line": 10,
                "text": "#include <QLoggingCategory>"
              },
              {
                "line": 11,
                "text": "#include <QTimer>"
              },
              {
                "line": 12,
                "text": ""
              },
              {
                "line": 13,
                "text": "Q_DECLARE_LOGGING_CATEGORY(decoder_js8)"
              }
            ]
          }
        },
        {
          "line": 13,
          "matches": [
            "decode",
            "JS8"
          ],
          "snippet": {
            "start_line": 7,
            "end_line": 19,
            "lines": [
              {
                "line": 7,
                "text": "#include \"Decoder.h\""
              },
              {
                "line": 8,
                "text": "#include \"JS8_Include/commons.h\""
              },
              {
                "line": 9,
                "text": ""
              },
              {
                "line": 10,
                "text": "#include <QLoggingCategory>"
              },
              {
                "line": 11,
                "text": "#include <QTimer>"
              },
              {
                "line": 12,
                "text": ""
              },
              {
                "line": 13,
                "text": "Q_DECLARE_LOGGING_CATEGORY(decoder_js8)"
              },
              {
                "line": 14,
                "text": ""
              },
              {
                "line": 15,
                "text": "Do not let youself be confused"
              },
              {
                "line": 16,
                "text": "    : This source file does not presently take part in the build."
              },
              {
                "line": 17,
                "text": ""
              },
              {
                "line": 18,
                "text": "      Decoder::Decoder(QObject * parent)"
              },
              {
                "line": 19,
                "text": "    : QObject(parent) {}"
              }
            ]
          }
        },
        {
          "line": 18,
          "matches": [
            "decode"
          ],
          "snippet": {
            "start_line": 12,
            "end_line": 24,
            "lines": [
              {
                "line": 12,
                "text": ""
              },
              {
                "line": 13,
                "text": "Q_DECLARE_LOGGING_CATEGORY(decoder_js8)"
              },
              {
                "line": 14,
                "text": ""
              },
              {
                "line": 15,
                "text": "Do not let youself be confused"
              },
              {
                "line": 16,
                "text": "    : This source file does not presently take part in the build."
              },
              {
                "line": 17,
                "text": ""
              },
              {
                "line": 18,
                "text": "      Decoder::Decoder(QObject * parent)"
              },
              {
                "line": 19,
                "text": "    : QObject(parent) {}"
              },
              {
                "line": 20,
                "text": ""
              },
              {
                "line": 21,
                "text": "Decoder::~Decoder() {}"
              },
              {
                "line": 22,
                "text": ""
              },
              {
                "line": 23,
                "text": "//"
              },
              {
                "line": 24,
                "text": "void Decoder::lock() {"
              }
            ]
          }
        },
        {
          "line": 21,
          "matches": [
            "decode"
          ],
          "snippet": {
            "start_line": 15,
            "end_line": 27,
            "lines": [
              {
                "line": 15,
                "text": "Do not let youself be confused"
              },
              {
                "line": 16,
                "text": "    : This source file does not presently take part in the build."
              },
              {
                "line": 17,
                "text": ""
              },
              {
                "line": 18,
                "text": "      Decoder::Decoder(QObject * parent)"
              },
              {
                "line": 19,
                "text": "    : QObject(parent) {}"
              },
              {
                "line": 20,
                "text": ""
              },
              {
                "line": 21,
                "text": "Decoder::~Decoder() {}"
              },
              {
                "line": 22,
                "text": ""
              },
              {
                "line": 23,
                "text": "//"
              },
              {
                "line": 24,
                "text": "void Decoder::lock() {"
              },
              {
                "line": 25,
                "text": "    // NOOP"
              },
              {
                "line": 26,
                "text": "}"
              },
              {
                "line": 27,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 29,
          "matches": [
            "decode"
          ],
          "snippet": {
            "start_line": 23,
            "end_line": 35,
            "lines": [
              {
                "line": 23,
                "text": "//"
              },
              {
                "line": 24,
                "text": "void Decoder::lock() {"
              },
              {
                "line": 25,
                "text": "    // NOOP"
              },
              {
                "line": 26,
                "text": "}"
              },
              {
                "line": 27,
                "text": ""
              },
              {
                "line": 28,
                "text": "//"
              },
              {
                "line": 29,
                "text": "void Decoder::unlock() {"
              },
              {
                "line": 30,
                "text": "    // NOOP"
              },
              {
                "line": 31,
                "text": "}"
              },
              {
                "line": 32,
                "text": ""
              },
              {
                "line": 33,
                "text": "//"
              },
              {
                "line": 34,
                "text": "Worker *Decoder::createWorker() {"
              },
              {
                "line": 35,
                "text": "    auto worker = new Worker();"
              }
            ]
          }
        },
        {
          "line": 34,
          "matches": [
            "decode",
            "Worker"
          ],
          "snippet": {
            "start_line": 28,
            "end_line": 40,
            "lines": [
              {
                "line": 28,
                "text": "//"
              },
              {
                "line": 29,
                "text": "void Decoder::unlock() {"
              },
              {
                "line": 30,
                "text": "    // NOOP"
              },
              {
                "line": 31,
                "text": "}"
              },
              {
                "line": 32,
                "text": ""
              },
              {
                "line": 33,
                "text": "//"
              },
              {
                "line": 34,
                "text": "Worker *Decoder::createWorker() {"
              },
              {
                "line": 35,
                "text": "    auto worker = new Worker();"
              },
              {
                "line": 36,
                "text": "    worker->moveToThread(&m_thread);"
              },
              {
                "line": 37,
                "text": "    connect(&m_thread, &QThread::finished, worker, &QObject::deleteLater);"
              },
              {
                "line": 38,
                "text": "    connect(this, &Decoder::startWorker, worker, &Worker::start);"
              },
              {
                "line": 39,
                "text": "    connect(this, &Decoder::quitWorker, worker, &Worker::quit);"
              },
              {
                "line": 40,
                "text": "    connect(worker, &Worker::ready, this, &Decoder::processReady);"
              }
            ]
          }
        },
        {
          "line": 36,
          "matches": [
            "Worker"
          ],
          "snippet": {
            "start_line": 30,
            "end_line": 42,
            "lines": [
              {
                "line": 30,
                "text": "    // NOOP"
              },
              {
                "line": 31,
                "text": "}"
              },
              {
                "line": 32,
                "text": ""
              },
              {
                "line": 33,
                "text": "//"
              },
              {
                "line": 34,
                "text": "Worker *Decoder::createWorker() {"
              },
              {
                "line": 35,
                "text": "    auto worker = new Worker();"
              },
              {
                "line": 36,
                "text": "    worker->moveToThread(&m_thread);"
              },
              {
                "line": 37,
                "text": "    connect(&m_thread, &QThread::finished, worker, &QObject::deleteLater);"
              },
              {
                "line": 38,
                "text": "    connect(this, &Decoder::startWorker, worker, &Worker::start);"
              },
              {
                "line": 39,
                "text": "    connect(this, &Decoder::quitWorker, worker, &Worker::quit);"
              },
              {
                "line": 40,
                "text": "    connect(worker, &Worker::ready, this, &Decoder::processReady);"
              },
              {
                "line": 41,
                "text": "    connect(worker, &Worker::error, this, &Decoder::processError);"
              },
              {
                "line": 42,
                "text": "    connect(worker, &Worker::finished, this, &Decoder::processFinished);"
              }
            ]
          }
        },
        {
          "line": 41,
          "matches": [
            "decode",
            "Worker"
          ],
          "snippet": {
            "start_line": 35,
            "end_line": 47,
            "lines": [
              {
                "line": 35,
                "text": "    auto worker = new Worker();"
              },
              {
                "line": 36,
                "text": "    worker->moveToThread(&m_thread);"
              },
              {
                "line": 37,
                "text": "    connect(&m_thread, &QThread::finished, worker, &QObject::deleteLater);"
              },
              {
                "line": 38,
                "text": "    connect(this, &Decoder::startWorker, worker, &Worker::start);"
              },
              {
                "line": 39,
                "text": "    connect(this, &Decoder::quitWorker, worker, &Worker::quit);"
              },
              {
                "line": 40,
                "text": "    connect(worker, &Worker::ready, this, &Decoder::processReady);"
              },
              {
                "line": 41,
                "text": "    connect(worker, &Worker::error, this, &Decoder::processError);"
              },
              {
                "line": 42,
                "text": "    connect(worker, &Worker::finished, this, &Decoder::processFinished);"
              },
              {
                "line": 43,
                "text": "    return worker;"
              },
              {
                "line": 44,
                "text": "}"
              },
              {
                "line": 45,
                "text": ""
              },
              {
                "line": 46,
                "text": "//"
              },
              {
                "line": 47,
                "text": "void Decoder::start(QThread::Priority priority) { m_thread.start(priority); }"
              }
            ]
          }
        },
        {
          "line": 47,
          "matches": [
            "decode"
          ],
          "snippet": {
            "start_line": 41,
            "end_line": 53,
            "lines": [
              {
                "line": 41,
                "text": "    connect(worker, &Worker::error, this, &Decoder::processError);"
              },
              {
                "line": 42,
                "text": "    connect(worker, &Worker::finished, this, &Decoder::processFinished);"
              },
              {
                "line": 43,
                "text": "    return worker;"
              },
              {
                "line": 44,
                "text": "}"
              },
              {
                "line": 45,
                "text": ""
              },
              {
                "line": 46,
                "text": "//"
              },
              {
                "line": 47,
                "text": "void Decoder::start(QThread::Priority priority) { m_thread.start(priority); }"
              },
              {
                "line": 48,
                "text": ""
              },
              {
                "line": 49,
                "text": "//"
              },
              {
                "line": 50,
                "text": "void Decoder::quit() { m_thread.quit(); }"
              },
              {
                "line": 51,
                "text": ""
              },
              {
                "line": 52,
                "text": "//"
              },
              {
                "line": 53,
                "text": "bool Decoder::wait() { return m_thread.wait(); }"
              }
            ]
          }
        },
        {
          "line": 53,
          "matches": [
            "decode"
          ],
          "snippet": {
            "start_line": 47,
            "end_line": 59,
            "lines": [
              {
                "line": 47,
                "text": "void Decoder::start(QThread::Priority priority) { m_thread.start(priority); }"
              },
              {
                "line": 48,
                "text": ""
              },
              {
                "line": 49,
                "text": "//"
              },
              {
                "line": 50,
                "text": "void Decoder::quit() { m_thread.quit(); }"
              },
              {
                "line": 51,
                "text": ""
              },
              {
                "line": 52,
                "text": "//"
              },
              {
                "line": 53,
                "text": "bool Decoder::wait() { return m_thread.wait(); }"
              },
              {
                "line": 54,
                "text": ""
              },
              {
                "line": 55,
                "text": "//"
              },
              {
                "line": 56,
                "text": "void Decoder::processStart(QString path, QStringList args) {"
              },
              {
                "line": 57,
                "text": "    if (m_worker.isNull()) {"
              },
              {
                "line": 58,
                "text": "        m_worker = createWorker();"
              },
              {
                "line": 59,
                "text": "    }"
              }
            ]
          }
        },
        {
          "line": 56,
          "matches": [
            "decode"
          ],
          "snippet": {
            "start_line": 50,
            "end_line": 62,
            "lines": [
              {
                "line": 50,
                "text": "void Decoder::quit() { m_thread.quit(); }"
              },
              {
                "line": 51,
                "text": ""
              },
              {
                "line": 52,
                "text": "//"
              },
              {
                "line": 53,
                "text": "bool Decoder::wait() { return m_thread.wait(); }"
              },
              {
                "line": 54,
                "text": ""
              },
              {
                "line": 55,
                "text": "//"
              },
              {
                "line": 56,
                "text": "void Decoder::processStart(QString path, QStringList args) {"
              },
              {
                "line": 57,
                "text": "    if (m_worker.isNull()) {"
              },
              {
                "line": 58,
                "text": "        m_worker = createWorker();"
              },
              {
                "line": 59,
                "text": "    }"
              },
              {
                "line": 60,
                "text": ""
              },
              {
                "line": 61,
                "text": "    emit startWorker(path, args);"
              },
              {
                "line": 62,
                "text": "}"
              }
            ]
          }
        },
        {
          "line": 61,
          "matches": [
            "Worker"
          ],
          "snippet": {
            "start_line": 55,
            "end_line": 67,
            "lines": [
              {
                "line": 55,
                "text": "//"
              },
              {
                "line": 56,
                "text": "void Decoder::processStart(QString path, QStringList args) {"
              },
              {
                "line": 57,
                "text": "    if (m_worker.isNull()) {"
              },
              {
                "line": 58,
                "text": "        m_worker = createWorker();"
              },
              {
                "line": 59,
                "text": "    }"
              },
              {
                "line": 60,
                "text": ""
              },
              {
                "line": 61,
                "text": "    emit startWorker(path, args);"
              },
              {
                "line": 62,
                "text": "}"
              },
              {
                "line": 63,
                "text": ""
              },
              {
                "line": 64,
                "text": "//"
              },
              {
                "line": 65,
                "text": "void Decoder::processReady(QByteArray t) { emit ready(t); }"
              },
              {
                "line": 66,
                "text": ""
              },
              {
                "line": 67,
                "text": "//"
              }
            ]
          }
        },
        {
          "line": 68,
          "matches": [
            "decode",
            "Worker"
          ],
          "snippet": {
            "start_line": 62,
            "end_line": 74,
            "lines": [
              {
                "line": 62,
                "text": "}"
              },
              {
                "line": 63,
                "text": ""
              },
              {
                "line": 64,
                "text": "//"
              },
              {
                "line": 65,
                "text": "void Decoder::processReady(QByteArray t) { emit ready(t); }"
              },
              {
                "line": 66,
                "text": ""
              },
              {
                "line": 67,
                "text": "//"
              },
              {
                "line": 68,
                "text": "void Decoder::processQuit() { emit quitWorker(); }"
              },
              {
                "line": 69,
                "text": ""
              },
              {
                "line": 70,
                "text": "//"
              },
              {
                "line": 71,
                "text": "void Decoder::processError(int errorCode, QString errorString) {"
              },
              {
                "line": 72,
                "text": "    qCDebug(decoder_js8) << \"decoder process error\" << errorCode << errorString;"
              },
              {
                "line": 73,
                "text": "    emit error(errorCode, errorString);"
              },
              {
                "line": 74,
                "text": "}"
              }
            ]
          }
        },
        {
          "line": 71,
          "matches": [
            "decode"
          ],
          "snippet": {
            "start_line": 65,
            "end_line": 77,
            "lines": [
              {
                "line": 65,
                "text": "void Decoder::processReady(QByteArray t) { emit ready(t); }"
              },
              {
                "line": 66,
                "text": ""
              },
              {
                "line": 67,
                "text": "//"
              },
              {
                "line": 68,
                "text": "void Decoder::processQuit() { emit quitWorker(); }"
              },
              {
                "line": 69,
                "text": ""
              },
              {
                "line": 70,
                "text": "//"
              },
              {
                "line": 71,
                "text": "void Decoder::processError(int errorCode, QString errorString) {"
              },
              {
                "line": 72,
                "text": "    qCDebug(decoder_js8) << \"decoder process error\" << errorCode << errorString;"
              },
              {
                "line": 73,
                "text": "    emit error(errorCode, errorString);"
              },
              {
                "line": 74,
                "text": "}"
              },
              {
                "line": 75,
                "text": ""
              },
              {
                "line": 76,
                "text": "//"
              },
              {
                "line": 77,
                "text": "void Decoder::processFinished(int exitCode, int statusCode,"
              }
            ]
          }
        },
        {
          "line": 77,
          "matches": [
            "decode"
          ],
          "snippet": {
            "start_line": 71,
            "end_line": 83,
            "lines": [
              {
                "line": 71,
                "text": "void Decoder::processError(int errorCode, QString errorString) {"
              },
              {
                "line": 72,
                "text": "    qCDebug(decoder_js8) << \"decoder process error\" << errorCode << errorString;"
              },
              {
                "line": 73,
                "text": "    emit error(errorCode, errorString);"
              },
              {
                "line": 74,
                "text": "}"
              },
              {
                "line": 75,
                "text": ""
              },
              {
                "line": 76,
                "text": "//"
              },
              {
                "line": 77,
                "text": "void Decoder::processFinished(int exitCode, int statusCode,"
              },
              {
                "line": 78,
                "text": "                              QString errorString) {"
              },
              {
                "line": 79,
                "text": "    qCDebug(decoder_js8) << \"decoder process finished\" << exitCode << statusCode"
              },
              {
                "line": 80,
                "text": "                         << errorString;"
              },
              {
                "line": 81,
                "text": "    emit finished(exitCode, statusCode, errorString);"
              },
              {
                "line": 82,
                "text": "}"
              },
              {
                "line": 83,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 85,
          "matches": [
            "Worker"
          ],
          "snippet": {
            "start_line": 79,
            "end_line": 91,
            "lines": [
              {
                "line": 79,
                "text": "    qCDebug(decoder_js8) << \"decoder process finished\" << exitCode << statusCode"
              },
              {
                "line": 80,
                "text": "                         << errorString;"
              },
              {
                "line": 81,
                "text": "    emit finished(exitCode, statusCode, errorString);"
              },
              {
                "line": 82,
                "text": "}"
              },
              {
                "line": 83,
                "text": ""
              },
              {
                "line": 84,
                "text": "////////////////////////////////////////"
              },
              {
                "line": 85,
                "text": "//////////////// WORKER ////////////////"
              },
              {
                "line": 86,
                "text": "////////////////////////////////////////"
              },
              {
                "line": 87,
                "text": ""
              },
              {
                "line": 88,
                "text": "//"
              },
              {
                "line": 89,
                "text": "Worker::~Worker() {}"
              },
              {
                "line": 90,
                "text": ""
              },
              {
                "line": 91,
                "text": "//"
              }
            ]
          }
        },
        {
          "line": 89,
          "matches": [
            "Worker"
          ],
          "snippet": {
            "start_line": 83,
            "end_line": 95,
            "lines": [
              {
                "line": 83,
                "text": ""
              },
              {
                "line": 84,
                "text": "////////////////////////////////////////"
              },
              {
                "line": 85,
                "text": "//////////////// WORKER ////////////////"
              },
              {
                "line": 86,
                "text": "////////////////////////////////////////"
              },
              {
                "line": 87,
                "text": ""
              },
              {
                "line": 88,
                "text": "//"
              },
              {
                "line": 89,
                "text": "Worker::~Worker() {}"
              },
              {
                "line": 90,
                "text": ""
              },
              {
                "line": 91,
                "text": "//"
              },
              {
                "line": 92,
                "text": "void Worker::setProcess(QProcess *proc, int msecs) {"
              },
              {
                "line": 93,
                "text": "    if (!m_proc.isNull()) {"
              },
              {
                "line": 94,
                "text": "        bool b = m_proc->waitForFinished(msecs);"
              },
              {
                "line": 95,
                "text": "        if (!b)"
              }
            ]
          }
        },
        {
          "line": 92,
          "matches": [
            "Worker"
          ],
          "snippet": {
            "start_line": 86,
            "end_line": 98,
            "lines": [
              {
                "line": 86,
                "text": "////////////////////////////////////////"
              },
              {
                "line": 87,
                "text": ""
              },
              {
                "line": 88,
                "text": "//"
              },
              {
                "line": 89,
                "text": "Worker::~Worker() {}"
              },
              {
                "line": 90,
                "text": ""
              },
              {
                "line": 91,
                "text": "//"
              },
              {
                "line": 92,
                "text": "void Worker::setProcess(QProcess *proc, int msecs) {"
              },
              {
                "line": 93,
                "text": "    if (!m_proc.isNull()) {"
              },
              {
                "line": 94,
                "text": "        bool b = m_proc->waitForFinished(msecs);"
              },
              {
                "line": 95,
                "text": "        if (!b)"
              },
              {
                "line": 96,
                "text": "            m_proc->close();"
              },
              {
                "line": 97,
                "text": "        m_proc.reset();"
              },
              {
                "line": 98,
                "text": "    }"
              }
            ]
          }
        },
        {
          "line": 106,
          "matches": [
            "Worker"
          ],
          "snippet": {
            "start_line": 100,
            "end_line": 112,
            "lines": [
              {
                "line": 100,
                "text": "    if (proc) {"
              },
              {
                "line": 101,
                "text": "        m_proc.reset(proc);"
              },
              {
                "line": 102,
                "text": "    }"
              },
              {
                "line": 103,
                "text": "}"
              },
              {
                "line": 104,
                "text": ""
              },
              {
                "line": 105,
                "text": "//"
              },
              {
                "line": 106,
                "text": "void Worker::start(QString path, QStringList args) {"
              },
              {
                "line": 107,
                "text": "    qCDebug(decoder_js8) << \"decoder process starting...\";"
              },
              {
                "line": 108,
                "text": ""
              },
              {
                "line": 109,
                "text": "    auto proc = new QProcess(this);"
              },
              {
                "line": 110,
                "text": ""
              },
              {
                "line": 111,
                "text": "    connect(proc, &QProcess::readyReadStandardOutput, [this, proc]() {"
              },
              {
                "line": 112,
                "text": "        while (proc->canReadLine()) {"
              }
            ]
          }
        },
        {
          "line": 137,
          "matches": [
            "Worker"
          ],
          "snippet": {
            "start_line": 131,
            "end_line": 139,
            "lines": [
              {
                "line": 131,
                "text": "    proc->start(path, args, QIODevice::ReadWrite | QIODevice::Unbuffered);"
              },
              {
                "line": 132,
                "text": ""
              },
              {
                "line": 133,
                "text": "    setProcess(proc);"
              },
              {
                "line": 134,
                "text": "}"
              },
              {
                "line": 135,
                "text": ""
              },
              {
                "line": 136,
                "text": "//"
              },
              {
                "line": 137,
                "text": "void Worker::quit() { setProcess(nullptr); }"
              },
              {
                "line": 138,
                "text": ""
              },
              {
                "line": 139,
                "text": "Q_LOGGING_CATEGORY(decoder_js8, \"decoder.js8\", QtWarningMsg)"
              }
            ]
          }
        }
      ]
    },
    {
      "path": "JS8_Mode/JS8Submode.cpp",
      "exists": true,
      "bytes": 13093,
      "sha256": "10d60fcdd5c908d85b26df1379b0dbc3afd75412aa269b3216196c0bc93aedfd",
      "line_count": 399,
      "phase_hits": {
        "timing_submode": 26,
        "symbol_to_soft_bits": 41,
        "bit_order_interleaver": 2,
        "whitening_erasure": 0,
        "ldpc_decode": 0,
        "message91_crc_text": 7
      },
      "function_blocks": [
        {
          "function": "floor",
          "line": 25,
          "signature": "template <std::floating_point T> constexpr int floor(T const v) {",
          "snippet": {
            "start_line": 11,
            "end_line": 39,
            "lines": [
              {
                "line": 11,
                "text": "#include <concepts>"
              },
              {
                "line": 12,
                "text": ""
              },
              {
                "line": 13,
                "text": "/******************************************************************************/"
              },
              {
                "line": 14,
                "text": "// Private Implementation"
              },
              {
                "line": 15,
                "text": "/******************************************************************************/"
              },
              {
                "line": 16,
                "text": ""
              },
              {
                "line": 17,
                "text": "Q_DECLARE_LOGGING_CATEGORY(js8submode_js8)"
              },
              {
                "line": 18,
                "text": ""
              },
              {
                "line": 19,
                "text": "namespace JS8::Submode {"
              },
              {
                "line": 20,
                "text": "namespace {"
              },
              {
                "line": 21,
                "text": "// std::floor doesn't become constexpr until C++23; until then, our own"
              },
              {
                "line": 22,
                "text": "// implementation. We only use this for computation of the number of"
              },
              {
                "line": 23,
                "text": "// frames needed for a submode, so it doesn't need to be complicated."
              },
              {
                "line": 24,
                "text": ""
              },
              {
                "line": 25,
                "text": "template <std::floating_point T> constexpr int floor(T const v) {"
              },
              {
                "line": 26,
                "text": "    auto const i = static_cast<int>(v);"
              },
              {
                "line": 27,
                "text": "    return v < i ? i - 1 : i;"
              },
              {
                "line": 28,
                "text": "}"
              },
              {
                "line": 29,
                "text": ""
              },
              {
                "line": 30,
                "text": "// Ensure that our implementation works as expected."
              },
              {
                "line": 31,
                "text": ""
              },
              {
                "line": 32,
                "text": "static_assert(floor(0.0) == 0);"
              },
              {
                "line": 33,
                "text": "static_assert(floor(0.499999) == 0);"
              },
              {
                "line": 34,
                "text": "static_assert(floor(0.5) == 0);"
              },
              {
                "line": 35,
                "text": "static_assert(floor(0.999999) == 0);"
              },
              {
                "line": 36,
                "text": "static_assert(floor(1.0) == 1);"
              },
              {
                "line": 37,
                "text": "static_assert(floor(123.0) == 123);"
              },
              {
                "line": 38,
                "text": "static_assert(floor(123.4) == 123);"
              },
              {
                "line": 39,
                "text": "static_assert(floor(-0.499999) == -1);"
              }
            ]
          }
        },
        {
          "function": "samplesForOneSymbol",
          "line": 79,
          "signature": "constexpr unsigned int samplesForOneSymbol() const {",
          "snippet": {
            "start_line": 65,
            "end_line": 93,
            "lines": [
              {
                "line": 65,
                "text": "          m_rxSNRThreshold(rxSNRThreshold), m_rxThreshold(rxThreshold),"
              },
              {
                "line": 66,
                "text": "          m_samplesForSymbols(JS8_NUM_SYMBOLS * samplesForOneSymbol),"
              },
              {
                "line": 67,
                "text": "          m_bandwidth(8 * JS8_RX_SAMPLE_RATE / samplesForOneSymbol),"
              },
              {
                "line": 68,
                "text": "          m_samplesPerPeriod(JS8_RX_SAMPLE_RATE * period),"
              },
              {
                "line": 69,
                "text": "          m_toneSpacing(JS8_RX_SAMPLE_RATE / (double)samplesForOneSymbol),"
              },
              {
                "line": 70,
                "text": "          m_samplesNeeded("
              },
              {
                "line": 71,
                "text": "              floor(m_samplesForSymbols +"
              },
              {
                "line": 72,
                "text": "                    (0.5 + startDelayMS / 1000.0) * JS8_RX_SAMPLE_RATE)),"
              },
              {
                "line": 73,
                "text": "          m_dataDuration(m_samplesForSymbols / (double)JS8_RX_SAMPLE_RATE),"
              },
              {
                "line": 74,
                "text": "          m_txDuration(m_dataDuration + startDelayMS / 1000.0) {}"
              },
              {
                "line": 75,
                "text": ""
              },
              {
                "line": 76,
                "text": "    // Inline accessors"
              },
              {
                "line": 77,
                "text": ""
              },
              {
                "line": 78,
                "text": "    constexpr const char *name() const { return m_name; }"
              },
              {
                "line": 79,
                "text": "    constexpr unsigned int samplesForOneSymbol() const {"
              },
              {
                "line": 80,
                "text": "        return m_samplesForOneSymbol;"
              },
              {
                "line": 81,
                "text": "    }"
              },
              {
                "line": 82,
                "text": "    constexpr unsigned int startDelayMS() const { return m_startDelayMS; }"
              },
              {
                "line": 83,
                "text": "    constexpr unsigned int period() const { return m_period; }"
              },
              {
                "line": 84,
                "text": "    constexpr Costas::Type costas() const { return m_costas; }"
              },
              {
                "line": 85,
                "text": "    constexpr int rxSNRThreshold() const { return m_rxSNRThreshold; }"
              },
              {
                "line": 86,
                "text": "    constexpr int rxThreshold() const { return m_rxThreshold; }"
              },
              {
                "line": 87,
                "text": "    constexpr int samplesForSymbols() const { return m_samplesForSymbols; }"
              },
              {
                "line": 88,
                "text": "    constexpr int bandwidth() const { return m_bandwidth; }"
              },
              {
                "line": 89,
                "text": "    constexpr int samplesPerPeriod() const { return m_samplesPerPeriod; }"
              },
              {
                "line": 90,
                "text": "    constexpr int samplesNeeded() const { return m_samplesNeeded; }"
              },
              {
                "line": 91,
                "text": "    constexpr double dataDuration() const { return m_dataDuration; }"
              },
              {
                "line": 92,
                "text": "    constexpr double toneSpacing() const { return m_toneSpacing; }"
              },
              {
                "line": 93,
                "text": "    constexpr double txDuration() const { return m_txDuration; }"
              }
            ]
          }
        },
        {
          "function": "startDelayMS",
          "line": 82,
          "signature": "constexpr unsigned int startDelayMS() const { return m_startDelayMS; }",
          "snippet": {
            "start_line": 68,
            "end_line": 96,
            "lines": [
              {
                "line": 68,
                "text": "          m_samplesPerPeriod(JS8_RX_SAMPLE_RATE * period),"
              },
              {
                "line": 69,
                "text": "          m_toneSpacing(JS8_RX_SAMPLE_RATE / (double)samplesForOneSymbol),"
              },
              {
                "line": 70,
                "text": "          m_samplesNeeded("
              },
              {
                "line": 71,
                "text": "              floor(m_samplesForSymbols +"
              },
              {
                "line": 72,
                "text": "                    (0.5 + startDelayMS / 1000.0) * JS8_RX_SAMPLE_RATE)),"
              },
              {
                "line": 73,
                "text": "          m_dataDuration(m_samplesForSymbols / (double)JS8_RX_SAMPLE_RATE),"
              },
              {
                "line": 74,
                "text": "          m_txDuration(m_dataDuration + startDelayMS / 1000.0) {}"
              },
              {
                "line": 75,
                "text": ""
              },
              {
                "line": 76,
                "text": "    // Inline accessors"
              },
              {
                "line": 77,
                "text": ""
              },
              {
                "line": 78,
                "text": "    constexpr const char *name() const { return m_name; }"
              },
              {
                "line": 79,
                "text": "    constexpr unsigned int samplesForOneSymbol() const {"
              },
              {
                "line": 80,
                "text": "        return m_samplesForOneSymbol;"
              },
              {
                "line": 81,
                "text": "    }"
              },
              {
                "line": 82,
                "text": "    constexpr unsigned int startDelayMS() const { return m_startDelayMS; }"
              },
              {
                "line": 83,
                "text": "    constexpr unsigned int period() const { return m_period; }"
              },
              {
                "line": 84,
                "text": "    constexpr Costas::Type costas() const { return m_costas; }"
              },
              {
                "line": 85,
                "text": "    constexpr int rxSNRThreshold() const { return m_rxSNRThreshold; }"
              },
              {
                "line": 86,
                "text": "    constexpr int rxThreshold() const { return m_rxThreshold; }"
              },
              {
                "line": 87,
                "text": "    constexpr int samplesForSymbols() const { return m_samplesForSymbols; }"
              },
              {
                "line": 88,
                "text": "    constexpr int bandwidth() const { return m_bandwidth; }"
              },
              {
                "line": 89,
                "text": "    constexpr int samplesPerPeriod() const { return m_samplesPerPeriod; }"
              },
              {
                "line": 90,
                "text": "    constexpr int samplesNeeded() const { return m_samplesNeeded; }"
              },
              {
                "line": 91,
                "text": "    constexpr double dataDuration() const { return m_dataDuration; }"
              },
              {
                "line": 92,
                "text": "    constexpr double toneSpacing() const { return m_toneSpacing; }"
              },
              {
                "line": 93,
                "text": "    constexpr double txDuration() const { return m_txDuration; }"
              },
              {
                "line": 94,
                "text": ""
              },
              {
                "line": 95,
                "text": "  private:"
              },
              {
                "line": 96,
                "text": "    // Data members ** ORDER DEPENDENCY **"
              }
            ]
          }
        },
        {
          "function": "period",
          "line": 83,
          "signature": "constexpr unsigned int period() const { return m_period; }",
          "snippet": {
            "start_line": 69,
            "end_line": 97,
            "lines": [
              {
                "line": 69,
                "text": "          m_toneSpacing(JS8_RX_SAMPLE_RATE / (double)samplesForOneSymbol),"
              },
              {
                "line": 70,
                "text": "          m_samplesNeeded("
              },
              {
                "line": 71,
                "text": "              floor(m_samplesForSymbols +"
              },
              {
                "line": 72,
                "text": "                    (0.5 + startDelayMS / 1000.0) * JS8_RX_SAMPLE_RATE)),"
              },
              {
                "line": 73,
                "text": "          m_dataDuration(m_samplesForSymbols / (double)JS8_RX_SAMPLE_RATE),"
              },
              {
                "line": 74,
                "text": "          m_txDuration(m_dataDuration + startDelayMS / 1000.0) {}"
              },
              {
                "line": 75,
                "text": ""
              },
              {
                "line": 76,
                "text": "    // Inline accessors"
              },
              {
                "line": 77,
                "text": ""
              },
              {
                "line": 78,
                "text": "    constexpr const char *name() const { return m_name; }"
              },
              {
                "line": 79,
                "text": "    constexpr unsigned int samplesForOneSymbol() const {"
              },
              {
                "line": 80,
                "text": "        return m_samplesForOneSymbol;"
              },
              {
                "line": 81,
                "text": "    }"
              },
              {
                "line": 82,
                "text": "    constexpr unsigned int startDelayMS() const { return m_startDelayMS; }"
              },
              {
                "line": 83,
                "text": "    constexpr unsigned int period() const { return m_period; }"
              },
              {
                "line": 84,
                "text": "    constexpr Costas::Type costas() const { return m_costas; }"
              },
              {
                "line": 85,
                "text": "    constexpr int rxSNRThreshold() const { return m_rxSNRThreshold; }"
              },
              {
                "line": 86,
                "text": "    constexpr int rxThreshold() const { return m_rxThreshold; }"
              },
              {
                "line": 87,
                "text": "    constexpr int samplesForSymbols() const { return m_samplesForSymbols; }"
              },
              {
                "line": 88,
                "text": "    constexpr int bandwidth() const { return m_bandwidth; }"
              },
              {
                "line": 89,
                "text": "    constexpr int samplesPerPeriod() const { return m_samplesPerPeriod; }"
              },
              {
                "line": 90,
                "text": "    constexpr int samplesNeeded() const { return m_samplesNeeded; }"
              },
              {
                "line": 91,
                "text": "    constexpr double dataDuration() const { return m_dataDuration; }"
              },
              {
                "line": 92,
                "text": "    constexpr double toneSpacing() const { return m_toneSpacing; }"
              },
              {
                "line": 93,
                "text": "    constexpr double txDuration() const { return m_txDuration; }"
              },
              {
                "line": 94,
                "text": ""
              },
              {
                "line": 95,
                "text": "  private:"
              },
              {
                "line": 96,
                "text": "    // Data members ** ORDER DEPENDENCY **"
              },
              {
                "line": 97,
                "text": ""
              }
            ]
          }
        },
        {
          "function": "costas",
          "line": 84,
          "signature": "constexpr Costas::Type costas() const { return m_costas; }",
          "snippet": {
            "start_line": 70,
            "end_line": 98,
            "lines": [
              {
                "line": 70,
                "text": "          m_samplesNeeded("
              },
              {
                "line": 71,
                "text": "              floor(m_samplesForSymbols +"
              },
              {
                "line": 72,
                "text": "                    (0.5 + startDelayMS / 1000.0) * JS8_RX_SAMPLE_RATE)),"
              },
              {
                "line": 73,
                "text": "          m_dataDuration(m_samplesForSymbols / (double)JS8_RX_SAMPLE_RATE),"
              },
              {
                "line": 74,
                "text": "          m_txDuration(m_dataDuration + startDelayMS / 1000.0) {}"
              },
              {
                "line": 75,
                "text": ""
              },
              {
                "line": 76,
                "text": "    // Inline accessors"
              },
              {
                "line": 77,
                "text": ""
              },
              {
                "line": 78,
                "text": "    constexpr const char *name() const { return m_name; }"
              },
              {
                "line": 79,
                "text": "    constexpr unsigned int samplesForOneSymbol() const {"
              },
              {
                "line": 80,
                "text": "        return m_samplesForOneSymbol;"
              },
              {
                "line": 81,
                "text": "    }"
              },
              {
                "line": 82,
                "text": "    constexpr unsigned int startDelayMS() const { return m_startDelayMS; }"
              },
              {
                "line": 83,
                "text": "    constexpr unsigned int period() const { return m_period; }"
              },
              {
                "line": 84,
                "text": "    constexpr Costas::Type costas() const { return m_costas; }"
              },
              {
                "line": 85,
                "text": "    constexpr int rxSNRThreshold() const { return m_rxSNRThreshold; }"
              },
              {
                "line": 86,
                "text": "    constexpr int rxThreshold() const { return m_rxThreshold; }"
              },
              {
                "line": 87,
                "text": "    constexpr int samplesForSymbols() const { return m_samplesForSymbols; }"
              },
              {
                "line": 88,
                "text": "    constexpr int bandwidth() const { return m_bandwidth; }"
              },
              {
                "line": 89,
                "text": "    constexpr int samplesPerPeriod() const { return m_samplesPerPeriod; }"
              },
              {
                "line": 90,
                "text": "    constexpr int samplesNeeded() const { return m_samplesNeeded; }"
              },
              {
                "line": 91,
                "text": "    constexpr double dataDuration() const { return m_dataDuration; }"
              },
              {
                "line": 92,
                "text": "    constexpr double toneSpacing() const { return m_toneSpacing; }"
              },
              {
                "line": 93,
                "text": "    constexpr double txDuration() const { return m_txDuration; }"
              },
              {
                "line": 94,
                "text": ""
              },
              {
                "line": 95,
                "text": "  private:"
              },
              {
                "line": 96,
                "text": "    // Data members ** ORDER DEPENDENCY **"
              },
              {
                "line": 97,
                "text": ""
              },
              {
                "line": 98,
                "text": "    const char *m_name;"
              }
            ]
          }
        },
        {
          "function": "rxSNRThreshold",
          "line": 85,
          "signature": "constexpr int rxSNRThreshold() const { return m_rxSNRThreshold; }",
          "snippet": {
            "start_line": 71,
            "end_line": 99,
            "lines": [
              {
                "line": 71,
                "text": "              floor(m_samplesForSymbols +"
              },
              {
                "line": 72,
                "text": "                    (0.5 + startDelayMS / 1000.0) * JS8_RX_SAMPLE_RATE)),"
              },
              {
                "line": 73,
                "text": "          m_dataDuration(m_samplesForSymbols / (double)JS8_RX_SAMPLE_RATE),"
              },
              {
                "line": 74,
                "text": "          m_txDuration(m_dataDuration + startDelayMS / 1000.0) {}"
              },
              {
                "line": 75,
                "text": ""
              },
              {
                "line": 76,
                "text": "    // Inline accessors"
              },
              {
                "line": 77,
                "text": ""
              },
              {
                "line": 78,
                "text": "    constexpr const char *name() const { return m_name; }"
              },
              {
                "line": 79,
                "text": "    constexpr unsigned int samplesForOneSymbol() const {"
              },
              {
                "line": 80,
                "text": "        return m_samplesForOneSymbol;"
              },
              {
                "line": 81,
                "text": "    }"
              },
              {
                "line": 82,
                "text": "    constexpr unsigned int startDelayMS() const { return m_startDelayMS; }"
              },
              {
                "line": 83,
                "text": "    constexpr unsigned int period() const { return m_period; }"
              },
              {
                "line": 84,
                "text": "    constexpr Costas::Type costas() const { return m_costas; }"
              },
              {
                "line": 85,
                "text": "    constexpr int rxSNRThreshold() const { return m_rxSNRThreshold; }"
              },
              {
                "line": 86,
                "text": "    constexpr int rxThreshold() const { return m_rxThreshold; }"
              },
              {
                "line": 87,
                "text": "    constexpr int samplesForSymbols() const { return m_samplesForSymbols; }"
              },
              {
                "line": 88,
                "text": "    constexpr int bandwidth() const { return m_bandwidth; }"
              },
              {
                "line": 89,
                "text": "    constexpr int samplesPerPeriod() const { return m_samplesPerPeriod; }"
              },
              {
                "line": 90,
                "text": "    constexpr int samplesNeeded() const { return m_samplesNeeded; }"
              },
              {
                "line": 91,
                "text": "    constexpr double dataDuration() const { return m_dataDuration; }"
              },
              {
                "line": 92,
                "text": "    constexpr double toneSpacing() const { return m_toneSpacing; }"
              },
              {
                "line": 93,
                "text": "    constexpr double txDuration() const { return m_txDuration; }"
              },
              {
                "line": 94,
                "text": ""
              },
              {
                "line": 95,
                "text": "  private:"
              },
              {
                "line": 96,
                "text": "    // Data members ** ORDER DEPENDENCY **"
              },
              {
                "line": 97,
                "text": ""
              },
              {
                "line": 98,
                "text": "    const char *m_name;"
              },
              {
                "line": 99,
                "text": "    unsigned int m_samplesForOneSymbol;"
              }
            ]
          }
        },
        {
          "function": "rxThreshold",
          "line": 86,
          "signature": "constexpr int rxThreshold() const { return m_rxThreshold; }",
          "snippet": {
            "start_line": 72,
            "end_line": 100,
            "lines": [
              {
                "line": 72,
                "text": "                    (0.5 + startDelayMS / 1000.0) * JS8_RX_SAMPLE_RATE)),"
              },
              {
                "line": 73,
                "text": "          m_dataDuration(m_samplesForSymbols / (double)JS8_RX_SAMPLE_RATE),"
              },
              {
                "line": 74,
                "text": "          m_txDuration(m_dataDuration + startDelayMS / 1000.0) {}"
              },
              {
                "line": 75,
                "text": ""
              },
              {
                "line": 76,
                "text": "    // Inline accessors"
              },
              {
                "line": 77,
                "text": ""
              },
              {
                "line": 78,
                "text": "    constexpr const char *name() const { return m_name; }"
              },
              {
                "line": 79,
                "text": "    constexpr unsigned int samplesForOneSymbol() const {"
              },
              {
                "line": 80,
                "text": "        return m_samplesForOneSymbol;"
              },
              {
                "line": 81,
                "text": "    }"
              },
              {
                "line": 82,
                "text": "    constexpr unsigned int startDelayMS() const { return m_startDelayMS; }"
              },
              {
                "line": 83,
                "text": "    constexpr unsigned int period() const { return m_period; }"
              },
              {
                "line": 84,
                "text": "    constexpr Costas::Type costas() const { return m_costas; }"
              },
              {
                "line": 85,
                "text": "    constexpr int rxSNRThreshold() const { return m_rxSNRThreshold; }"
              },
              {
                "line": 86,
                "text": "    constexpr int rxThreshold() const { return m_rxThreshold; }"
              },
              {
                "line": 87,
                "text": "    constexpr int samplesForSymbols() const { return m_samplesForSymbols; }"
              },
              {
                "line": 88,
                "text": "    constexpr int bandwidth() const { return m_bandwidth; }"
              },
              {
                "line": 89,
                "text": "    constexpr int samplesPerPeriod() const { return m_samplesPerPeriod; }"
              },
              {
                "line": 90,
                "text": "    constexpr int samplesNeeded() const { return m_samplesNeeded; }"
              },
              {
                "line": 91,
                "text": "    constexpr double dataDuration() const { return m_dataDuration; }"
              },
              {
                "line": 92,
                "text": "    constexpr double toneSpacing() const { return m_toneSpacing; }"
              },
              {
                "line": 93,
                "text": "    constexpr double txDuration() const { return m_txDuration; }"
              },
              {
                "line": 94,
                "text": ""
              },
              {
                "line": 95,
                "text": "  private:"
              },
              {
                "line": 96,
                "text": "    // Data members ** ORDER DEPENDENCY **"
              },
              {
                "line": 97,
                "text": ""
              },
              {
                "line": 98,
                "text": "    const char *m_name;"
              },
              {
                "line": 99,
                "text": "    unsigned int m_samplesForOneSymbol;"
              },
              {
                "line": 100,
                "text": "    unsigned int m_startDelayMS;"
              }
            ]
          }
        },
        {
          "function": "samplesForSymbols",
          "line": 87,
          "signature": "constexpr int samplesForSymbols() const { return m_samplesForSymbols; }",
          "snippet": {
            "start_line": 73,
            "end_line": 101,
            "lines": [
              {
                "line": 73,
                "text": "          m_dataDuration(m_samplesForSymbols / (double)JS8_RX_SAMPLE_RATE),"
              },
              {
                "line": 74,
                "text": "          m_txDuration(m_dataDuration + startDelayMS / 1000.0) {}"
              },
              {
                "line": 75,
                "text": ""
              },
              {
                "line": 76,
                "text": "    // Inline accessors"
              },
              {
                "line": 77,
                "text": ""
              },
              {
                "line": 78,
                "text": "    constexpr const char *name() const { return m_name; }"
              },
              {
                "line": 79,
                "text": "    constexpr unsigned int samplesForOneSymbol() const {"
              },
              {
                "line": 80,
                "text": "        return m_samplesForOneSymbol;"
              },
              {
                "line": 81,
                "text": "    }"
              },
              {
                "line": 82,
                "text": "    constexpr unsigned int startDelayMS() const { return m_startDelayMS; }"
              },
              {
                "line": 83,
                "text": "    constexpr unsigned int period() const { return m_period; }"
              },
              {
                "line": 84,
                "text": "    constexpr Costas::Type costas() const { return m_costas; }"
              },
              {
                "line": 85,
                "text": "    constexpr int rxSNRThreshold() const { return m_rxSNRThreshold; }"
              },
              {
                "line": 86,
                "text": "    constexpr int rxThreshold() const { return m_rxThreshold; }"
              },
              {
                "line": 87,
                "text": "    constexpr int samplesForSymbols() const { return m_samplesForSymbols; }"
              },
              {
                "line": 88,
                "text": "    constexpr int bandwidth() const { return m_bandwidth; }"
              },
              {
                "line": 89,
                "text": "    constexpr int samplesPerPeriod() const { return m_samplesPerPeriod; }"
              },
              {
                "line": 90,
                "text": "    constexpr int samplesNeeded() const { return m_samplesNeeded; }"
              },
              {
                "line": 91,
                "text": "    constexpr double dataDuration() const { return m_dataDuration; }"
              },
              {
                "line": 92,
                "text": "    constexpr double toneSpacing() const { return m_toneSpacing; }"
              },
              {
                "line": 93,
                "text": "    constexpr double txDuration() const { return m_txDuration; }"
              },
              {
                "line": 94,
                "text": ""
              },
              {
                "line": 95,
                "text": "  private:"
              },
              {
                "line": 96,
                "text": "    // Data members ** ORDER DEPENDENCY **"
              },
              {
                "line": 97,
                "text": ""
              },
              {
                "line": 98,
                "text": "    const char *m_name;"
              },
              {
                "line": 99,
                "text": "    unsigned int m_samplesForOneSymbol;"
              },
              {
                "line": 100,
                "text": "    unsigned int m_startDelayMS;"
              },
              {
                "line": 101,
                "text": "    unsigned int m_period;"
              }
            ]
          }
        },
        {
          "function": "bandwidth",
          "line": 88,
          "signature": "constexpr int bandwidth() const { return m_bandwidth; }",
          "snippet": {
            "start_line": 74,
            "end_line": 102,
            "lines": [
              {
                "line": 74,
                "text": "          m_txDuration(m_dataDuration + startDelayMS / 1000.0) {}"
              },
              {
                "line": 75,
                "text": ""
              },
              {
                "line": 76,
                "text": "    // Inline accessors"
              },
              {
                "line": 77,
                "text": ""
              },
              {
                "line": 78,
                "text": "    constexpr const char *name() const { return m_name; }"
              },
              {
                "line": 79,
                "text": "    constexpr unsigned int samplesForOneSymbol() const {"
              },
              {
                "line": 80,
                "text": "        return m_samplesForOneSymbol;"
              },
              {
                "line": 81,
                "text": "    }"
              },
              {
                "line": 82,
                "text": "    constexpr unsigned int startDelayMS() const { return m_startDelayMS; }"
              },
              {
                "line": 83,
                "text": "    constexpr unsigned int period() const { return m_period; }"
              },
              {
                "line": 84,
                "text": "    constexpr Costas::Type costas() const { return m_costas; }"
              },
              {
                "line": 85,
                "text": "    constexpr int rxSNRThreshold() const { return m_rxSNRThreshold; }"
              },
              {
                "line": 86,
                "text": "    constexpr int rxThreshold() const { return m_rxThreshold; }"
              },
              {
                "line": 87,
                "text": "    constexpr int samplesForSymbols() const { return m_samplesForSymbols; }"
              },
              {
                "line": 88,
                "text": "    constexpr int bandwidth() const { return m_bandwidth; }"
              },
              {
                "line": 89,
                "text": "    constexpr int samplesPerPeriod() const { return m_samplesPerPeriod; }"
              },
              {
                "line": 90,
                "text": "    constexpr int samplesNeeded() const { return m_samplesNeeded; }"
              },
              {
                "line": 91,
                "text": "    constexpr double dataDuration() const { return m_dataDuration; }"
              },
              {
                "line": 92,
                "text": "    constexpr double toneSpacing() const { return m_toneSpacing; }"
              },
              {
                "line": 93,
                "text": "    constexpr double txDuration() const { return m_txDuration; }"
              },
              {
                "line": 94,
                "text": ""
              },
              {
                "line": 95,
                "text": "  private:"
              },
              {
                "line": 96,
                "text": "    // Data members ** ORDER DEPENDENCY **"
              },
              {
                "line": 97,
                "text": ""
              },
              {
                "line": 98,
                "text": "    const char *m_name;"
              },
              {
                "line": 99,
                "text": "    unsigned int m_samplesForOneSymbol;"
              },
              {
                "line": 100,
                "text": "    unsigned int m_startDelayMS;"
              },
              {
                "line": 101,
                "text": "    unsigned int m_period;"
              },
              {
                "line": 102,
                "text": "    Costas::Type m_costas;"
              }
            ]
          }
        },
        {
          "function": "samplesPerPeriod",
          "line": 89,
          "signature": "constexpr int samplesPerPeriod() const { return m_samplesPerPeriod; }",
          "snippet": {
            "start_line": 75,
            "end_line": 103,
            "lines": [
              {
                "line": 75,
                "text": ""
              },
              {
                "line": 76,
                "text": "    // Inline accessors"
              },
              {
                "line": 77,
                "text": ""
              },
              {
                "line": 78,
                "text": "    constexpr const char *name() const { return m_name; }"
              },
              {
                "line": 79,
                "text": "    constexpr unsigned int samplesForOneSymbol() const {"
              },
              {
                "line": 80,
                "text": "        return m_samplesForOneSymbol;"
              },
              {
                "line": 81,
                "text": "    }"
              },
              {
                "line": 82,
                "text": "    constexpr unsigned int startDelayMS() const { return m_startDelayMS; }"
              },
              {
                "line": 83,
                "text": "    constexpr unsigned int period() const { return m_period; }"
              },
              {
                "line": 84,
                "text": "    constexpr Costas::Type costas() const { return m_costas; }"
              },
              {
                "line": 85,
                "text": "    constexpr int rxSNRThreshold() const { return m_rxSNRThreshold; }"
              },
              {
                "line": 86,
                "text": "    constexpr int rxThreshold() const { return m_rxThreshold; }"
              },
              {
                "line": 87,
                "text": "    constexpr int samplesForSymbols() const { return m_samplesForSymbols; }"
              },
              {
                "line": 88,
                "text": "    constexpr int bandwidth() const { return m_bandwidth; }"
              },
              {
                "line": 89,
                "text": "    constexpr int samplesPerPeriod() const { return m_samplesPerPeriod; }"
              },
              {
                "line": 90,
                "text": "    constexpr int samplesNeeded() const { return m_samplesNeeded; }"
              },
              {
                "line": 91,
                "text": "    constexpr double dataDuration() const { return m_dataDuration; }"
              },
              {
                "line": 92,
                "text": "    constexpr double toneSpacing() const { return m_toneSpacing; }"
              },
              {
                "line": 93,
                "text": "    constexpr double txDuration() const { return m_txDuration; }"
              },
              {
                "line": 94,
                "text": ""
              },
              {
                "line": 95,
                "text": "  private:"
              },
              {
                "line": 96,
                "text": "    // Data members ** ORDER DEPENDENCY **"
              },
              {
                "line": 97,
                "text": ""
              },
              {
                "line": 98,
                "text": "    const char *m_name;"
              },
              {
                "line": 99,
                "text": "    unsigned int m_samplesForOneSymbol;"
              },
              {
                "line": 100,
                "text": "    unsigned int m_startDelayMS;"
              },
              {
                "line": 101,
                "text": "    unsigned int m_period;"
              },
              {
                "line": 102,
                "text": "    Costas::Type m_costas;"
              },
              {
                "line": 103,
                "text": "    int m_rxSNRThreshold;"
              }
            ]
          }
        },
        {
          "function": "samplesNeeded",
          "line": 90,
          "signature": "constexpr int samplesNeeded() const { return m_samplesNeeded; }",
          "snippet": {
            "start_line": 76,
            "end_line": 104,
            "lines": [
              {
                "line": 76,
                "text": "    // Inline accessors"
              },
              {
                "line": 77,
                "text": ""
              },
              {
                "line": 78,
                "text": "    constexpr const char *name() const { return m_name; }"
              },
              {
                "line": 79,
                "text": "    constexpr unsigned int samplesForOneSymbol() const {"
              },
              {
                "line": 80,
                "text": "        return m_samplesForOneSymbol;"
              },
              {
                "line": 81,
                "text": "    }"
              },
              {
                "line": 82,
                "text": "    constexpr unsigned int startDelayMS() const { return m_startDelayMS; }"
              },
              {
                "line": 83,
                "text": "    constexpr unsigned int period() const { return m_period; }"
              },
              {
                "line": 84,
                "text": "    constexpr Costas::Type costas() const { return m_costas; }"
              },
              {
                "line": 85,
                "text": "    constexpr int rxSNRThreshold() const { return m_rxSNRThreshold; }"
              },
              {
                "line": 86,
                "text": "    constexpr int rxThreshold() const { return m_rxThreshold; }"
              },
              {
                "line": 87,
                "text": "    constexpr int samplesForSymbols() const { return m_samplesForSymbols; }"
              },
              {
                "line": 88,
                "text": "    constexpr int bandwidth() const { return m_bandwidth; }"
              },
              {
                "line": 89,
                "text": "    constexpr int samplesPerPeriod() const { return m_samplesPerPeriod; }"
              },
              {
                "line": 90,
                "text": "    constexpr int samplesNeeded() const { return m_samplesNeeded; }"
              },
              {
                "line": 91,
                "text": "    constexpr double dataDuration() const { return m_dataDuration; }"
              },
              {
                "line": 92,
                "text": "    constexpr double toneSpacing() const { return m_toneSpacing; }"
              },
              {
                "line": 93,
                "text": "    constexpr double txDuration() const { return m_txDuration; }"
              },
              {
                "line": 94,
                "text": ""
              },
              {
                "line": 95,
                "text": "  private:"
              },
              {
                "line": 96,
                "text": "    // Data members ** ORDER DEPENDENCY **"
              },
              {
                "line": 97,
                "text": ""
              },
              {
                "line": 98,
                "text": "    const char *m_name;"
              },
              {
                "line": 99,
                "text": "    unsigned int m_samplesForOneSymbol;"
              },
              {
                "line": 100,
                "text": "    unsigned int m_startDelayMS;"
              },
              {
                "line": 101,
                "text": "    unsigned int m_period;"
              },
              {
                "line": 102,
                "text": "    Costas::Type m_costas;"
              },
              {
                "line": 103,
                "text": "    int m_rxSNRThreshold;"
              },
              {
                "line": 104,
                "text": "    int m_rxThreshold;"
              }
            ]
          }
        },
        {
          "function": "dataDuration",
          "line": 91,
          "signature": "constexpr double dataDuration() const { return m_dataDuration; }",
          "snippet": {
            "start_line": 77,
            "end_line": 105,
            "lines": [
              {
                "line": 77,
                "text": ""
              },
              {
                "line": 78,
                "text": "    constexpr const char *name() const { return m_name; }"
              },
              {
                "line": 79,
                "text": "    constexpr unsigned int samplesForOneSymbol() const {"
              },
              {
                "line": 80,
                "text": "        return m_samplesForOneSymbol;"
              },
              {
                "line": 81,
                "text": "    }"
              },
              {
                "line": 82,
                "text": "    constexpr unsigned int startDelayMS() const { return m_startDelayMS; }"
              },
              {
                "line": 83,
                "text": "    constexpr unsigned int period() const { return m_period; }"
              },
              {
                "line": 84,
                "text": "    constexpr Costas::Type costas() const { return m_costas; }"
              },
              {
                "line": 85,
                "text": "    constexpr int rxSNRThreshold() const { return m_rxSNRThreshold; }"
              },
              {
                "line": 86,
                "text": "    constexpr int rxThreshold() const { return m_rxThreshold; }"
              },
              {
                "line": 87,
                "text": "    constexpr int samplesForSymbols() const { return m_samplesForSymbols; }"
              },
              {
                "line": 88,
                "text": "    constexpr int bandwidth() const { return m_bandwidth; }"
              },
              {
                "line": 89,
                "text": "    constexpr int samplesPerPeriod() const { return m_samplesPerPeriod; }"
              },
              {
                "line": 90,
                "text": "    constexpr int samplesNeeded() const { return m_samplesNeeded; }"
              },
              {
                "line": 91,
                "text": "    constexpr double dataDuration() const { return m_dataDuration; }"
              },
              {
                "line": 92,
                "text": "    constexpr double toneSpacing() const { return m_toneSpacing; }"
              },
              {
                "line": 93,
                "text": "    constexpr double txDuration() const { return m_txDuration; }"
              },
              {
                "line": 94,
                "text": ""
              },
              {
                "line": 95,
                "text": "  private:"
              },
              {
                "line": 96,
                "text": "    // Data members ** ORDER DEPENDENCY **"
              },
              {
                "line": 97,
                "text": ""
              },
              {
                "line": 98,
                "text": "    const char *m_name;"
              },
              {
                "line": 99,
                "text": "    unsigned int m_samplesForOneSymbol;"
              },
              {
                "line": 100,
                "text": "    unsigned int m_startDelayMS;"
              },
              {
                "line": 101,
                "text": "    unsigned int m_period;"
              },
              {
                "line": 102,
                "text": "    Costas::Type m_costas;"
              },
              {
                "line": 103,
                "text": "    int m_rxSNRThreshold;"
              },
              {
                "line": 104,
                "text": "    int m_rxThreshold;"
              },
              {
                "line": 105,
                "text": "    int m_samplesForSymbols;"
              }
            ]
          }
        }
      ],
      "keyword_snippets": [
        {
          "line": 2,
          "matches": [
            "submode"
          ],
          "snippet": {
            "start_line": 1,
            "end_line": 8,
            "lines": [
              {
                "line": 1,
                "text": "/**"
              },
              {
                "line": 2,
                "text": " * @file JS8Submode.cpp"
              },
              {
                "line": 3,
                "text": " * @brief Implementation of JS8 submode parameter inquiry functions"
              },
              {
                "line": 4,
                "text": " */"
              },
              {
                "line": 5,
                "text": "#include \"JS8Submode.h\""
              },
              {
                "line": 6,
                "text": "#include \"JS8_Include/commons.h\""
              },
              {
                "line": 7,
                "text": "#include \"JS8_Main/Varicode.h\""
              },
              {
                "line": 8,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 17,
          "matches": [
            "submode"
          ],
          "snippet": {
            "start_line": 11,
            "end_line": 23,
            "lines": [
              {
                "line": 11,
                "text": "#include <concepts>"
              },
              {
                "line": 12,
                "text": ""
              },
              {
                "line": 13,
                "text": "/******************************************************************************/"
              },
              {
                "line": 14,
                "text": "// Private Implementation"
              },
              {
                "line": 15,
                "text": "/******************************************************************************/"
              },
              {
                "line": 16,
                "text": ""
              },
              {
                "line": 17,
                "text": "Q_DECLARE_LOGGING_CATEGORY(js8submode_js8)"
              },
              {
                "line": 18,
                "text": ""
              },
              {
                "line": 19,
                "text": "namespace JS8::Submode {"
              },
              {
                "line": 20,
                "text": "namespace {"
              },
              {
                "line": 21,
                "text": "// std::floor doesn't become constexpr until C++23; until then, our own"
              },
              {
                "line": 22,
                "text": "// implementation. We only use this for computation of the number of"
              },
              {
                "line": 23,
                "text": "// frames needed for a submode, so it doesn't need to be complicated."
              }
            ]
          }
        },
        {
          "line": 23,
          "matches": [
            "submode"
          ],
          "snippet": {
            "start_line": 17,
            "end_line": 29,
            "lines": [
              {
                "line": 17,
                "text": "Q_DECLARE_LOGGING_CATEGORY(js8submode_js8)"
              },
              {
                "line": 18,
                "text": ""
              },
              {
                "line": 19,
                "text": "namespace JS8::Submode {"
              },
              {
                "line": 20,
                "text": "namespace {"
              },
              {
                "line": 21,
                "text": "// std::floor doesn't become constexpr until C++23; until then, our own"
              },
              {
                "line": 22,
                "text": "// implementation. We only use this for computation of the number of"
              },
              {
                "line": 23,
                "text": "// frames needed for a submode, so it doesn't need to be complicated."
              },
              {
                "line": 24,
                "text": ""
              },
              {
                "line": 25,
                "text": "template <std::floating_point T> constexpr int floor(T const v) {"
              },
              {
                "line": 26,
                "text": "    auto const i = static_cast<int>(v);"
              },
              {
                "line": 27,
                "text": "    return v < i ? i - 1 : i;"
              },
              {
                "line": 28,
                "text": "}"
              },
              {
                "line": 29,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 46,
          "matches": [
            "submode"
          ],
          "snippet": {
            "start_line": 40,
            "end_line": 52,
            "lines": [
              {
                "line": 40,
                "text": "static_assert(floor(-0.5) == -1);"
              },
              {
                "line": 41,
                "text": "static_assert(floor(-0.999999) == -1);"
              },
              {
                "line": 42,
                "text": "static_assert(floor(-1.0) == -1);"
              },
              {
                "line": 43,
                "text": "static_assert(floor(-123.0) == -123);"
              },
              {
                "line": 44,
                "text": "static_assert(floor(-123.4) == -124);"
              },
              {
                "line": 45,
                "text": ""
              },
              {
                "line": 46,
                "text": "// Data that describes a JS8 submode. Anything here should be able to be"
              },
              {
                "line": 47,
                "text": "// completely determined at compile time, i.e., any instance of this is"
              },
              {
                "line": 48,
                "text": "// just constant data."
              },
              {
                "line": 49,
                "text": ""
              },
              {
                "line": 50,
                "text": "class Data {"
              },
              {
                "line": 51,
                "text": "  public:"
              },
              {
                "line": 52,
                "text": "    // Constructor; in addition to the basics provided by the constructor"
              }
            ]
          }
        },
        {
          "line": 59,
          "matches": [
            "samplesForOneSymbol"
          ],
          "snippet": {
            "start_line": 53,
            "end_line": 65,
            "lines": [
              {
                "line": 53,
                "text": "    // parameters, we'll determine various convenience constants in order"
              },
              {
                "line": 54,
                "text": "    // to simplify calling code. These derived values depend only on the"
              },
              {
                "line": 55,
                "text": "    // JS8_NUM_SYMBOLS and RX_SAMPLE_RATE definitions, and therefore can"
              },
              {
                "line": 56,
                "text": "    // be entirely computed at compile time."
              },
              {
                "line": 57,
                "text": ""
              },
              {
                "line": 58,
                "text": "    constexpr Data(const char *const name,"
              },
              {
                "line": 59,
                "text": "                   unsigned int const samplesForOneSymbol,"
              },
              {
                "line": 60,
                "text": "                   unsigned int const startDelayMS, unsigned int const period,"
              },
              {
                "line": 61,
                "text": "                   Costas::Type const costas, int const rxSNRThreshold,"
              },
              {
                "line": 62,
                "text": "                   int const rxThreshold = 10)"
              },
              {
                "line": 63,
                "text": "        : m_name(name), m_samplesForOneSymbol(samplesForOneSymbol),"
              },
              {
                "line": 64,
                "text": "          m_startDelayMS(startDelayMS), m_period(period), m_costas(costas),"
              },
              {
                "line": 65,
                "text": "          m_rxSNRThreshold(rxSNRThreshold), m_rxThreshold(rxThreshold),"
              }
            ]
          }
        },
        {
          "line": 63,
          "matches": [
            "samplesForOneSymbol"
          ],
          "snippet": {
            "start_line": 57,
            "end_line": 69,
            "lines": [
              {
                "line": 57,
                "text": ""
              },
              {
                "line": 58,
                "text": "    constexpr Data(const char *const name,"
              },
              {
                "line": 59,
                "text": "                   unsigned int const samplesForOneSymbol,"
              },
              {
                "line": 60,
                "text": "                   unsigned int const startDelayMS, unsigned int const period,"
              },
              {
                "line": 61,
                "text": "                   Costas::Type const costas, int const rxSNRThreshold,"
              },
              {
                "line": 62,
                "text": "                   int const rxThreshold = 10)"
              },
              {
                "line": 63,
                "text": "        : m_name(name), m_samplesForOneSymbol(samplesForOneSymbol),"
              },
              {
                "line": 64,
                "text": "          m_startDelayMS(startDelayMS), m_period(period), m_costas(costas),"
              },
              {
                "line": 65,
                "text": "          m_rxSNRThreshold(rxSNRThreshold), m_rxThreshold(rxThreshold),"
              },
              {
                "line": 66,
                "text": "          m_samplesForSymbols(JS8_NUM_SYMBOLS * samplesForOneSymbol),"
              },
              {
                "line": 67,
                "text": "          m_bandwidth(8 * JS8_RX_SAMPLE_RATE / samplesForOneSymbol),"
              },
              {
                "line": 68,
                "text": "          m_samplesPerPeriod(JS8_RX_SAMPLE_RATE * period),"
              },
              {
                "line": 69,
                "text": "          m_toneSpacing(JS8_RX_SAMPLE_RATE / (double)samplesForOneSymbol),"
              }
            ]
          }
        },
        {
          "line": 66,
          "matches": [
            "samplesForOneSymbol"
          ],
          "snippet": {
            "start_line": 60,
            "end_line": 72,
            "lines": [
              {
                "line": 60,
                "text": "                   unsigned int const startDelayMS, unsigned int const period,"
              },
              {
                "line": 61,
                "text": "                   Costas::Type const costas, int const rxSNRThreshold,"
              },
              {
                "line": 62,
                "text": "                   int const rxThreshold = 10)"
              },
              {
                "line": 63,
                "text": "        : m_name(name), m_samplesForOneSymbol(samplesForOneSymbol),"
              },
              {
                "line": 64,
                "text": "          m_startDelayMS(startDelayMS), m_period(period), m_costas(costas),"
              },
              {
                "line": 65,
                "text": "          m_rxSNRThreshold(rxSNRThreshold), m_rxThreshold(rxThreshold),"
              },
              {
                "line": 66,
                "text": "          m_samplesForSymbols(JS8_NUM_SYMBOLS * samplesForOneSymbol),"
              },
              {
                "line": 67,
                "text": "          m_bandwidth(8 * JS8_RX_SAMPLE_RATE / samplesForOneSymbol),"
              },
              {
                "line": 68,
                "text": "          m_samplesPerPeriod(JS8_RX_SAMPLE_RATE * period),"
              },
              {
                "line": 69,
                "text": "          m_toneSpacing(JS8_RX_SAMPLE_RATE / (double)samplesForOneSymbol),"
              },
              {
                "line": 70,
                "text": "          m_samplesNeeded("
              },
              {
                "line": 71,
                "text": "              floor(m_samplesForSymbols +"
              },
              {
                "line": 72,
                "text": "                    (0.5 + startDelayMS / 1000.0) * JS8_RX_SAMPLE_RATE)),"
              }
            ]
          }
        },
        {
          "line": 79,
          "matches": [
            "samplesForOneSymbol"
          ],
          "snippet": {
            "start_line": 73,
            "end_line": 85,
            "lines": [
              {
                "line": 73,
                "text": "          m_dataDuration(m_samplesForSymbols / (double)JS8_RX_SAMPLE_RATE),"
              },
              {
                "line": 74,
                "text": "          m_txDuration(m_dataDuration + startDelayMS / 1000.0) {}"
              },
              {
                "line": 75,
                "text": ""
              },
              {
                "line": 76,
                "text": "    // Inline accessors"
              },
              {
                "line": 77,
                "text": ""
              },
              {
                "line": 78,
                "text": "    constexpr const char *name() const { return m_name; }"
              },
              {
                "line": 79,
                "text": "    constexpr unsigned int samplesForOneSymbol() const {"
              },
              {
                "line": 80,
                "text": "        return m_samplesForOneSymbol;"
              },
              {
                "line": 81,
                "text": "    }"
              },
              {
                "line": 82,
                "text": "    constexpr unsigned int startDelayMS() const { return m_startDelayMS; }"
              },
              {
                "line": 83,
                "text": "    constexpr unsigned int period() const { return m_period; }"
              },
              {
                "line": 84,
                "text": "    constexpr Costas::Type costas() const { return m_costas; }"
              },
              {
                "line": 85,
                "text": "    constexpr int rxSNRThreshold() const { return m_rxSNRThreshold; }"
              }
            ]
          }
        },
        {
          "line": 92,
          "matches": [
            "toneSpacing"
          ],
          "snippet": {
            "start_line": 86,
            "end_line": 98,
            "lines": [
              {
                "line": 86,
                "text": "    constexpr int rxThreshold() const { return m_rxThreshold; }"
              },
              {
                "line": 87,
                "text": "    constexpr int samplesForSymbols() const { return m_samplesForSymbols; }"
              },
              {
                "line": 88,
                "text": "    constexpr int bandwidth() const { return m_bandwidth; }"
              },
              {
                "line": 89,
                "text": "    constexpr int samplesPerPeriod() const { return m_samplesPerPeriod; }"
              },
              {
                "line": 90,
                "text": "    constexpr int samplesNeeded() const { return m_samplesNeeded; }"
              },
              {
                "line": 91,
                "text": "    constexpr double dataDuration() const { return m_dataDuration; }"
              },
              {
                "line": 92,
                "text": "    constexpr double toneSpacing() const { return m_toneSpacing; }"
              },
              {
                "line": 93,
                "text": "    constexpr double txDuration() const { return m_txDuration; }"
              },
              {
                "line": 94,
                "text": ""
              },
              {
                "line": 95,
                "text": "  private:"
              },
              {
                "line": 96,
                "text": "    // Data members ** ORDER DEPENDENCY **"
              },
              {
                "line": 97,
                "text": ""
              },
              {
                "line": 98,
                "text": "    const char *m_name;"
              }
            ]
          }
        },
        {
          "line": 99,
          "matches": [
            "samplesForOneSymbol"
          ],
          "snippet": {
            "start_line": 93,
            "end_line": 105,
            "lines": [
              {
                "line": 93,
                "text": "    constexpr double txDuration() const { return m_txDuration; }"
              },
              {
                "line": 94,
                "text": ""
              },
              {
                "line": 95,
                "text": "  private:"
              },
              {
                "line": 96,
                "text": "    // Data members ** ORDER DEPENDENCY **"
              },
              {
                "line": 97,
                "text": ""
              },
              {
                "line": 98,
                "text": "    const char *m_name;"
              },
              {
                "line": 99,
                "text": "    unsigned int m_samplesForOneSymbol;"
              },
              {
                "line": 100,
                "text": "    unsigned int m_startDelayMS;"
              },
              {
                "line": 101,
                "text": "    unsigned int m_period;"
              },
              {
                "line": 102,
                "text": "    Costas::Type m_costas;"
              },
              {
                "line": 103,
                "text": "    int m_rxSNRThreshold;"
              },
              {
                "line": 104,
                "text": "    int m_rxThreshold;"
              },
              {
                "line": 105,
                "text": "    int m_samplesForSymbols;"
              }
            ]
          }
        },
        {
          "line": 108,
          "matches": [
            "toneSpacing"
          ],
          "snippet": {
            "start_line": 102,
            "end_line": 114,
            "lines": [
              {
                "line": 102,
                "text": "    Costas::Type m_costas;"
              },
              {
                "line": 103,
                "text": "    int m_rxSNRThreshold;"
              },
              {
                "line": 104,
                "text": "    int m_rxThreshold;"
              },
              {
                "line": 105,
                "text": "    int m_samplesForSymbols;"
              },
              {
                "line": 106,
                "text": "    int m_bandwidth;"
              },
              {
                "line": 107,
                "text": "    int m_samplesPerPeriod;"
              },
              {
                "line": 108,
                "text": "    double m_toneSpacing;"
              },
              {
                "line": 109,
                "text": "    int m_samplesNeeded;"
              },
              {
                "line": 110,
                "text": "    double m_dataDuration;"
              },
              {
                "line": 111,
                "text": "    double m_txDuration;"
              },
              {
                "line": 112,
                "text": "};"
              },
              {
                "line": 113,
                "text": ""
              },
              {
                "line": 114,
                "text": "// Data for known submodes. Normal mode uses the old Costas Array"
              }
            ]
          }
        },
        {
          "line": 114,
          "matches": [
            "submode"
          ],
          "snippet": {
            "start_line": 108,
            "end_line": 120,
            "lines": [
              {
                "line": 108,
                "text": "    double m_toneSpacing;"
              },
              {
                "line": 109,
                "text": "    int m_samplesNeeded;"
              },
              {
                "line": 110,
                "text": "    double m_dataDuration;"
              },
              {
                "line": 111,
                "text": "    double m_txDuration;"
              },
              {
                "line": 112,
                "text": "};"
              },
              {
                "line": 113,
                "text": ""
              },
              {
                "line": 114,
                "text": "// Data for known submodes. Normal mode uses the old Costas Array"
              },
              {
                "line": 115,
                "text": "// definition; all other modes use the new one."
              },
              {
                "line": 116,
                "text": ""
              },
              {
                "line": 117,
                "text": "constexpr Data Normal = {\"NORMAL\","
              },
              {
                "line": 118,
                "text": "                         JS8A_SYMBOL_SAMPLES,"
              },
              {
                "line": 119,
                "text": "                         JS8A_START_DELAY_MS,"
              },
              {
                "line": 120,
                "text": "                         JS8A_TX_SECONDS,"
              }
            ]
          }
        },
        {
          "line": 155,
          "matches": [
            "submode"
          ],
          "snippet": {
            "start_line": 149,
            "end_line": 161,
            "lines": [
              {
                "line": 149,
                "text": "                         JS8I_START_DELAY_MS,"
              },
              {
                "line": 150,
                "text": "                         JS8I_TX_SECONDS,"
              },
              {
                "line": 151,
                "text": "                         Costas::Type::MODIFIED,"
              },
              {
                "line": 152,
                "text": "                         -18,"
              },
              {
                "line": 153,
                "text": "                         50};"
              },
              {
                "line": 154,
                "text": ""
              },
              {
                "line": 155,
                "text": "// Given a submode, return data for it, or, if we don't have any idea"
              },
              {
                "line": 156,
                "text": "// what the caller is talking about, throw."
              },
              {
                "line": 157,
                "text": "//"
              },
              {
                "line": 158,
                "text": "// Note that the original code in all cases did its best to just carry"
              },
              {
                "line": 159,
                "text": "// on in the event of an invalid submode, e.g., by returning 0, etc.,"
              },
              {
                "line": 160,
                "text": "// but that approach will in general lead to things like division by"
              },
              {
                "line": 161,
                "text": "// zero in computeCycleForDecode(), below, so either way we're going"
              }
            ]
          }
        },
        {
          "line": 159,
          "matches": [
            "submode"
          ],
          "snippet": {
            "start_line": 153,
            "end_line": 165,
            "lines": [
              {
                "line": 153,
                "text": "                         50};"
              },
              {
                "line": 154,
                "text": ""
              },
              {
                "line": 155,
                "text": "// Given a submode, return data for it, or, if we don't have any idea"
              },
              {
                "line": 156,
                "text": "// what the caller is talking about, throw."
              },
              {
                "line": 157,
                "text": "//"
              },
              {
                "line": 158,
                "text": "// Note that the original code in all cases did its best to just carry"
              },
              {
                "line": 159,
                "text": "// on in the event of an invalid submode, e.g., by returning 0, etc.,"
              },
              {
                "line": 160,
                "text": "// but that approach will in general lead to things like division by"
              },
              {
                "line": 161,
                "text": "// zero in computeCycleForDecode(), below, so either way we're going"
              },
              {
                "line": 162,
                "text": "// to end up with a runtime error, and it seems preferable that it's"
              },
              {
                "line": 163,
                "text": "// an informative one."
              },
              {
                "line": 164,
                "text": "//"
              },
              {
                "line": 165,
                "text": "// Note that the Varicode::SubModeType enum is not dense, so we can't"
              }
            ]
          }
        },
        {
          "line": 165,
          "matches": [
            "submode"
          ],
          "snippet": {
            "start_line": 159,
            "end_line": 171,
            "lines": [
              {
                "line": 159,
                "text": "// on in the event of an invalid submode, e.g., by returning 0, etc.,"
              },
              {
                "line": 160,
                "text": "// but that approach will in general lead to things like division by"
              },
              {
                "line": 161,
                "text": "// zero in computeCycleForDecode(), below, so either way we're going"
              },
              {
                "line": 162,
                "text": "// to end up with a runtime error, and it seems preferable that it's"
              },
              {
                "line": 163,
                "text": "// an informative one."
              },
              {
                "line": 164,
                "text": "//"
              },
              {
                "line": 165,
                "text": "// Note that the Varicode::SubModeType enum is not dense, so we can't"
              },
              {
                "line": 166,
                "text": "// just do direct indexed access here."
              },
              {
                "line": 167,
                "text": ""
              },
              {
                "line": 168,
                "text": "constexpr Data const &data(int const submode) {"
              },
              {
                "line": 169,
                "text": "    switch (submode) {"
              },
              {
                "line": 170,
                "text": "    case Varicode::JS8CallNormal:"
              },
              {
                "line": 171,
                "text": "        return Normal;"
              }
            ]
          }
        },
        {
          "line": 168,
          "matches": [
            "submode"
          ],
          "snippet": {
            "start_line": 162,
            "end_line": 174,
            "lines": [
              {
                "line": 162,
                "text": "// to end up with a runtime error, and it seems preferable that it's"
              },
              {
                "line": 163,
                "text": "// an informative one."
              },
              {
                "line": 164,
                "text": "//"
              },
              {
                "line": 165,
                "text": "// Note that the Varicode::SubModeType enum is not dense, so we can't"
              },
              {
                "line": 166,
                "text": "// just do direct indexed access here."
              },
              {
                "line": 167,
                "text": ""
              },
              {
                "line": 168,
                "text": "constexpr Data const &data(int const submode) {"
              },
              {
                "line": 169,
                "text": "    switch (submode) {"
              },
              {
                "line": 170,
                "text": "    case Varicode::JS8CallNormal:"
              },
              {
                "line": 171,
                "text": "        return Normal;"
              },
              {
                "line": 172,
                "text": "    case Varicode::JS8CallFast:"
              },
              {
                "line": 173,
                "text": "        return Fast;"
              },
              {
                "line": 174,
                "text": "    case Varicode::JS8CallTurbo:"
              }
            ]
          }
        },
        {
          "line": 181,
          "matches": [
            "submode"
          ],
          "snippet": {
            "start_line": 175,
            "end_line": 187,
            "lines": [
              {
                "line": 175,
                "text": "        return Turbo;"
              },
              {
                "line": 176,
                "text": "    case Varicode::JS8CallSlow:"
              },
              {
                "line": 177,
                "text": "        return Slow;"
              },
              {
                "line": 178,
                "text": "    case Varicode::JS8CallUltra:"
              },
              {
                "line": 179,
                "text": "        return Ultra;"
              },
              {
                "line": 180,
                "text": "    default: {"
              },
              {
                "line": 181,
                "text": "        throw error{QObject::tr(\"Invalid JS8 submode %1\").arg(submode)};"
              },
              {
                "line": 182,
                "text": "    }"
              },
              {
                "line": 183,
                "text": "    }"
              },
              {
                "line": 184,
                "text": "};"
              },
              {
                "line": 185,
                "text": ""
              },
              {
                "line": 186,
                "text": "class ListDataAsDebugOutput {"
              },
              {
                "line": 187,
                "text": "  private:"
              }
            ]
          }
        },
        {
          "line": 189,
          "matches": [
            "submode"
          ],
          "snippet": {
            "start_line": 183,
            "end_line": 195,
            "lines": [
              {
                "line": 183,
                "text": "    }"
              },
              {
                "line": 184,
                "text": "};"
              },
              {
                "line": 185,
                "text": ""
              },
              {
                "line": 186,
                "text": "class ListDataAsDebugOutput {"
              },
              {
                "line": 187,
                "text": "  private:"
              },
              {
                "line": 188,
                "text": "    inline void list_one_mode(Data data) {"
              },
              {
                "line": 189,
                "text": "        qCDebug(js8submode_js8)"
              },
              {
                "line": 190,
                "text": "            << \"\\nname               \" << data.name() << \"\\nsamplesForOneSymbol\""
              },
              {
                "line": 191,
                "text": "            << data.samplesForOneSymbol() << \"\\nstartDelayMS       \""
              },
              {
                "line": 192,
                "text": "            << data.startDelayMS() << \"\\nperiod             \" << data.period()"
              },
              {
                "line": 193,
                "text": "            << \"\\ncostas             \""
              },
              {
                "line": 194,
                "text": "            << (data.costas() == Costas::Type::MODIFIED"
              },
              {
                "line": 195,
                "text": "                    ? \"MODIFIED\""
              }
            ]
          }
        },
        {
          "line": 191,
          "matches": [
            "samplesForOneSymbol"
          ],
          "snippet": {
            "start_line": 185,
            "end_line": 197,
            "lines": [
              {
                "line": 185,
                "text": ""
              },
              {
                "line": 186,
                "text": "class ListDataAsDebugOutput {"
              },
              {
                "line": 187,
                "text": "  private:"
              },
              {
                "line": 188,
                "text": "    inline void list_one_mode(Data data) {"
              },
              {
                "line": 189,
                "text": "        qCDebug(js8submode_js8)"
              },
              {
                "line": 190,
                "text": "            << \"\\nname               \" << data.name() << \"\\nsamplesForOneSymbol\""
              },
              {
                "line": 191,
                "text": "            << data.samplesForOneSymbol() << \"\\nstartDelayMS       \""
              },
              {
                "line": 192,
                "text": "            << data.startDelayMS() << \"\\nperiod             \" << data.period()"
              },
              {
                "line": 193,
                "text": "            << \"\\ncostas             \""
              },
              {
                "line": 194,
                "text": "            << (data.costas() == Costas::Type::MODIFIED"
              },
              {
                "line": 195,
                "text": "                    ? \"MODIFIED\""
              },
              {
                "line": 196,
                "text": "                    : (data.costas() == Costas::Type::ORIGINAL ? \"ORIGINAL\""
              },
              {
                "line": 197,
                "text": "                                                               : \"????\"))"
              }
            ]
          }
        },
        {
          "line": 205,
          "matches": [
            "toneSpacing"
          ],
          "snippet": {
            "start_line": 199,
            "end_line": 211,
            "lines": [
              {
                "line": 199,
                "text": "            << \"\\nrxThreshold        \" << data.rxThreshold()"
              },
              {
                "line": 200,
                "text": "            << \"\\nsamplesForSymbols  \" << data.samplesForSymbols()"
              },
              {
                "line": 201,
                "text": "            << \"\\nbandwidth          \" << data.bandwidth()"
              },
              {
                "line": 202,
                "text": "            << \"\\nsamplesPerPeriod   \" << data.samplesPerPeriod()"
              },
              {
                "line": 203,
                "text": "            << \"\\nsamplesNeeded      \" << data.samplesNeeded()"
              },
              {
                "line": 204,
                "text": "            << \"\\ndataDuration       \" << data.dataDuration()"
              },
              {
                "line": 205,
                "text": "            << \"\\ntoneSpacing        \" << data.toneSpacing()"
              },
              {
                "line": 206,
                "text": "            << \"\\ntxDuration         \" << data.txDuration() << \"\\n\";"
              },
              {
                "line": 207,
                "text": "    }"
              },
              {
                "line": 208,
                "text": ""
              },
              {
                "line": 209,
                "text": "  public:"
              },
              {
                "line": 210,
                "text": "    inline ListDataAsDebugOutput() {"
              },
              {
                "line": 211,
                "text": "        list_one_mode(Slow);"
              }
            ]
          }
        },
        {
          "line": 222,
          "matches": [
            "submode"
          ],
          "snippet": {
            "start_line": 216,
            "end_line": 228,
            "lines": [
              {
                "line": 216,
                "text": "    }"
              },
              {
                "line": 217,
                "text": "};"
              },
              {
                "line": 218,
                "text": ""
              },
              {
                "line": 219,
                "text": "static ListDataAsDebugOutput list_data_as_debug_output ="
              },
              {
                "line": 220,
                "text": "    ListDataAsDebugOutput{};"
              },
              {
                "line": 221,
                "text": "} // namespace"
              },
              {
                "line": 222,
                "text": "} // namespace JS8::Submode"
              },
              {
                "line": 223,
                "text": ""
              },
              {
                "line": 224,
                "text": "/******************************************************************************/"
              },
              {
                "line": 225,
                "text": "// Public Implementation"
              },
              {
                "line": 226,
                "text": "/******************************************************************************/"
              },
              {
                "line": 227,
                "text": "/**"
              },
              {
                "line": 228,
                "text": " * @brief JS8 Submode namespace implementation"
              }
            ]
          }
        },
        {
          "line": 228,
          "matches": [
            "submode"
          ],
          "snippet": {
            "start_line": 222,
            "end_line": 234,
            "lines": [
              {
                "line": 222,
                "text": "} // namespace JS8::Submode"
              },
              {
                "line": 223,
                "text": ""
              },
              {
                "line": 224,
                "text": "/******************************************************************************/"
              },
              {
                "line": 225,
                "text": "// Public Implementation"
              },
              {
                "line": 226,
                "text": "/******************************************************************************/"
              },
              {
                "line": 227,
                "text": "/**"
              },
              {
                "line": 228,
                "text": " * @brief JS8 Submode namespace implementation"
              },
              {
                "line": 229,
                "text": " */"
              },
              {
                "line": 230,
                "text": "namespace JS8::Submode {"
              },
              {
                "line": 231,
                "text": "// Submode name inquiry function; return a translated value, if there is"
              },
              {
                "line": 232,
                "text": "// a translated value, otherwise, the untranslated mode name."
              },
              {
                "line": 233,
                "text": ""
              },
              {
                "line": 234,
                "text": "/**"
              }
            ]
          }
        }
      ]
    },
    {
      "path": "JS8_Mode/soft_combiner.h",
      "exists": true,
      "bytes": 9185,
      "sha256": "59a2c7dafab922a1aa93d7de7c57a50fa63d6fd900507c63233390de073218ea",
      "line_count": 294,
      "phase_hits": {
        "timing_submode": 0,
        "symbol_to_soft_bits": 109,
        "bit_order_interleaver": 5,
        "whitening_erasure": 4,
        "ldpc_decode": 0,
        "message91_crc_text": 0
      },
      "function_blocks": [
        {
          "function": "SoftCombiner",
          "line": 55,
          "signature": "explicit SoftCombiner(bool enabled, bool runSelfTest = true)",
          "snippet": {
            "start_line": 41,
            "end_line": 69,
            "lines": [
              {
                "line": 41,
                "text": "                   dtBin == other.dtBin && signature == other.signature;"
              },
              {
                "line": 42,
                "text": "        }"
              },
              {
                "line": 43,
                "text": "    };"
              },
              {
                "line": 44,
                "text": ""
              },
              {
                "line": 45,
                "text": "    struct Combined {"
              },
              {
                "line": 46,
                "text": "        Key key;"
              },
              {
                "line": 47,
                "text": "        std::array<float, N> llr0;"
              },
              {
                "line": 48,
                "text": "        std::array<float, N> llr1;"
              },
              {
                "line": 49,
                "text": "        int repeats;"
              },
              {
                "line": 50,
                "text": "        bool combined;"
              },
              {
                "line": 51,
                "text": "    };"
              },
              {
                "line": 52,
                "text": ""
              },
              {
                "line": 53,
                "text": "    SoftCombiner() : SoftCombiner(defaultEnabled(), true) {}"
              },
              {
                "line": 54,
                "text": ""
              },
              {
                "line": 55,
                "text": "    explicit SoftCombiner(bool enabled, bool runSelfTest = true)"
              },
              {
                "line": 56,
                "text": "        : m_enabled(enabled) {"
              },
              {
                "line": 57,
                "text": "        if (!m_enabled) {"
              },
              {
                "line": 58,
                "text": "            qCDebug(decoder_js8)"
              },
              {
                "line": 59,
                "text": "                << \"soft-combining disabled (JS8_SOFT_COMBINING=0)\";"
              },
              {
                "line": 60,
                "text": "        }"
              },
              {
                "line": 61,
                "text": "        if (runSelfTest)"
              },
              {
                "line": 62,
                "text": "            maybeRunSelfTest();"
              },
              {
                "line": 63,
                "text": "    }"
              },
              {
                "line": 64,
                "text": ""
              },
              {
                "line": 65,
                "text": "    Key makeKey(int mode, float f1, float dt, std::array<float, N> const &llr0,"
              },
              {
                "line": 66,
                "text": "                std::array<float, N> const &llr1) const {"
              },
              {
                "line": 67,
                "text": "        return Key{mode, static_cast<int>(std::lround(f1)),"
              },
              {
                "line": 68,
                "text": "                   static_cast<int>(std::lround(dt * 10.0f)), // 100 ms bins"
              },
              {
                "line": 69,
                "text": "                   signature(llr0, llr1)};"
              }
            ]
          }
        },
        {
          "function": "markDecoded",
          "line": 104,
          "signature": "void markDecoded(Key const &key) {",
          "snippet": {
            "start_line": 90,
            "end_line": 118,
            "lines": [
              {
                "line": 90,
                "text": "            it->llr0[i] += llr0[i];"
              },
              {
                "line": 91,
                "text": "            it->llr1[i] += llr1[i];"
              },
              {
                "line": 92,
                "text": "        }"
              },
              {
                "line": 93,
                "text": ""
              },
              {
                "line": 94,
                "text": "        ++it->repeats;"
              },
              {
                "line": 95,
                "text": "        it->lastSeen = Clock::now();"
              },
              {
                "line": 96,
                "text": ""
              },
              {
                "line": 97,
                "text": "        qCDebug(decoder_js8)"
              },
              {
                "line": 98,
                "text": "            << \"soft-combining repeats\" << it->repeats << \"mode\" << key.mode"
              },
              {
                "line": 99,
                "text": "            << \"freq\" << key.freqBin << \"dtbin\" << key.dtBin;"
              },
              {
                "line": 100,
                "text": ""
              },
              {
                "line": 101,
                "text": "        return Combined{key, it->llr0, it->llr1, it->repeats, true};"
              },
              {
                "line": 102,
                "text": "    }"
              },
              {
                "line": 103,
                "text": ""
              },
              {
                "line": 104,
                "text": "    void markDecoded(Key const &key) {"
              },
              {
                "line": 105,
                "text": "        if (!m_enabled)"
              },
              {
                "line": 106,
                "text": "            return;"
              },
              {
                "line": 107,
                "text": ""
              },
              {
                "line": 108,
                "text": "        auto lookup = keyForLookup(key);"
              },
              {
                "line": 109,
                "text": "        auto it = m_entries.find(lookup);"
              },
              {
                "line": 110,
                "text": ""
              },
              {
                "line": 111,
                "text": "        if (it == m_entries.end())"
              },
              {
                "line": 112,
                "text": "            return;"
              },
              {
                "line": 113,
                "text": ""
              },
              {
                "line": 114,
                "text": "        auto &bucket = it->second;"
              },
              {
                "line": 115,
                "text": "        bucket.erase(std::remove_if(bucket.begin(), bucket.end(),"
              },
              {
                "line": 116,
                "text": "                                    [&key](Entry const &entry) {"
              },
              {
                "line": 117,
                "text": "                                        return entry.signature == key.signature;"
              },
              {
                "line": 118,
                "text": "                                    }),"
              }
            ]
          }
        },
        {
          "function": "flush",
          "line": 125,
          "signature": "void flush(std::chrono::seconds ttl) {",
          "snippet": {
            "start_line": 111,
            "end_line": 139,
            "lines": [
              {
                "line": 111,
                "text": "        if (it == m_entries.end())"
              },
              {
                "line": 112,
                "text": "            return;"
              },
              {
                "line": 113,
                "text": ""
              },
              {
                "line": 114,
                "text": "        auto &bucket = it->second;"
              },
              {
                "line": 115,
                "text": "        bucket.erase(std::remove_if(bucket.begin(), bucket.end(),"
              },
              {
                "line": 116,
                "text": "                                    [&key](Entry const &entry) {"
              },
              {
                "line": 117,
                "text": "                                        return entry.signature == key.signature;"
              },
              {
                "line": 118,
                "text": "                                    }),"
              },
              {
                "line": 119,
                "text": "                     bucket.end());"
              },
              {
                "line": 120,
                "text": ""
              },
              {
                "line": 121,
                "text": "        if (bucket.empty())"
              },
              {
                "line": 122,
                "text": "            m_entries.erase(it);"
              },
              {
                "line": 123,
                "text": "    }"
              },
              {
                "line": 124,
                "text": ""
              },
              {
                "line": 125,
                "text": "    void flush(std::chrono::seconds ttl) {"
              },
              {
                "line": 126,
                "text": "        if (!m_enabled)"
              },
              {
                "line": 127,
                "text": "            return;"
              },
              {
                "line": 128,
                "text": ""
              },
              {
                "line": 129,
                "text": "        auto const now = Clock::now();"
              },
              {
                "line": 130,
                "text": ""
              },
              {
                "line": 131,
                "text": "        for (auto it = m_entries.begin(); it != m_entries.end();) {"
              },
              {
                "line": 132,
                "text": "            auto &bucket = it->second;"
              },
              {
                "line": 133,
                "text": ""
              },
              {
                "line": 134,
                "text": "            bucket.erase(std::remove_if(bucket.begin(), bucket.end(),"
              },
              {
                "line": 135,
                "text": "                                        [now, ttl](Entry const &entry) {"
              },
              {
                "line": 136,
                "text": "                                            return now - entry.lastSeen > ttl;"
              },
              {
                "line": 137,
                "text": "                                        }),"
              },
              {
                "line": 138,
                "text": "                         bucket.end());"
              },
              {
                "line": 139,
                "text": ""
              }
            ]
          }
        },
        {
          "function": "signatureIndices",
          "line": 178,
          "signature": "static constexpr auto signatureIndices() {",
          "snippet": {
            "start_line": 164,
            "end_line": 192,
            "lines": [
              {
                "line": 164,
                "text": "            return h1 ^ (h2 << 1) ^ (h3 << 2);"
              },
              {
                "line": 165,
                "text": "        }"
              },
              {
                "line": 166,
                "text": "    };"
              },
              {
                "line": 167,
                "text": ""
              },
              {
                "line": 168,
                "text": "    struct Entry {"
              },
              {
                "line": 169,
                "text": "        uint32_t signature;"
              },
              {
                "line": 170,
                "text": "        std::array<float, N> llr0;"
              },
              {
                "line": 171,
                "text": "        std::array<float, N> llr1;"
              },
              {
                "line": 172,
                "text": "        int repeats;"
              },
              {
                "line": 173,
                "text": "        Clock::time_point lastSeen;"
              },
              {
                "line": 174,
                "text": "    };"
              },
              {
                "line": 175,
                "text": ""
              },
              {
                "line": 176,
                "text": "    using Bucket = std::vector<Entry>;"
              },
              {
                "line": 177,
                "text": ""
              },
              {
                "line": 178,
                "text": "    static constexpr auto signatureIndices() {"
              },
              {
                "line": 179,
                "text": "        std::array<int, 32> indices{};"
              },
              {
                "line": 180,
                "text": "        int value = 0;"
              },
              {
                "line": 181,
                "text": "        for (std::size_t i = 0; i < indices.size(); ++i) {"
              },
              {
                "line": 182,
                "text": "            value = (value + 37) % static_cast<int>(N);"
              },
              {
                "line": 183,
                "text": "            indices[i] = value;"
              },
              {
                "line": 184,
                "text": "        }"
              },
              {
                "line": 185,
                "text": "        return indices;"
              },
              {
                "line": 186,
                "text": "    }"
              },
              {
                "line": 187,
                "text": ""
              },
              {
                "line": 188,
                "text": "    static typename Bucket::iterator findEntry(Bucket &bucket, uint32_t signature) {"
              },
              {
                "line": 189,
                "text": "        constexpr int MAX_HAMMING ="
              },
              {
                "line": 190,
                "text": "            4; // allow small differences between noisy repeats"
              },
              {
                "line": 191,
                "text": ""
              },
              {
                "line": 192,
                "text": "        return std::find_if("
              }
            ]
          }
        },
        {
          "function": "findEntry",
          "line": 188,
          "signature": "static typename Bucket::iterator findEntry(Bucket &bucket, uint32_t signature) {",
          "snippet": {
            "start_line": 174,
            "end_line": 202,
            "lines": [
              {
                "line": 174,
                "text": "    };"
              },
              {
                "line": 175,
                "text": ""
              },
              {
                "line": 176,
                "text": "    using Bucket = std::vector<Entry>;"
              },
              {
                "line": 177,
                "text": ""
              },
              {
                "line": 178,
                "text": "    static constexpr auto signatureIndices() {"
              },
              {
                "line": 179,
                "text": "        std::array<int, 32> indices{};"
              },
              {
                "line": 180,
                "text": "        int value = 0;"
              },
              {
                "line": 181,
                "text": "        for (std::size_t i = 0; i < indices.size(); ++i) {"
              },
              {
                "line": 182,
                "text": "            value = (value + 37) % static_cast<int>(N);"
              },
              {
                "line": 183,
                "text": "            indices[i] = value;"
              },
              {
                "line": 184,
                "text": "        }"
              },
              {
                "line": 185,
                "text": "        return indices;"
              },
              {
                "line": 186,
                "text": "    }"
              },
              {
                "line": 187,
                "text": ""
              },
              {
                "line": 188,
                "text": "    static typename Bucket::iterator findEntry(Bucket &bucket, uint32_t signature) {"
              },
              {
                "line": 189,
                "text": "        constexpr int MAX_HAMMING ="
              },
              {
                "line": 190,
                "text": "            4; // allow small differences between noisy repeats"
              },
              {
                "line": 191,
                "text": ""
              },
              {
                "line": 192,
                "text": "        return std::find_if("
              },
              {
                "line": 193,
                "text": "            bucket.begin(), bucket.end(), [signature](Entry const &entry) {"
              },
              {
                "line": 194,
                "text": "                return hamming(signature, entry.signature) <= MAX_HAMMING;"
              },
              {
                "line": 195,
                "text": "            });"
              },
              {
                "line": 196,
                "text": "    }"
              },
              {
                "line": 197,
                "text": ""
              },
              {
                "line": 198,
                "text": "    static bool defaultEnabled() {"
              },
              {
                "line": 199,
                "text": "        bool ok = false;"
              },
              {
                "line": 200,
                "text": "        int value = qEnvironmentVariableIntValue(\"JS8_SOFT_COMBINING\", &ok);"
              },
              {
                "line": 201,
                "text": "        return ok ? value != 0 : true;"
              },
              {
                "line": 202,
                "text": "    }"
              }
            ]
          }
        },
        {
          "function": "defaultEnabled",
          "line": 198,
          "signature": "static bool defaultEnabled() {",
          "snippet": {
            "start_line": 184,
            "end_line": 212,
            "lines": [
              {
                "line": 184,
                "text": "        }"
              },
              {
                "line": 185,
                "text": "        return indices;"
              },
              {
                "line": 186,
                "text": "    }"
              },
              {
                "line": 187,
                "text": ""
              },
              {
                "line": 188,
                "text": "    static typename Bucket::iterator findEntry(Bucket &bucket, uint32_t signature) {"
              },
              {
                "line": 189,
                "text": "        constexpr int MAX_HAMMING ="
              },
              {
                "line": 190,
                "text": "            4; // allow small differences between noisy repeats"
              },
              {
                "line": 191,
                "text": ""
              },
              {
                "line": 192,
                "text": "        return std::find_if("
              },
              {
                "line": 193,
                "text": "            bucket.begin(), bucket.end(), [signature](Entry const &entry) {"
              },
              {
                "line": 194,
                "text": "                return hamming(signature, entry.signature) <= MAX_HAMMING;"
              },
              {
                "line": 195,
                "text": "            });"
              },
              {
                "line": 196,
                "text": "    }"
              },
              {
                "line": 197,
                "text": ""
              },
              {
                "line": 198,
                "text": "    static bool defaultEnabled() {"
              },
              {
                "line": 199,
                "text": "        bool ok = false;"
              },
              {
                "line": 200,
                "text": "        int value = qEnvironmentVariableIntValue(\"JS8_SOFT_COMBINING\", &ok);"
              },
              {
                "line": 201,
                "text": "        return ok ? value != 0 : true;"
              },
              {
                "line": 202,
                "text": "    }"
              },
              {
                "line": 203,
                "text": ""
              },
              {
                "line": 204,
                "text": "    static uint32_t signature(std::array<float, N> const &llr0,"
              },
              {
                "line": 205,
                "text": "                              std::array<float, N> const &llr1) {"
              },
              {
                "line": 206,
                "text": "        static constexpr auto INDICES = signatureIndices();"
              },
              {
                "line": 207,
                "text": ""
              },
              {
                "line": 208,
                "text": "        uint32_t sig = 0;"
              },
              {
                "line": 209,
                "text": "        for (std::size_t i = 0; i < INDICES.size(); ++i) {"
              },
              {
                "line": 210,
                "text": "            auto const idx = INDICES[i];"
              },
              {
                "line": 211,
                "text": "            float const v = 0.5f * (llr0[idx] + llr1[idx]);"
              },
              {
                "line": 212,
                "text": "            if (v >= 0.0f)"
              }
            ]
          }
        },
        {
          "function": "hamming",
          "line": 218,
          "signature": "static int hamming(uint32_t a, uint32_t b) {",
          "snippet": {
            "start_line": 204,
            "end_line": 232,
            "lines": [
              {
                "line": 204,
                "text": "    static uint32_t signature(std::array<float, N> const &llr0,"
              },
              {
                "line": 205,
                "text": "                              std::array<float, N> const &llr1) {"
              },
              {
                "line": 206,
                "text": "        static constexpr auto INDICES = signatureIndices();"
              },
              {
                "line": 207,
                "text": ""
              },
              {
                "line": 208,
                "text": "        uint32_t sig = 0;"
              },
              {
                "line": 209,
                "text": "        for (std::size_t i = 0; i < INDICES.size(); ++i) {"
              },
              {
                "line": 210,
                "text": "            auto const idx = INDICES[i];"
              },
              {
                "line": 211,
                "text": "            float const v = 0.5f * (llr0[idx] + llr1[idx]);"
              },
              {
                "line": 212,
                "text": "            if (v >= 0.0f)"
              },
              {
                "line": 213,
                "text": "                sig |= (1u << i);"
              },
              {
                "line": 214,
                "text": "        }"
              },
              {
                "line": 215,
                "text": "        return sig;"
              },
              {
                "line": 216,
                "text": "    }"
              },
              {
                "line": 217,
                "text": ""
              },
              {
                "line": 218,
                "text": "    static int hamming(uint32_t a, uint32_t b) {"
              },
              {
                "line": 219,
                "text": "        uint32_t v = a ^ b;"
              },
              {
                "line": 220,
                "text": "        int c = 0;"
              },
              {
                "line": 221,
                "text": "        while (v) {"
              },
              {
                "line": 222,
                "text": "            v &= (v - 1);"
              },
              {
                "line": 223,
                "text": "            ++c;"
              },
              {
                "line": 224,
                "text": "        }"
              },
              {
                "line": 225,
                "text": "        return c;"
              },
              {
                "line": 226,
                "text": "    }"
              },
              {
                "line": 227,
                "text": ""
              },
              {
                "line": 228,
                "text": "    static void maybeRunSelfTest() {"
              },
              {
                "line": 229,
                "text": "        static std::once_flag once;"
              },
              {
                "line": 230,
                "text": "        std::call_once(once, []() {"
              },
              {
                "line": 231,
                "text": "            if (!qEnvironmentVariableIsSet(\"JS8_SOFT_COMBINING_TEST\"))"
              },
              {
                "line": 232,
                "text": "                return;"
              }
            ]
          }
        },
        {
          "function": "maybeRunSelfTest",
          "line": 228,
          "signature": "static void maybeRunSelfTest() {",
          "snippet": {
            "start_line": 214,
            "end_line": 242,
            "lines": [
              {
                "line": 214,
                "text": "        }"
              },
              {
                "line": 215,
                "text": "        return sig;"
              },
              {
                "line": 216,
                "text": "    }"
              },
              {
                "line": 217,
                "text": ""
              },
              {
                "line": 218,
                "text": "    static int hamming(uint32_t a, uint32_t b) {"
              },
              {
                "line": 219,
                "text": "        uint32_t v = a ^ b;"
              },
              {
                "line": 220,
                "text": "        int c = 0;"
              },
              {
                "line": 221,
                "text": "        while (v) {"
              },
              {
                "line": 222,
                "text": "            v &= (v - 1);"
              },
              {
                "line": 223,
                "text": "            ++c;"
              },
              {
                "line": 224,
                "text": "        }"
              },
              {
                "line": 225,
                "text": "        return c;"
              },
              {
                "line": 226,
                "text": "    }"
              },
              {
                "line": 227,
                "text": ""
              },
              {
                "line": 228,
                "text": "    static void maybeRunSelfTest() {"
              },
              {
                "line": 229,
                "text": "        static std::once_flag once;"
              },
              {
                "line": 230,
                "text": "        std::call_once(once, []() {"
              },
              {
                "line": 231,
                "text": "            if (!qEnvironmentVariableIsSet(\"JS8_SOFT_COMBINING_TEST\"))"
              },
              {
                "line": 232,
                "text": "                return;"
              },
              {
                "line": 233,
                "text": ""
              },
              {
                "line": 234,
                "text": "            SoftCombiner combiner(true, false);"
              },
              {
                "line": 235,
                "text": ""
              },
              {
                "line": 236,
                "text": "            std::array<float, N> baseline{};"
              },
              {
                "line": 237,
                "text": "            for (std::size_t i = 0; i < baseline.size(); ++i) {"
              },
              {
                "line": 238,
                "text": "                baseline[i] = (i % 2 == 0) ? 2.0f : -2.0f;"
              },
              {
                "line": 239,
                "text": "            }"
              },
              {
                "line": 240,
                "text": ""
              },
              {
                "line": 241,
                "text": "            auto noisy = [](std::array<float, N> base, int flipStride) {"
              },
              {
                "line": 242,
                "text": "                for (std::size_t i = 0; i < base.size(); ++i) {"
              }
            ]
          }
        }
      ],
      "keyword_snippets": [
        {
          "line": 22,
          "matches": [
            "LLR",
            "llr",
            "candidate"
          ],
          "snippet": {
            "start_line": 16,
            "end_line": 28,
            "lines": [
              {
                "line": 16,
                "text": "#include <vector>"
              },
              {
                "line": 17,
                "text": ""
              },
              {
                "line": 18,
                "text": "Q_DECLARE_LOGGING_CATEGORY(decoder_js8);"
              },
              {
                "line": 19,
                "text": ""
              },
              {
                "line": 20,
                "text": "namespace js8 {"
              },
              {
                "line": 21,
                "text": "/**"
              },
              {
                "line": 22,
                "text": " * @brief Cache and combine repeated LLR frames for the same decode candidate."
              },
              {
                "line": 23,
                "text": " *"
              },
              {
                "line": 24,
                "text": " * Uses a coarse freq/dt bin and a small LLR signature as the key; repeated"
              },
              {
                "line": 25,
                "text": " * receptions accumulate LLRs to improve decode probability without changing"
              },
              {
                "line": 26,
                "text": " * over-the-air behavior. Templated on the LLR length so the caller binds it"
              },
              {
                "line": 27,
                "text": " * to the decoder's bit count."
              },
              {
                "line": 28,
                "text": " */"
              }
            ]
          }
        },
        {
          "line": 26,
          "matches": [
            "LLR",
            "llr"
          ],
          "snippet": {
            "start_line": 20,
            "end_line": 32,
            "lines": [
              {
                "line": 20,
                "text": "namespace js8 {"
              },
              {
                "line": 21,
                "text": "/**"
              },
              {
                "line": 22,
                "text": " * @brief Cache and combine repeated LLR frames for the same decode candidate."
              },
              {
                "line": 23,
                "text": " *"
              },
              {
                "line": 24,
                "text": " * Uses a coarse freq/dt bin and a small LLR signature as the key; repeated"
              },
              {
                "line": 25,
                "text": " * receptions accumulate LLRs to improve decode probability without changing"
              },
              {
                "line": 26,
                "text": " * over-the-air behavior. Templated on the LLR length so the caller binds it"
              },
              {
                "line": 27,
                "text": " * to the decoder's bit count."
              },
              {
                "line": 28,
                "text": " */"
              },
              {
                "line": 29,
                "text": "template <std::size_t N> class SoftCombiner {"
              },
              {
                "line": 30,
                "text": "    using Clock = std::chrono::steady_clock;"
              },
              {
                "line": 31,
                "text": ""
              },
              {
                "line": 32,
                "text": "  public:"
              }
            ]
          }
        },
        {
          "line": 47,
          "matches": [
            "LLR",
            "llr"
          ],
          "snippet": {
            "start_line": 41,
            "end_line": 53,
            "lines": [
              {
                "line": 41,
                "text": "                   dtBin == other.dtBin && signature == other.signature;"
              },
              {
                "line": 42,
                "text": "        }"
              },
              {
                "line": 43,
                "text": "    };"
              },
              {
                "line": 44,
                "text": ""
              },
              {
                "line": 45,
                "text": "    struct Combined {"
              },
              {
                "line": 46,
                "text": "        Key key;"
              },
              {
                "line": 47,
                "text": "        std::array<float, N> llr0;"
              },
              {
                "line": 48,
                "text": "        std::array<float, N> llr1;"
              },
              {
                "line": 49,
                "text": "        int repeats;"
              },
              {
                "line": 50,
                "text": "        bool combined;"
              },
              {
                "line": 51,
                "text": "    };"
              },
              {
                "line": 52,
                "text": ""
              },
              {
                "line": 53,
                "text": "    SoftCombiner() : SoftCombiner(defaultEnabled(), true) {}"
              }
            ]
          }
        },
        {
          "line": 53,
          "matches": [
            "soft"
          ],
          "snippet": {
            "start_line": 47,
            "end_line": 59,
            "lines": [
              {
                "line": 47,
                "text": "        std::array<float, N> llr0;"
              },
              {
                "line": 48,
                "text": "        std::array<float, N> llr1;"
              },
              {
                "line": 49,
                "text": "        int repeats;"
              },
              {
                "line": 50,
                "text": "        bool combined;"
              },
              {
                "line": 51,
                "text": "    };"
              },
              {
                "line": 52,
                "text": ""
              },
              {
                "line": 53,
                "text": "    SoftCombiner() : SoftCombiner(defaultEnabled(), true) {}"
              },
              {
                "line": 54,
                "text": ""
              },
              {
                "line": 55,
                "text": "    explicit SoftCombiner(bool enabled, bool runSelfTest = true)"
              },
              {
                "line": 56,
                "text": "        : m_enabled(enabled) {"
              },
              {
                "line": 57,
                "text": "        if (!m_enabled) {"
              },
              {
                "line": 58,
                "text": "            qCDebug(decoder_js8)"
              },
              {
                "line": 59,
                "text": "                << \"soft-combining disabled (JS8_SOFT_COMBINING=0)\";"
              }
            ]
          }
        },
        {
          "line": 59,
          "matches": [
            "soft"
          ],
          "snippet": {
            "start_line": 53,
            "end_line": 65,
            "lines": [
              {
                "line": 53,
                "text": "    SoftCombiner() : SoftCombiner(defaultEnabled(), true) {}"
              },
              {
                "line": 54,
                "text": ""
              },
              {
                "line": 55,
                "text": "    explicit SoftCombiner(bool enabled, bool runSelfTest = true)"
              },
              {
                "line": 56,
                "text": "        : m_enabled(enabled) {"
              },
              {
                "line": 57,
                "text": "        if (!m_enabled) {"
              },
              {
                "line": 58,
                "text": "            qCDebug(decoder_js8)"
              },
              {
                "line": 59,
                "text": "                << \"soft-combining disabled (JS8_SOFT_COMBINING=0)\";"
              },
              {
                "line": 60,
                "text": "        }"
              },
              {
                "line": 61,
                "text": "        if (runSelfTest)"
              },
              {
                "line": 62,
                "text": "            maybeRunSelfTest();"
              },
              {
                "line": 63,
                "text": "    }"
              },
              {
                "line": 64,
                "text": ""
              },
              {
                "line": 65,
                "text": "    Key makeKey(int mode, float f1, float dt, std::array<float, N> const &llr0,"
              }
            ]
          }
        },
        {
          "line": 65,
          "matches": [
            "LLR",
            "llr"
          ],
          "snippet": {
            "start_line": 59,
            "end_line": 71,
            "lines": [
              {
                "line": 59,
                "text": "                << \"soft-combining disabled (JS8_SOFT_COMBINING=0)\";"
              },
              {
                "line": 60,
                "text": "        }"
              },
              {
                "line": 61,
                "text": "        if (runSelfTest)"
              },
              {
                "line": 62,
                "text": "            maybeRunSelfTest();"
              },
              {
                "line": 63,
                "text": "    }"
              },
              {
                "line": 64,
                "text": ""
              },
              {
                "line": 65,
                "text": "    Key makeKey(int mode, float f1, float dt, std::array<float, N> const &llr0,"
              },
              {
                "line": 66,
                "text": "                std::array<float, N> const &llr1) const {"
              },
              {
                "line": 67,
                "text": "        return Key{mode, static_cast<int>(std::lround(f1)),"
              },
              {
                "line": 68,
                "text": "                   static_cast<int>(std::lround(dt * 10.0f)), // 100 ms bins"
              },
              {
                "line": 69,
                "text": "                   signature(llr0, llr1)};"
              },
              {
                "line": 70,
                "text": "    }"
              },
              {
                "line": 71,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 66,
          "matches": [
            "LLR",
            "llr"
          ],
          "snippet": {
            "start_line": 60,
            "end_line": 72,
            "lines": [
              {
                "line": 60,
                "text": "        }"
              },
              {
                "line": 61,
                "text": "        if (runSelfTest)"
              },
              {
                "line": 62,
                "text": "            maybeRunSelfTest();"
              },
              {
                "line": 63,
                "text": "    }"
              },
              {
                "line": 64,
                "text": ""
              },
              {
                "line": 65,
                "text": "    Key makeKey(int mode, float f1, float dt, std::array<float, N> const &llr0,"
              },
              {
                "line": 66,
                "text": "                std::array<float, N> const &llr1) const {"
              },
              {
                "line": 67,
                "text": "        return Key{mode, static_cast<int>(std::lround(f1)),"
              },
              {
                "line": 68,
                "text": "                   static_cast<int>(std::lround(dt * 10.0f)), // 100 ms bins"
              },
              {
                "line": 69,
                "text": "                   signature(llr0, llr1)};"
              },
              {
                "line": 70,
                "text": "    }"
              },
              {
                "line": 71,
                "text": ""
              },
              {
                "line": 72,
                "text": "    Combined combine(Key const &key, std::array<float, N> const &llr0,"
              }
            ]
          }
        },
        {
          "line": 72,
          "matches": [
            "LLR",
            "llr"
          ],
          "snippet": {
            "start_line": 66,
            "end_line": 78,
            "lines": [
              {
                "line": 66,
                "text": "                std::array<float, N> const &llr1) const {"
              },
              {
                "line": 67,
                "text": "        return Key{mode, static_cast<int>(std::lround(f1)),"
              },
              {
                "line": 68,
                "text": "                   static_cast<int>(std::lround(dt * 10.0f)), // 100 ms bins"
              },
              {
                "line": 69,
                "text": "                   signature(llr0, llr1)};"
              },
              {
                "line": 70,
                "text": "    }"
              },
              {
                "line": 71,
                "text": ""
              },
              {
                "line": 72,
                "text": "    Combined combine(Key const &key, std::array<float, N> const &llr0,"
              },
              {
                "line": 73,
                "text": "                     std::array<float, N> const &llr1,"
              },
              {
                "line": 74,
                "text": "                     std::chrono::seconds ttl) {"
              },
              {
                "line": 75,
                "text": "        flush(ttl);"
              },
              {
                "line": 76,
                "text": ""
              },
              {
                "line": 77,
                "text": "        if (!m_enabled) {"
              },
              {
                "line": 78,
                "text": "            return Combined{key, llr0, llr1, 1, false};"
              }
            ]
          }
        },
        {
          "line": 78,
          "matches": [
            "LLR",
            "llr"
          ],
          "snippet": {
            "start_line": 72,
            "end_line": 84,
            "lines": [
              {
                "line": 72,
                "text": "    Combined combine(Key const &key, std::array<float, N> const &llr0,"
              },
              {
                "line": 73,
                "text": "                     std::array<float, N> const &llr1,"
              },
              {
                "line": 74,
                "text": "                     std::chrono::seconds ttl) {"
              },
              {
                "line": 75,
                "text": "        flush(ttl);"
              },
              {
                "line": 76,
                "text": ""
              },
              {
                "line": 77,
                "text": "        if (!m_enabled) {"
              },
              {
                "line": 78,
                "text": "            return Combined{key, llr0, llr1, 1, false};"
              },
              {
                "line": 79,
                "text": "        }"
              },
              {
                "line": 80,
                "text": ""
              },
              {
                "line": 81,
                "text": "        auto &bucket = m_entries[keyForLookup(key)];"
              },
              {
                "line": 82,
                "text": "        auto it = findEntry(bucket, key.signature);"
              },
              {
                "line": 83,
                "text": ""
              },
              {
                "line": 84,
                "text": "        if (it == bucket.end()) {"
              }
            ]
          }
        },
        {
          "line": 85,
          "matches": [
            "LLR",
            "llr"
          ],
          "snippet": {
            "start_line": 79,
            "end_line": 91,
            "lines": [
              {
                "line": 79,
                "text": "        }"
              },
              {
                "line": 80,
                "text": ""
              },
              {
                "line": 81,
                "text": "        auto &bucket = m_entries[keyForLookup(key)];"
              },
              {
                "line": 82,
                "text": "        auto it = findEntry(bucket, key.signature);"
              },
              {
                "line": 83,
                "text": ""
              },
              {
                "line": 84,
                "text": "        if (it == bucket.end()) {"
              },
              {
                "line": 85,
                "text": "            bucket.push_back(makeEntry(key.signature, llr0, llr1));"
              },
              {
                "line": 86,
                "text": "            return Combined{key, llr0, llr1, 1, false};"
              },
              {
                "line": 87,
                "text": "        }"
              },
              {
                "line": 88,
                "text": ""
              },
              {
                "line": 89,
                "text": "        for (std::size_t i = 0; i < llr0.size(); ++i) {"
              },
              {
                "line": 90,
                "text": "            it->llr0[i] += llr0[i];"
              },
              {
                "line": 91,
                "text": "            it->llr1[i] += llr1[i];"
              }
            ]
          }
        },
        {
          "line": 86,
          "matches": [
            "LLR",
            "llr"
          ],
          "snippet": {
            "start_line": 80,
            "end_line": 92,
            "lines": [
              {
                "line": 80,
                "text": ""
              },
              {
                "line": 81,
                "text": "        auto &bucket = m_entries[keyForLookup(key)];"
              },
              {
                "line": 82,
                "text": "        auto it = findEntry(bucket, key.signature);"
              },
              {
                "line": 83,
                "text": ""
              },
              {
                "line": 84,
                "text": "        if (it == bucket.end()) {"
              },
              {
                "line": 85,
                "text": "            bucket.push_back(makeEntry(key.signature, llr0, llr1));"
              },
              {
                "line": 86,
                "text": "            return Combined{key, llr0, llr1, 1, false};"
              },
              {
                "line": 87,
                "text": "        }"
              },
              {
                "line": 88,
                "text": ""
              },
              {
                "line": 89,
                "text": "        for (std::size_t i = 0; i < llr0.size(); ++i) {"
              },
              {
                "line": 90,
                "text": "            it->llr0[i] += llr0[i];"
              },
              {
                "line": 91,
                "text": "            it->llr1[i] += llr1[i];"
              },
              {
                "line": 92,
                "text": "        }"
              }
            ]
          }
        },
        {
          "line": 91,
          "matches": [
            "LLR",
            "llr"
          ],
          "snippet": {
            "start_line": 85,
            "end_line": 97,
            "lines": [
              {
                "line": 85,
                "text": "            bucket.push_back(makeEntry(key.signature, llr0, llr1));"
              },
              {
                "line": 86,
                "text": "            return Combined{key, llr0, llr1, 1, false};"
              },
              {
                "line": 87,
                "text": "        }"
              },
              {
                "line": 88,
                "text": ""
              },
              {
                "line": 89,
                "text": "        for (std::size_t i = 0; i < llr0.size(); ++i) {"
              },
              {
                "line": 90,
                "text": "            it->llr0[i] += llr0[i];"
              },
              {
                "line": 91,
                "text": "            it->llr1[i] += llr1[i];"
              },
              {
                "line": 92,
                "text": "        }"
              },
              {
                "line": 93,
                "text": ""
              },
              {
                "line": 94,
                "text": "        ++it->repeats;"
              },
              {
                "line": 95,
                "text": "        it->lastSeen = Clock::now();"
              },
              {
                "line": 96,
                "text": ""
              },
              {
                "line": 97,
                "text": "        qCDebug(decoder_js8)"
              }
            ]
          }
        },
        {
          "line": 98,
          "matches": [
            "soft"
          ],
          "snippet": {
            "start_line": 92,
            "end_line": 104,
            "lines": [
              {
                "line": 92,
                "text": "        }"
              },
              {
                "line": 93,
                "text": ""
              },
              {
                "line": 94,
                "text": "        ++it->repeats;"
              },
              {
                "line": 95,
                "text": "        it->lastSeen = Clock::now();"
              },
              {
                "line": 96,
                "text": ""
              },
              {
                "line": 97,
                "text": "        qCDebug(decoder_js8)"
              },
              {
                "line": 98,
                "text": "            << \"soft-combining repeats\" << it->repeats << \"mode\" << key.mode"
              },
              {
                "line": 99,
                "text": "            << \"freq\" << key.freqBin << \"dtbin\" << key.dtBin;"
              },
              {
                "line": 100,
                "text": ""
              },
              {
                "line": 101,
                "text": "        return Combined{key, it->llr0, it->llr1, it->repeats, true};"
              },
              {
                "line": 102,
                "text": "    }"
              },
              {
                "line": 103,
                "text": ""
              },
              {
                "line": 104,
                "text": "    void markDecoded(Key const &key) {"
              }
            ]
          }
        },
        {
          "line": 101,
          "matches": [
            "LLR",
            "llr"
          ],
          "snippet": {
            "start_line": 95,
            "end_line": 107,
            "lines": [
              {
                "line": 95,
                "text": "        it->lastSeen = Clock::now();"
              },
              {
                "line": 96,
                "text": ""
              },
              {
                "line": 97,
                "text": "        qCDebug(decoder_js8)"
              },
              {
                "line": 98,
                "text": "            << \"soft-combining repeats\" << it->repeats << \"mode\" << key.mode"
              },
              {
                "line": 99,
                "text": "            << \"freq\" << key.freqBin << \"dtbin\" << key.dtBin;"
              },
              {
                "line": 100,
                "text": ""
              },
              {
                "line": 101,
                "text": "        return Combined{key, it->llr0, it->llr1, it->repeats, true};"
              },
              {
                "line": 102,
                "text": "    }"
              },
              {
                "line": 103,
                "text": ""
              },
              {
                "line": 104,
                "text": "    void markDecoded(Key const &key) {"
              },
              {
                "line": 105,
                "text": "        if (!m_enabled)"
              },
              {
                "line": 106,
                "text": "            return;"
              },
              {
                "line": 107,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 115,
          "matches": [
            "erase"
          ],
          "snippet": {
            "start_line": 109,
            "end_line": 121,
            "lines": [
              {
                "line": 109,
                "text": "        auto it = m_entries.find(lookup);"
              },
              {
                "line": 110,
                "text": ""
              },
              {
                "line": 111,
                "text": "        if (it == m_entries.end())"
              },
              {
                "line": 112,
                "text": "            return;"
              },
              {
                "line": 113,
                "text": ""
              },
              {
                "line": 114,
                "text": "        auto &bucket = it->second;"
              },
              {
                "line": 115,
                "text": "        bucket.erase(std::remove_if(bucket.begin(), bucket.end(),"
              },
              {
                "line": 116,
                "text": "                                    [&key](Entry const &entry) {"
              },
              {
                "line": 117,
                "text": "                                        return entry.signature == key.signature;"
              },
              {
                "line": 118,
                "text": "                                    }),"
              },
              {
                "line": 119,
                "text": "                     bucket.end());"
              },
              {
                "line": 120,
                "text": ""
              },
              {
                "line": 121,
                "text": "        if (bucket.empty())"
              }
            ]
          }
        },
        {
          "line": 122,
          "matches": [
            "erase"
          ],
          "snippet": {
            "start_line": 116,
            "end_line": 128,
            "lines": [
              {
                "line": 116,
                "text": "                                    [&key](Entry const &entry) {"
              },
              {
                "line": 117,
                "text": "                                        return entry.signature == key.signature;"
              },
              {
                "line": 118,
                "text": "                                    }),"
              },
              {
                "line": 119,
                "text": "                     bucket.end());"
              },
              {
                "line": 120,
                "text": ""
              },
              {
                "line": 121,
                "text": "        if (bucket.empty())"
              },
              {
                "line": 122,
                "text": "            m_entries.erase(it);"
              },
              {
                "line": 123,
                "text": "    }"
              },
              {
                "line": 124,
                "text": ""
              },
              {
                "line": 125,
                "text": "    void flush(std::chrono::seconds ttl) {"
              },
              {
                "line": 126,
                "text": "        if (!m_enabled)"
              },
              {
                "line": 127,
                "text": "            return;"
              },
              {
                "line": 128,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 134,
          "matches": [
            "erase"
          ],
          "snippet": {
            "start_line": 128,
            "end_line": 140,
            "lines": [
              {
                "line": 128,
                "text": ""
              },
              {
                "line": 129,
                "text": "        auto const now = Clock::now();"
              },
              {
                "line": 130,
                "text": ""
              },
              {
                "line": 131,
                "text": "        for (auto it = m_entries.begin(); it != m_entries.end();) {"
              },
              {
                "line": 132,
                "text": "            auto &bucket = it->second;"
              },
              {
                "line": 133,
                "text": ""
              },
              {
                "line": 134,
                "text": "            bucket.erase(std::remove_if(bucket.begin(), bucket.end(),"
              },
              {
                "line": 135,
                "text": "                                        [now, ttl](Entry const &entry) {"
              },
              {
                "line": 136,
                "text": "                                            return now - entry.lastSeen > ttl;"
              },
              {
                "line": 137,
                "text": "                                        }),"
              },
              {
                "line": 138,
                "text": "                         bucket.end());"
              },
              {
                "line": 139,
                "text": ""
              },
              {
                "line": 140,
                "text": "            if (bucket.empty())"
              }
            ]
          }
        },
        {
          "line": 141,
          "matches": [
            "erase"
          ],
          "snippet": {
            "start_line": 135,
            "end_line": 147,
            "lines": [
              {
                "line": 135,
                "text": "                                        [now, ttl](Entry const &entry) {"
              },
              {
                "line": 136,
                "text": "                                            return now - entry.lastSeen > ttl;"
              },
              {
                "line": 137,
                "text": "                                        }),"
              },
              {
                "line": 138,
                "text": "                         bucket.end());"
              },
              {
                "line": 139,
                "text": ""
              },
              {
                "line": 140,
                "text": "            if (bucket.empty())"
              },
              {
                "line": 141,
                "text": "                it = m_entries.erase(it);"
              },
              {
                "line": 142,
                "text": "            else"
              },
              {
                "line": 143,
                "text": "                ++it;"
              },
              {
                "line": 144,
                "text": "        }"
              },
              {
                "line": 145,
                "text": "    }"
              },
              {
                "line": 146,
                "text": ""
              },
              {
                "line": 147,
                "text": "  private:"
              }
            ]
          }
        },
        {
          "line": 170,
          "matches": [
            "LLR",
            "llr"
          ],
          "snippet": {
            "start_line": 164,
            "end_line": 176,
            "lines": [
              {
                "line": 164,
                "text": "            return h1 ^ (h2 << 1) ^ (h3 << 2);"
              },
              {
                "line": 165,
                "text": "        }"
              },
              {
                "line": 166,
                "text": "    };"
              },
              {
                "line": 167,
                "text": ""
              },
              {
                "line": 168,
                "text": "    struct Entry {"
              },
              {
                "line": 169,
                "text": "        uint32_t signature;"
              },
              {
                "line": 170,
                "text": "        std::array<float, N> llr0;"
              },
              {
                "line": 171,
                "text": "        std::array<float, N> llr1;"
              },
              {
                "line": 172,
                "text": "        int repeats;"
              },
              {
                "line": 173,
                "text": "        Clock::time_point lastSeen;"
              },
              {
                "line": 174,
                "text": "    };"
              },
              {
                "line": 175,
                "text": ""
              },
              {
                "line": 176,
                "text": "    using Bucket = std::vector<Entry>;"
              }
            ]
          }
        },
        {
          "line": 171,
          "matches": [
            "LLR",
            "llr"
          ],
          "snippet": {
            "start_line": 165,
            "end_line": 177,
            "lines": [
              {
                "line": 165,
                "text": "        }"
              },
              {
                "line": 166,
                "text": "    };"
              },
              {
                "line": 167,
                "text": ""
              },
              {
                "line": 168,
                "text": "    struct Entry {"
              },
              {
                "line": 169,
                "text": "        uint32_t signature;"
              },
              {
                "line": 170,
                "text": "        std::array<float, N> llr0;"
              },
              {
                "line": 171,
                "text": "        std::array<float, N> llr1;"
              },
              {
                "line": 172,
                "text": "        int repeats;"
              },
              {
                "line": 173,
                "text": "        Clock::time_point lastSeen;"
              },
              {
                "line": 174,
                "text": "    };"
              },
              {
                "line": 175,
                "text": ""
              },
              {
                "line": 176,
                "text": "    using Bucket = std::vector<Entry>;"
              },
              {
                "line": 177,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 200,
          "matches": [
            "soft"
          ],
          "snippet": {
            "start_line": 194,
            "end_line": 206,
            "lines": [
              {
                "line": 194,
                "text": "                return hamming(signature, entry.signature) <= MAX_HAMMING;"
              },
              {
                "line": 195,
                "text": "            });"
              },
              {
                "line": 196,
                "text": "    }"
              },
              {
                "line": 197,
                "text": ""
              },
              {
                "line": 198,
                "text": "    static bool defaultEnabled() {"
              },
              {
                "line": 199,
                "text": "        bool ok = false;"
              },
              {
                "line": 200,
                "text": "        int value = qEnvironmentVariableIntValue(\"JS8_SOFT_COMBINING\", &ok);"
              },
              {
                "line": 201,
                "text": "        return ok ? value != 0 : true;"
              },
              {
                "line": 202,
                "text": "    }"
              },
              {
                "line": 203,
                "text": ""
              },
              {
                "line": 204,
                "text": "    static uint32_t signature(std::array<float, N> const &llr0,"
              },
              {
                "line": 205,
                "text": "                              std::array<float, N> const &llr1) {"
              },
              {
                "line": 206,
                "text": "        static constexpr auto INDICES = signatureIndices();"
              }
            ]
          }
        },
        {
          "line": 204,
          "matches": [
            "LLR",
            "llr"
          ],
          "snippet": {
            "start_line": 198,
            "end_line": 210,
            "lines": [
              {
                "line": 198,
                "text": "    static bool defaultEnabled() {"
              },
              {
                "line": 199,
                "text": "        bool ok = false;"
              },
              {
                "line": 200,
                "text": "        int value = qEnvironmentVariableIntValue(\"JS8_SOFT_COMBINING\", &ok);"
              },
              {
                "line": 201,
                "text": "        return ok ? value != 0 : true;"
              },
              {
                "line": 202,
                "text": "    }"
              },
              {
                "line": 203,
                "text": ""
              },
              {
                "line": 204,
                "text": "    static uint32_t signature(std::array<float, N> const &llr0,"
              },
              {
                "line": 205,
                "text": "                              std::array<float, N> const &llr1) {"
              },
              {
                "line": 206,
                "text": "        static constexpr auto INDICES = signatureIndices();"
              },
              {
                "line": 207,
                "text": ""
              },
              {
                "line": 208,
                "text": "        uint32_t sig = 0;"
              },
              {
                "line": 209,
                "text": "        for (std::size_t i = 0; i < INDICES.size(); ++i) {"
              },
              {
                "line": 210,
                "text": "            auto const idx = INDICES[i];"
              }
            ]
          }
        }
      ]
    },
    {
      "path": "JS8_Mode/whitening_processor.h",
      "exists": true,
      "bytes": 9129,
      "sha256": "bcd61a557030caba012b501d3ea851ab0cfda16c8ec4d01ddc902bebec86fb45",
      "line_count": 259,
      "phase_hits": {
        "timing_submode": 0,
        "symbol_to_soft_bits": 112,
        "bit_order_interleaver": 2,
        "whitening_erasure": 57,
        "ldpc_decode": 0,
        "message91_crc_text": 0
      },
      "function_blocks": [],
      "keyword_snippets": [
        {
          "line": 19,
          "matches": [
            "whiten",
            "noise",
            "LLR"
          ],
          "snippet": {
            "start_line": 13,
            "end_line": 25,
            "lines": [
              {
                "line": 13,
                "text": "#include <vector>"
              },
              {
                "line": 14,
                "text": ""
              },
              {
                "line": 15,
                "text": "Q_DECLARE_LOGGING_CATEGORY(decoder_js8);"
              },
              {
                "line": 16,
                "text": ""
              },
              {
                "line": 17,
                "text": "namespace js8 {"
              },
              {
                "line": 18,
                "text": "/**"
              },
              {
                "line": 19,
                "text": " * @brief Compute per-tone/symbol noise medians and whiten LLRs for a JS8 frame."
              },
              {
                "line": 20,
                "text": " *"
              },
              {
                "line": 21,
                "text": " * Given symbol magnitudes (sans Costas) and winners, produces normalized"
              },
              {
                "line": 22,
                "text": " * LLR0/LLR1, optionally applying noise-based whitening and erasure. Fully"
              },
              {
                "line": 23,
                "text": " * templated on matrix dimensions, so it stays header-only; used inside the JS8"
              },
              {
                "line": 24,
                "text": " * decoder per candidate."
              },
              {
                "line": 25,
                "text": " */"
              }
            ]
          }
        },
        {
          "line": 22,
          "matches": [
            "whiten",
            "noise",
            "LLR"
          ],
          "snippet": {
            "start_line": 16,
            "end_line": 28,
            "lines": [
              {
                "line": 16,
                "text": ""
              },
              {
                "line": 17,
                "text": "namespace js8 {"
              },
              {
                "line": 18,
                "text": "/**"
              },
              {
                "line": 19,
                "text": " * @brief Compute per-tone/symbol noise medians and whiten LLRs for a JS8 frame."
              },
              {
                "line": 20,
                "text": " *"
              },
              {
                "line": 21,
                "text": " * Given symbol magnitudes (sans Costas) and winners, produces normalized"
              },
              {
                "line": 22,
                "text": " * LLR0/LLR1, optionally applying noise-based whitening and erasure. Fully"
              },
              {
                "line": 23,
                "text": " * templated on matrix dimensions, so it stays header-only; used inside the JS8"
              },
              {
                "line": 24,
                "text": " * decoder per candidate."
              },
              {
                "line": 25,
                "text": " */"
              },
              {
                "line": 26,
                "text": "template <int NROWS, int ND, int N> class WhiteningProcessor {"
              },
              {
                "line": 27,
                "text": "  public:"
              },
              {
                "line": 28,
                "text": "    struct Result {"
              }
            ]
          }
        },
        {
          "line": 26,
          "matches": [
            "whiten"
          ],
          "snippet": {
            "start_line": 20,
            "end_line": 32,
            "lines": [
              {
                "line": 20,
                "text": " *"
              },
              {
                "line": 21,
                "text": " * Given symbol magnitudes (sans Costas) and winners, produces normalized"
              },
              {
                "line": 22,
                "text": " * LLR0/LLR1, optionally applying noise-based whitening and erasure. Fully"
              },
              {
                "line": 23,
                "text": " * templated on matrix dimensions, so it stays header-only; used inside the JS8"
              },
              {
                "line": 24,
                "text": " * decoder per candidate."
              },
              {
                "line": 25,
                "text": " */"
              },
              {
                "line": 26,
                "text": "template <int NROWS, int ND, int N> class WhiteningProcessor {"
              },
              {
                "line": 27,
                "text": "  public:"
              },
              {
                "line": 28,
                "text": "    struct Result {"
              },
              {
                "line": 29,
                "text": "        std::array<float, 3 * ND> llr0;"
              },
              {
                "line": 30,
                "text": "        std::array<float, 3 * ND> llr1;"
              },
              {
                "line": 31,
                "text": "        bool whiteningApplied;"
              },
              {
                "line": 32,
                "text": "        bool erasureApplied;"
              }
            ]
          }
        },
        {
          "line": 31,
          "matches": [
            "whiten"
          ],
          "snippet": {
            "start_line": 25,
            "end_line": 37,
            "lines": [
              {
                "line": 25,
                "text": " */"
              },
              {
                "line": 26,
                "text": "template <int NROWS, int ND, int N> class WhiteningProcessor {"
              },
              {
                "line": 27,
                "text": "  public:"
              },
              {
                "line": 28,
                "text": "    struct Result {"
              },
              {
                "line": 29,
                "text": "        std::array<float, 3 * ND> llr0;"
              },
              {
                "line": 30,
                "text": "        std::array<float, 3 * ND> llr1;"
              },
              {
                "line": 31,
                "text": "        bool whiteningApplied;"
              },
              {
                "line": 32,
                "text": "        bool erasureApplied;"
              },
              {
                "line": 33,
                "text": "        std::size_t erasures;"
              },
              {
                "line": 34,
                "text": "        double avgAbsPre;"
              },
              {
                "line": 35,
                "text": "        double avgAbsPost;"
              },
              {
                "line": 36,
                "text": "    };"
              },
              {
                "line": 37,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 61,
          "matches": [
            "noise"
          ],
          "snippet": {
            "start_line": 55,
            "end_line": 67,
            "lines": [
              {
                "line": 55,
                "text": "                med = 0.5f * (med + values[mid - 1]);"
              },
              {
                "line": 56,
                "text": "            }"
              },
              {
                "line": 57,
                "text": ""
              },
              {
                "line": 58,
                "text": "            return med;"
              },
              {
                "line": 59,
                "text": "        };"
              },
              {
                "line": 60,
                "text": ""
              },
              {
                "line": 61,
                "text": "        // Estimate per-tone noise using non-winning tone magnitudes across the"
              },
              {
                "line": 62,
                "text": "        // frame."
              },
              {
                "line": 63,
                "text": "        auto const toneNoise ="
              },
              {
                "line": 64,
                "text": "            [&]() -> std::optional<std::array<float, NROWS>> {"
              },
              {
                "line": 65,
                "text": "            std::array<std::vector<float>, NROWS> toneSamples;"
              },
              {
                "line": 66,
                "text": "            std::array<float, NROWS> noise = {};"
              },
              {
                "line": 67,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 66,
          "matches": [
            "noise"
          ],
          "snippet": {
            "start_line": 60,
            "end_line": 72,
            "lines": [
              {
                "line": 60,
                "text": ""
              },
              {
                "line": 61,
                "text": "        // Estimate per-tone noise using non-winning tone magnitudes across the"
              },
              {
                "line": 62,
                "text": "        // frame."
              },
              {
                "line": 63,
                "text": "        auto const toneNoise ="
              },
              {
                "line": 64,
                "text": "            [&]() -> std::optional<std::array<float, NROWS>> {"
              },
              {
                "line": 65,
                "text": "            std::array<std::vector<float>, NROWS> toneSamples;"
              },
              {
                "line": 66,
                "text": "            std::array<float, NROWS> noise = {};"
              },
              {
                "line": 67,
                "text": ""
              },
              {
                "line": 68,
                "text": "            // Collect non-winning magnitudes for each tone."
              },
              {
                "line": 69,
                "text": "            for (int j = 0; j < ND; ++j) {"
              },
              {
                "line": 70,
                "text": "                int const winner = symbolWinners[j];"
              },
              {
                "line": 71,
                "text": ""
              },
              {
                "line": 72,
                "text": "                for (int i = 0; i < NROWS; ++i) {"
              }
            ]
          }
        },
        {
          "line": 82,
          "matches": [
            "noise"
          ],
          "snippet": {
            "start_line": 76,
            "end_line": 88,
            "lines": [
              {
                "line": 76,
                "text": "            }"
              },
              {
                "line": 77,
                "text": ""
              },
              {
                "line": 78,
                "text": "            bool ok = true;"
              },
              {
                "line": 79,
                "text": ""
              },
              {
                "line": 80,
                "text": "            for (int i = 0; i < NROWS; ++i) {"
              },
              {
                "line": 81,
                "text": "                if (auto m = median(toneSamples[i]); m) {"
              },
              {
                "line": 82,
                "text": "                    noise[i] = *m;"
              },
              {
                "line": 83,
                "text": "                } else {"
              },
              {
                "line": 84,
                "text": "                    ok = false;"
              },
              {
                "line": 85,
                "text": "                    break;"
              },
              {
                "line": 86,
                "text": "                }"
              },
              {
                "line": 87,
                "text": "            }"
              },
              {
                "line": 88,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 92,
          "matches": [
            "noise"
          ],
          "snippet": {
            "start_line": 86,
            "end_line": 98,
            "lines": [
              {
                "line": 86,
                "text": "                }"
              },
              {
                "line": 87,
                "text": "            }"
              },
              {
                "line": 88,
                "text": ""
              },
              {
                "line": 89,
                "text": "            if (!ok)"
              },
              {
                "line": 90,
                "text": "                return std::nullopt;"
              },
              {
                "line": 91,
                "text": ""
              },
              {
                "line": 92,
                "text": "            return noise;"
              },
              {
                "line": 93,
                "text": "        }();"
              },
              {
                "line": 94,
                "text": ""
              },
              {
                "line": 95,
                "text": "        if (toneNoise && debug) {"
              },
              {
                "line": 96,
                "text": "            std::ostringstream oss;"
              },
              {
                "line": 97,
                "text": ""
              },
              {
                "line": 98,
                "text": "            oss << \"toneNoise:\";"
              }
            ]
          }
        },
        {
          "line": 98,
          "matches": [
            "noise"
          ],
          "snippet": {
            "start_line": 92,
            "end_line": 104,
            "lines": [
              {
                "line": 92,
                "text": "            return noise;"
              },
              {
                "line": 93,
                "text": "        }();"
              },
              {
                "line": 94,
                "text": ""
              },
              {
                "line": 95,
                "text": "        if (toneNoise && debug) {"
              },
              {
                "line": 96,
                "text": "            std::ostringstream oss;"
              },
              {
                "line": 97,
                "text": ""
              },
              {
                "line": 98,
                "text": "            oss << \"toneNoise:\";"
              },
              {
                "line": 99,
                "text": "            for (auto const value : *toneNoise)"
              },
              {
                "line": 100,
                "text": "                oss << ' ' << value;"
              },
              {
                "line": 101,
                "text": ""
              },
              {
                "line": 102,
                "text": "            qCDebug(decoder_js8).noquote() << oss.str().c_str();"
              },
              {
                "line": 103,
                "text": "        }"
              },
              {
                "line": 104,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 105,
          "matches": [
            "noise"
          ],
          "snippet": {
            "start_line": 99,
            "end_line": 111,
            "lines": [
              {
                "line": 99,
                "text": "            for (auto const value : *toneNoise)"
              },
              {
                "line": 100,
                "text": "                oss << ' ' << value;"
              },
              {
                "line": 101,
                "text": ""
              },
              {
                "line": 102,
                "text": "            qCDebug(decoder_js8).noquote() << oss.str().c_str();"
              },
              {
                "line": 103,
                "text": "        }"
              },
              {
                "line": 104,
                "text": ""
              },
              {
                "line": 105,
                "text": "        // Estimate per-symbol noise using non-winning tone magnitudes per"
              },
              {
                "line": 106,
                "text": "        // symbol."
              },
              {
                "line": 107,
                "text": "        auto const symbolNoise = [&]() -> std::optional<std::vector<float>> {"
              },
              {
                "line": 108,
                "text": "            std::vector<float> noise;"
              },
              {
                "line": 109,
                "text": "            noise.reserve(ND);"
              },
              {
                "line": 110,
                "text": ""
              },
              {
                "line": 111,
                "text": "            for (int j = 0; j < ND; ++j) {"
              }
            ]
          }
        },
        {
          "line": 107,
          "matches": [
            "noise"
          ],
          "snippet": {
            "start_line": 101,
            "end_line": 113,
            "lines": [
              {
                "line": 101,
                "text": ""
              },
              {
                "line": 102,
                "text": "            qCDebug(decoder_js8).noquote() << oss.str().c_str();"
              },
              {
                "line": 103,
                "text": "        }"
              },
              {
                "line": 104,
                "text": ""
              },
              {
                "line": 105,
                "text": "        // Estimate per-symbol noise using non-winning tone magnitudes per"
              },
              {
                "line": 106,
                "text": "        // symbol."
              },
              {
                "line": 107,
                "text": "        auto const symbolNoise = [&]() -> std::optional<std::vector<float>> {"
              },
              {
                "line": 108,
                "text": "            std::vector<float> noise;"
              },
              {
                "line": 109,
                "text": "            noise.reserve(ND);"
              },
              {
                "line": 110,
                "text": ""
              },
              {
                "line": 111,
                "text": "            for (int j = 0; j < ND; ++j) {"
              },
              {
                "line": 112,
                "text": "                std::vector<float> bins;"
              },
              {
                "line": 113,
                "text": "                bins.reserve(NROWS - 1);"
              }
            ]
          }
        },
        {
          "line": 123,
          "matches": [
            "noise"
          ],
          "snippet": {
            "start_line": 117,
            "end_line": 129,
            "lines": [
              {
                "line": 117,
                "text": "                for (int i = 0; i < NROWS; ++i) {"
              },
              {
                "line": 118,
                "text": "                    if (i != winner)"
              },
              {
                "line": 119,
                "text": "                        bins.push_back(s1[i][j]);"
              },
              {
                "line": 120,
                "text": "                }"
              },
              {
                "line": 121,
                "text": ""
              },
              {
                "line": 122,
                "text": "                if (auto m = median(bins); m) {"
              },
              {
                "line": 123,
                "text": "                    noise.push_back(*m);"
              },
              {
                "line": 124,
                "text": "                } else {"
              },
              {
                "line": 125,
                "text": "                    return std::nullopt;"
              },
              {
                "line": 126,
                "text": "                }"
              },
              {
                "line": 127,
                "text": "            }"
              },
              {
                "line": 128,
                "text": ""
              },
              {
                "line": 129,
                "text": "            return noise;"
              }
            ]
          }
        },
        {
          "line": 129,
          "matches": [
            "noise"
          ],
          "snippet": {
            "start_line": 123,
            "end_line": 135,
            "lines": [
              {
                "line": 123,
                "text": "                    noise.push_back(*m);"
              },
              {
                "line": 124,
                "text": "                } else {"
              },
              {
                "line": 125,
                "text": "                    return std::nullopt;"
              },
              {
                "line": 126,
                "text": "                }"
              },
              {
                "line": 127,
                "text": "            }"
              },
              {
                "line": 128,
                "text": ""
              },
              {
                "line": 129,
                "text": "            return noise;"
              },
              {
                "line": 130,
                "text": "        }();"
              },
              {
                "line": 131,
                "text": ""
              },
              {
                "line": 132,
                "text": "        if (symbolNoise && !symbolNoise->empty() && debug) {"
              },
              {
                "line": 133,
                "text": "            auto const [minIt, maxIt] ="
              },
              {
                "line": 134,
                "text": "                std::minmax_element(symbolNoise->begin(), symbolNoise->end());"
              },
              {
                "line": 135,
                "text": "            float const avg = std::accumulate(symbolNoise->begin(),"
              }
            ]
          }
        },
        {
          "line": 132,
          "matches": [
            "noise"
          ],
          "snippet": {
            "start_line": 126,
            "end_line": 138,
            "lines": [
              {
                "line": 126,
                "text": "                }"
              },
              {
                "line": 127,
                "text": "            }"
              },
              {
                "line": 128,
                "text": ""
              },
              {
                "line": 129,
                "text": "            return noise;"
              },
              {
                "line": 130,
                "text": "        }();"
              },
              {
                "line": 131,
                "text": ""
              },
              {
                "line": 132,
                "text": "        if (symbolNoise && !symbolNoise->empty() && debug) {"
              },
              {
                "line": 133,
                "text": "            auto const [minIt, maxIt] ="
              },
              {
                "line": 134,
                "text": "                std::minmax_element(symbolNoise->begin(), symbolNoise->end());"
              },
              {
                "line": 135,
                "text": "            float const avg = std::accumulate(symbolNoise->begin(),"
              },
              {
                "line": 136,
                "text": "                                              symbolNoise->end(), 0.0f) /"
              },
              {
                "line": 137,
                "text": "                              static_cast<float>(symbolNoise->size());"
              },
              {
                "line": 138,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 136,
          "matches": [
            "noise"
          ],
          "snippet": {
            "start_line": 130,
            "end_line": 142,
            "lines": [
              {
                "line": 130,
                "text": "        }();"
              },
              {
                "line": 131,
                "text": ""
              },
              {
                "line": 132,
                "text": "        if (symbolNoise && !symbolNoise->empty() && debug) {"
              },
              {
                "line": 133,
                "text": "            auto const [minIt, maxIt] ="
              },
              {
                "line": 134,
                "text": "                std::minmax_element(symbolNoise->begin(), symbolNoise->end());"
              },
              {
                "line": 135,
                "text": "            float const avg = std::accumulate(symbolNoise->begin(),"
              },
              {
                "line": 136,
                "text": "                                              symbolNoise->end(), 0.0f) /"
              },
              {
                "line": 137,
                "text": "                              static_cast<float>(symbolNoise->size());"
              },
              {
                "line": 138,
                "text": ""
              },
              {
                "line": 139,
                "text": "            qCDebug(decoder_js8)"
              },
              {
                "line": 140,
                "text": "                << \"symbolNoise avg/min/max\" << avg << *minIt << *maxIt;"
              },
              {
                "line": 141,
                "text": "        }"
              },
              {
                "line": 142,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 145,
          "matches": [
            "whiten"
          ],
          "snippet": {
            "start_line": 139,
            "end_line": 151,
            "lines": [
              {
                "line": 139,
                "text": "            qCDebug(decoder_js8)"
              },
              {
                "line": 140,
                "text": "                << \"symbolNoise avg/min/max\" << avg << *minIt << *maxIt;"
              },
              {
                "line": 141,
                "text": "        }"
              },
              {
                "line": 142,
                "text": ""
              },
              {
                "line": 143,
                "text": "        Result result{};"
              },
              {
                "line": 144,
                "text": ""
              },
              {
                "line": 145,
                "text": "        bool const disableWhitening ="
              },
              {
                "line": 146,
                "text": "            std::getenv(\"JS8_DISABLE_WHITENING\") != nullptr;"
              },
              {
                "line": 147,
                "text": "        bool const whiteningAvailable = toneNoise && symbolNoise &&"
              },
              {
                "line": 148,
                "text": "                                        !symbolNoise->empty() &&"
              },
              {
                "line": 149,
                "text": "                                        !disableWhitening;"
              },
              {
                "line": 150,
                "text": "        bool const applyErasureInWhitening ="
              },
              {
                "line": 151,
                "text": "            whiteningAvailable && erasureThreshold > 0.0f;"
              }
            ]
          }
        },
        {
          "line": 146,
          "matches": [
            "whiten"
          ],
          "snippet": {
            "start_line": 140,
            "end_line": 152,
            "lines": [
              {
                "line": 140,
                "text": "                << \"symbolNoise avg/min/max\" << avg << *minIt << *maxIt;"
              },
              {
                "line": 141,
                "text": "        }"
              },
              {
                "line": 142,
                "text": ""
              },
              {
                "line": 143,
                "text": "        Result result{};"
              },
              {
                "line": 144,
                "text": ""
              },
              {
                "line": 145,
                "text": "        bool const disableWhitening ="
              },
              {
                "line": 146,
                "text": "            std::getenv(\"JS8_DISABLE_WHITENING\") != nullptr;"
              },
              {
                "line": 147,
                "text": "        bool const whiteningAvailable = toneNoise && symbolNoise &&"
              },
              {
                "line": 148,
                "text": "                                        !symbolNoise->empty() &&"
              },
              {
                "line": 149,
                "text": "                                        !disableWhitening;"
              },
              {
                "line": 150,
                "text": "        bool const applyErasureInWhitening ="
              },
              {
                "line": 151,
                "text": "            whiteningAvailable && erasureThreshold > 0.0f;"
              },
              {
                "line": 152,
                "text": "        double sumAbsPre = 0.0;"
              }
            ]
          }
        },
        {
          "line": 151,
          "matches": [
            "whiten"
          ],
          "snippet": {
            "start_line": 145,
            "end_line": 157,
            "lines": [
              {
                "line": 145,
                "text": "        bool const disableWhitening ="
              },
              {
                "line": 146,
                "text": "            std::getenv(\"JS8_DISABLE_WHITENING\") != nullptr;"
              },
              {
                "line": 147,
                "text": "        bool const whiteningAvailable = toneNoise && symbolNoise &&"
              },
              {
                "line": 148,
                "text": "                                        !symbolNoise->empty() &&"
              },
              {
                "line": 149,
                "text": "                                        !disableWhitening;"
              },
              {
                "line": 150,
                "text": "        bool const applyErasureInWhitening ="
              },
              {
                "line": 151,
                "text": "            whiteningAvailable && erasureThreshold > 0.0f;"
              },
              {
                "line": 152,
                "text": "        double sumAbsPre = 0.0;"
              },
              {
                "line": 153,
                "text": "        double sumAbsPost = 0.0;"
              },
              {
                "line": 154,
                "text": "        std::size_t erasures = 0;"
              },
              {
                "line": 155,
                "text": ""
              },
              {
                "line": 156,
                "text": "        for (int j = 0; j < ND; ++j) {"
              },
              {
                "line": 157,
                "text": "            int const i1 = 3 * j;     // First column (matches Fortran's i1)"
              }
            ]
          }
        },
        {
          "line": 167,
          "matches": [
            "LLR"
          ],
          "snippet": {
            "start_line": 161,
            "end_line": 173,
            "lines": [
              {
                "line": 161,
                "text": "            std::array<float, NROWS> ps;"
              },
              {
                "line": 162,
                "text": ""
              },
              {
                "line": 163,
                "text": "            for (int i = 0; i < NROWS; ++i)"
              },
              {
                "line": 164,
                "text": "                ps[i] = s1[i][j];"
              },
              {
                "line": 165,
                "text": ""
              },
              {
                "line": 166,
                "text": "            // Assign to `bmeta` in column order, with correct values"
              },
              {
                "line": 167,
                "text": "            result.llr0[i1] = std::max({ps[4], ps[5], ps[6], ps[7]}) -"
              },
              {
                "line": 168,
                "text": "                              std::max({ps[0], ps[1], ps[2], ps[3]}); // r4"
              },
              {
                "line": 169,
                "text": "            result.llr0[i2] = std::max({ps[2], ps[3], ps[6], ps[7]}) -"
              },
              {
                "line": 170,
                "text": "                              std::max({ps[0], ps[1], ps[4], ps[5]}); // r2"
              },
              {
                "line": 171,
                "text": "            result.llr0[i4] = std::max({ps[1], ps[3], ps[5], ps[7]}) -"
              },
              {
                "line": 172,
                "text": "                              std::max({ps[0], ps[2], ps[4], ps[6]}); // r1"
              },
              {
                "line": 173,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 171,
          "matches": [
            "LLR"
          ],
          "snippet": {
            "start_line": 165,
            "end_line": 177,
            "lines": [
              {
                "line": 165,
                "text": ""
              },
              {
                "line": 166,
                "text": "            // Assign to `bmeta` in column order, with correct values"
              },
              {
                "line": 167,
                "text": "            result.llr0[i1] = std::max({ps[4], ps[5], ps[6], ps[7]}) -"
              },
              {
                "line": 168,
                "text": "                              std::max({ps[0], ps[1], ps[2], ps[3]}); // r4"
              },
              {
                "line": 169,
                "text": "            result.llr0[i2] = std::max({ps[2], ps[3], ps[6], ps[7]}) -"
              },
              {
                "line": 170,
                "text": "                              std::max({ps[0], ps[1], ps[4], ps[5]}); // r2"
              },
              {
                "line": 171,
                "text": "            result.llr0[i4] = std::max({ps[1], ps[3], ps[5], ps[7]}) -"
              },
              {
                "line": 172,
                "text": "                              std::max({ps[0], ps[2], ps[4], ps[6]}); // r1"
              },
              {
                "line": 173,
                "text": ""
              },
              {
                "line": 174,
                "text": "            for (auto &x : ps)"
              },
              {
                "line": 175,
                "text": "                x = std::log(x + 1e-32f);"
              },
              {
                "line": 176,
                "text": ""
              },
              {
                "line": 177,
                "text": "            // Assign to `bmetb` in column order, with correct values"
              }
            ]
          }
        },
        {
          "line": 178,
          "matches": [
            "LLR"
          ],
          "snippet": {
            "start_line": 172,
            "end_line": 184,
            "lines": [
              {
                "line": 172,
                "text": "                              std::max({ps[0], ps[2], ps[4], ps[6]}); // r1"
              },
              {
                "line": 173,
                "text": ""
              },
              {
                "line": 174,
                "text": "            for (auto &x : ps)"
              },
              {
                "line": 175,
                "text": "                x = std::log(x + 1e-32f);"
              },
              {
                "line": 176,
                "text": ""
              },
              {
                "line": 177,
                "text": "            // Assign to `bmetb` in column order, with correct values"
              },
              {
                "line": 178,
                "text": "            result.llr1[i1] = std::max({ps[4], ps[5], ps[6], ps[7]}) -"
              },
              {
                "line": 179,
                "text": "                              std::max({ps[0], ps[1], ps[2], ps[3]}); // r4"
              },
              {
                "line": 180,
                "text": "            result.llr1[i2] = std::max({ps[2], ps[3], ps[6], ps[7]}) -"
              },
              {
                "line": 181,
                "text": "                              std::max({ps[0], ps[1], ps[4], ps[5]}); // r2"
              },
              {
                "line": 182,
                "text": "            result.llr1[i4] = std::max({ps[1], ps[3], ps[5], ps[7]}) -"
              },
              {
                "line": 183,
                "text": "                              std::max({ps[0], ps[2], ps[4], ps[6]}); // r1"
              },
              {
                "line": 184,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 182,
          "matches": [
            "LLR"
          ],
          "snippet": {
            "start_line": 176,
            "end_line": 188,
            "lines": [
              {
                "line": 176,
                "text": ""
              },
              {
                "line": 177,
                "text": "            // Assign to `bmetb` in column order, with correct values"
              },
              {
                "line": 178,
                "text": "            result.llr1[i1] = std::max({ps[4], ps[5], ps[6], ps[7]}) -"
              },
              {
                "line": 179,
                "text": "                              std::max({ps[0], ps[1], ps[2], ps[3]}); // r4"
              },
              {
                "line": 180,
                "text": "            result.llr1[i2] = std::max({ps[2], ps[3], ps[6], ps[7]}) -"
              },
              {
                "line": 181,
                "text": "                              std::max({ps[0], ps[1], ps[4], ps[5]}); // r2"
              },
              {
                "line": 182,
                "text": "            result.llr1[i4] = std::max({ps[1], ps[3], ps[5], ps[7]}) -"
              },
              {
                "line": 183,
                "text": "                              std::max({ps[0], ps[2], ps[4], ps[6]}); // r1"
              },
              {
                "line": 184,
                "text": ""
              },
              {
                "line": 185,
                "text": "            if (whiteningAvailable) {"
              },
              {
                "line": 186,
                "text": "                int const winner = symbolWinners[j];"
              },
              {
                "line": 187,
                "text": "                float const tn = std::max(0.0f, (*toneNoise)[winner]);"
              },
              {
                "line": 188,
                "text": "                float const sn = std::max(0.0f, (*symbolNoise)[j]);"
              }
            ]
          }
        }
      ]
    },
    {
      "path": "JS8_Mode/ldpc_feedback.h",
      "exists": true,
      "bytes": 3293,
      "sha256": "c9bb4ccc8f3def26952a29e97a88f4d912f7f79ed6006e843601b9d30fb974d0",
      "line_count": 109,
      "phase_hits": {
        "timing_submode": 0,
        "symbol_to_soft_bits": 50,
        "bit_order_interleaver": 4,
        "whitening_erasure": 0,
        "ldpc_decode": 24,
        "message91_crc_text": 0
      },
      "function_blocks": [
        {
          "function": "llrErasureThreshold",
          "line": 33,
          "signature": "inline float llrErasureThreshold() {",
          "snippet": {
            "start_line": 19,
            "end_line": 47,
            "lines": [
              {
                "line": 19,
                "text": " *"
              },
              {
                "line": 20,
                "text": " * Inline env readers expose thresholds/pass limits; the templated"
              },
              {
                "line": 21,
                "text": " * refineLlrsWithLdpcFeedback shrinks/boosts LLRs using the decoded"
              },
              {
                "line": 22,
                "text": " * codeword to retry LDPC. Used inside the JS8 decode loop between"
              },
              {
                "line": 23,
                "text": " * LDPC passes."
              },
              {
                "line": 24,
                "text": " */"
              },
              {
                "line": 25,
                "text": "constexpr float LLR_ERASURE_THRESHOLD_DEFAULT = 0.25f;"
              },
              {
                "line": 26,
                "text": "constexpr float LLR_FEEDBACK_CONFIDENT_MIN = 3.0f;"
              },
              {
                "line": 27,
                "text": "constexpr float LLR_FEEDBACK_UNCERTAIN_MAX = 1.0f;"
              },
              {
                "line": 28,
                "text": "constexpr float LLR_FEEDBACK_CONFIDENT_BOOST = 1.2f;"
              },
              {
                "line": 29,
                "text": "constexpr float LLR_FEEDBACK_UNCERTAIN_SHRINK = 0.5f;"
              },
              {
                "line": 30,
                "text": "constexpr float LLR_FEEDBACK_MAX_MAG = 6.0f;"
              },
              {
                "line": 31,
                "text": "constexpr int LDPC_FEEDBACK_MAX_PASSES_DEFAULT = 8;"
              },
              {
                "line": 32,
                "text": ""
              },
              {
                "line": 33,
                "text": "inline float llrErasureThreshold() {"
              },
              {
                "line": 34,
                "text": "    float threshold = LLR_ERASURE_THRESHOLD_DEFAULT;"
              },
              {
                "line": 35,
                "text": ""
              },
              {
                "line": 36,
                "text": "    if (auto const env = std::getenv(\"JS8_LLR_ERASURE_THRESH\"); env) {"
              },
              {
                "line": 37,
                "text": "        char *end = nullptr;"
              },
              {
                "line": 38,
                "text": "        float val = std::strtof(env, &end);"
              },
              {
                "line": 39,
                "text": ""
              },
              {
                "line": 40,
                "text": "        if (end != env && std::isfinite(val)) {"
              },
              {
                "line": 41,
                "text": "            threshold = val;"
              },
              {
                "line": 42,
                "text": "        }"
              },
              {
                "line": 43,
                "text": "    }"
              },
              {
                "line": 44,
                "text": ""
              },
              {
                "line": 45,
                "text": "    if (threshold <= 0.0f || !std::isfinite(threshold) ||"
              },
              {
                "line": 46,
                "text": "        std::getenv(\"JS8_DISABLE_ERASURE_THRESHOLDING\")) {"
              },
              {
                "line": 47,
                "text": "        return 0.0f;"
              }
            ]
          }
        },
        {
          "function": "ldpcFeedbackEnabled",
          "line": 53,
          "signature": "inline bool ldpcFeedbackEnabled() {",
          "snippet": {
            "start_line": 39,
            "end_line": 67,
            "lines": [
              {
                "line": 39,
                "text": ""
              },
              {
                "line": 40,
                "text": "        if (end != env && std::isfinite(val)) {"
              },
              {
                "line": 41,
                "text": "            threshold = val;"
              },
              {
                "line": 42,
                "text": "        }"
              },
              {
                "line": 43,
                "text": "    }"
              },
              {
                "line": 44,
                "text": ""
              },
              {
                "line": 45,
                "text": "    if (threshold <= 0.0f || !std::isfinite(threshold) ||"
              },
              {
                "line": 46,
                "text": "        std::getenv(\"JS8_DISABLE_ERASURE_THRESHOLDING\")) {"
              },
              {
                "line": 47,
                "text": "        return 0.0f;"
              },
              {
                "line": 48,
                "text": "    }"
              },
              {
                "line": 49,
                "text": ""
              },
              {
                "line": 50,
                "text": "    return threshold;"
              },
              {
                "line": 51,
                "text": "}"
              },
              {
                "line": 52,
                "text": ""
              },
              {
                "line": 53,
                "text": "inline bool ldpcFeedbackEnabled() {"
              },
              {
                "line": 54,
                "text": "    bool ok = false;"
              },
              {
                "line": 55,
                "text": "    int value = qEnvironmentVariableIntValue(\"JS8_LDPC_FEEDBACK\", &ok);"
              },
              {
                "line": 56,
                "text": "    return ok ? value != 0 : true;"
              },
              {
                "line": 57,
                "text": "}"
              },
              {
                "line": 58,
                "text": ""
              },
              {
                "line": 59,
                "text": "inline int ldpcFeedbackMaxPasses() {"
              },
              {
                "line": 60,
                "text": "    bool ok = false;"
              },
              {
                "line": 61,
                "text": "    int value = qEnvironmentVariableIntValue(\"JS8_LDPC_MAX_PASSES\", &ok);"
              },
              {
                "line": 62,
                "text": ""
              },
              {
                "line": 63,
                "text": "    if (!ok)"
              },
              {
                "line": 64,
                "text": "        return LDPC_FEEDBACK_MAX_PASSES_DEFAULT;"
              },
              {
                "line": 65,
                "text": ""
              },
              {
                "line": 66,
                "text": "    return std::clamp(value, 1, LDPC_FEEDBACK_MAX_PASSES_DEFAULT);"
              },
              {
                "line": 67,
                "text": "}"
              }
            ]
          }
        },
        {
          "function": "ldpcFeedbackMaxPasses",
          "line": 59,
          "signature": "inline int ldpcFeedbackMaxPasses() {",
          "snippet": {
            "start_line": 45,
            "end_line": 73,
            "lines": [
              {
                "line": 45,
                "text": "    if (threshold <= 0.0f || !std::isfinite(threshold) ||"
              },
              {
                "line": 46,
                "text": "        std::getenv(\"JS8_DISABLE_ERASURE_THRESHOLDING\")) {"
              },
              {
                "line": 47,
                "text": "        return 0.0f;"
              },
              {
                "line": 48,
                "text": "    }"
              },
              {
                "line": 49,
                "text": ""
              },
              {
                "line": 50,
                "text": "    return threshold;"
              },
              {
                "line": 51,
                "text": "}"
              },
              {
                "line": 52,
                "text": ""
              },
              {
                "line": 53,
                "text": "inline bool ldpcFeedbackEnabled() {"
              },
              {
                "line": 54,
                "text": "    bool ok = false;"
              },
              {
                "line": 55,
                "text": "    int value = qEnvironmentVariableIntValue(\"JS8_LDPC_FEEDBACK\", &ok);"
              },
              {
                "line": 56,
                "text": "    return ok ? value != 0 : true;"
              },
              {
                "line": 57,
                "text": "}"
              },
              {
                "line": 58,
                "text": ""
              },
              {
                "line": 59,
                "text": "inline int ldpcFeedbackMaxPasses() {"
              },
              {
                "line": 60,
                "text": "    bool ok = false;"
              },
              {
                "line": 61,
                "text": "    int value = qEnvironmentVariableIntValue(\"JS8_LDPC_MAX_PASSES\", &ok);"
              },
              {
                "line": 62,
                "text": ""
              },
              {
                "line": 63,
                "text": "    if (!ok)"
              },
              {
                "line": 64,
                "text": "        return LDPC_FEEDBACK_MAX_PASSES_DEFAULT;"
              },
              {
                "line": 65,
                "text": ""
              },
              {
                "line": 66,
                "text": "    return std::clamp(value, 1, LDPC_FEEDBACK_MAX_PASSES_DEFAULT);"
              },
              {
                "line": 67,
                "text": "}"
              },
              {
                "line": 68,
                "text": ""
              },
              {
                "line": 69,
                "text": "template <std::size_t N>"
              },
              {
                "line": 70,
                "text": "void refineLlrsWithLdpcFeedback(std::array<float, N> const &llrIn,"
              },
              {
                "line": 71,
                "text": "                                std::array<int8_t, N> const &cw,"
              },
              {
                "line": 72,
                "text": "                                float erasureThreshold,"
              },
              {
                "line": 73,
                "text": "                                std::array<float, N> &llrOut,"
              }
            ]
          }
        }
      ],
      "keyword_snippets": [
        {
          "line": 14,
          "matches": [
            "decode"
          ],
          "snippet": {
            "start_line": 8,
            "end_line": 20,
            "lines": [
              {
                "line": 8,
                "text": "#include <array>"
              },
              {
                "line": 9,
                "text": "#include <cmath>"
              },
              {
                "line": 10,
                "text": "#include <cstdint>"
              },
              {
                "line": 11,
                "text": "#include <cstdlib>"
              },
              {
                "line": 12,
                "text": "#include <optional>"
              },
              {
                "line": 13,
                "text": ""
              },
              {
                "line": 14,
                "text": "Q_DECLARE_LOGGING_CATEGORY(decoder_js8);"
              },
              {
                "line": 15,
                "text": ""
              },
              {
                "line": 16,
                "text": "namespace js8 {"
              },
              {
                "line": 17,
                "text": "/**"
              },
              {
                "line": 18,
                "text": " * @brief LDPC erasure threshold config and feedback refinement helpers."
              },
              {
                "line": 19,
                "text": " *"
              },
              {
                "line": 20,
                "text": " * Inline env readers expose thresholds/pass limits; the templated"
              }
            ]
          }
        },
        {
          "line": 18,
          "matches": [
            "ldpc"
          ],
          "snippet": {
            "start_line": 12,
            "end_line": 24,
            "lines": [
              {
                "line": 12,
                "text": "#include <optional>"
              },
              {
                "line": 13,
                "text": ""
              },
              {
                "line": 14,
                "text": "Q_DECLARE_LOGGING_CATEGORY(decoder_js8);"
              },
              {
                "line": 15,
                "text": ""
              },
              {
                "line": 16,
                "text": "namespace js8 {"
              },
              {
                "line": 17,
                "text": "/**"
              },
              {
                "line": 18,
                "text": " * @brief LDPC erasure threshold config and feedback refinement helpers."
              },
              {
                "line": 19,
                "text": " *"
              },
              {
                "line": 20,
                "text": " * Inline env readers expose thresholds/pass limits; the templated"
              },
              {
                "line": 21,
                "text": " * refineLlrsWithLdpcFeedback shrinks/boosts LLRs using the decoded"
              },
              {
                "line": 22,
                "text": " * codeword to retry LDPC. Used inside the JS8 decode loop between"
              },
              {
                "line": 23,
                "text": " * LDPC passes."
              },
              {
                "line": 24,
                "text": " */"
              }
            ]
          }
        },
        {
          "line": 21,
          "matches": [
            "ldpc",
            "decode",
            "LLR"
          ],
          "snippet": {
            "start_line": 15,
            "end_line": 27,
            "lines": [
              {
                "line": 15,
                "text": ""
              },
              {
                "line": 16,
                "text": "namespace js8 {"
              },
              {
                "line": 17,
                "text": "/**"
              },
              {
                "line": 18,
                "text": " * @brief LDPC erasure threshold config and feedback refinement helpers."
              },
              {
                "line": 19,
                "text": " *"
              },
              {
                "line": 20,
                "text": " * Inline env readers expose thresholds/pass limits; the templated"
              },
              {
                "line": 21,
                "text": " * refineLlrsWithLdpcFeedback shrinks/boosts LLRs using the decoded"
              },
              {
                "line": 22,
                "text": " * codeword to retry LDPC. Used inside the JS8 decode loop between"
              },
              {
                "line": 23,
                "text": " * LDPC passes."
              },
              {
                "line": 24,
                "text": " */"
              },
              {
                "line": 25,
                "text": "constexpr float LLR_ERASURE_THRESHOLD_DEFAULT = 0.25f;"
              },
              {
                "line": 26,
                "text": "constexpr float LLR_FEEDBACK_CONFIDENT_MIN = 3.0f;"
              },
              {
                "line": 27,
                "text": "constexpr float LLR_FEEDBACK_UNCERTAIN_MAX = 1.0f;"
              }
            ]
          }
        },
        {
          "line": 26,
          "matches": [
            "LLR"
          ],
          "snippet": {
            "start_line": 20,
            "end_line": 32,
            "lines": [
              {
                "line": 20,
                "text": " * Inline env readers expose thresholds/pass limits; the templated"
              },
              {
                "line": 21,
                "text": " * refineLlrsWithLdpcFeedback shrinks/boosts LLRs using the decoded"
              },
              {
                "line": 22,
                "text": " * codeword to retry LDPC. Used inside the JS8 decode loop between"
              },
              {
                "line": 23,
                "text": " * LDPC passes."
              },
              {
                "line": 24,
                "text": " */"
              },
              {
                "line": 25,
                "text": "constexpr float LLR_ERASURE_THRESHOLD_DEFAULT = 0.25f;"
              },
              {
                "line": 26,
                "text": "constexpr float LLR_FEEDBACK_CONFIDENT_MIN = 3.0f;"
              },
              {
                "line": 27,
                "text": "constexpr float LLR_FEEDBACK_UNCERTAIN_MAX = 1.0f;"
              },
              {
                "line": 28,
                "text": "constexpr float LLR_FEEDBACK_CONFIDENT_BOOST = 1.2f;"
              },
              {
                "line": 29,
                "text": "constexpr float LLR_FEEDBACK_UNCERTAIN_SHRINK = 0.5f;"
              },
              {
                "line": 30,
                "text": "constexpr float LLR_FEEDBACK_MAX_MAG = 6.0f;"
              },
              {
                "line": 31,
                "text": "constexpr int LDPC_FEEDBACK_MAX_PASSES_DEFAULT = 8;"
              },
              {
                "line": 32,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 31,
          "matches": [
            "ldpc"
          ],
          "snippet": {
            "start_line": 25,
            "end_line": 37,
            "lines": [
              {
                "line": 25,
                "text": "constexpr float LLR_ERASURE_THRESHOLD_DEFAULT = 0.25f;"
              },
              {
                "line": 26,
                "text": "constexpr float LLR_FEEDBACK_CONFIDENT_MIN = 3.0f;"
              },
              {
                "line": 27,
                "text": "constexpr float LLR_FEEDBACK_UNCERTAIN_MAX = 1.0f;"
              },
              {
                "line": 28,
                "text": "constexpr float LLR_FEEDBACK_CONFIDENT_BOOST = 1.2f;"
              },
              {
                "line": 29,
                "text": "constexpr float LLR_FEEDBACK_UNCERTAIN_SHRINK = 0.5f;"
              },
              {
                "line": 30,
                "text": "constexpr float LLR_FEEDBACK_MAX_MAG = 6.0f;"
              },
              {
                "line": 31,
                "text": "constexpr int LDPC_FEEDBACK_MAX_PASSES_DEFAULT = 8;"
              },
              {
                "line": 32,
                "text": ""
              },
              {
                "line": 33,
                "text": "inline float llrErasureThreshold() {"
              },
              {
                "line": 34,
                "text": "    float threshold = LLR_ERASURE_THRESHOLD_DEFAULT;"
              },
              {
                "line": 35,
                "text": ""
              },
              {
                "line": 36,
                "text": "    if (auto const env = std::getenv(\"JS8_LLR_ERASURE_THRESH\"); env) {"
              },
              {
                "line": 37,
                "text": "        char *end = nullptr;"
              }
            ]
          }
        },
        {
          "line": 36,
          "matches": [
            "LLR"
          ],
          "snippet": {
            "start_line": 30,
            "end_line": 42,
            "lines": [
              {
                "line": 30,
                "text": "constexpr float LLR_FEEDBACK_MAX_MAG = 6.0f;"
              },
              {
                "line": 31,
                "text": "constexpr int LDPC_FEEDBACK_MAX_PASSES_DEFAULT = 8;"
              },
              {
                "line": 32,
                "text": ""
              },
              {
                "line": 33,
                "text": "inline float llrErasureThreshold() {"
              },
              {
                "line": 34,
                "text": "    float threshold = LLR_ERASURE_THRESHOLD_DEFAULT;"
              },
              {
                "line": 35,
                "text": ""
              },
              {
                "line": 36,
                "text": "    if (auto const env = std::getenv(\"JS8_LLR_ERASURE_THRESH\"); env) {"
              },
              {
                "line": 37,
                "text": "        char *end = nullptr;"
              },
              {
                "line": 38,
                "text": "        float val = std::strtof(env, &end);"
              },
              {
                "line": 39,
                "text": ""
              },
              {
                "line": 40,
                "text": "        if (end != env && std::isfinite(val)) {"
              },
              {
                "line": 41,
                "text": "            threshold = val;"
              },
              {
                "line": 42,
                "text": "        }"
              }
            ]
          }
        },
        {
          "line": 53,
          "matches": [
            "ldpc"
          ],
          "snippet": {
            "start_line": 47,
            "end_line": 59,
            "lines": [
              {
                "line": 47,
                "text": "        return 0.0f;"
              },
              {
                "line": 48,
                "text": "    }"
              },
              {
                "line": 49,
                "text": ""
              },
              {
                "line": 50,
                "text": "    return threshold;"
              },
              {
                "line": 51,
                "text": "}"
              },
              {
                "line": 52,
                "text": ""
              },
              {
                "line": 53,
                "text": "inline bool ldpcFeedbackEnabled() {"
              },
              {
                "line": 54,
                "text": "    bool ok = false;"
              },
              {
                "line": 55,
                "text": "    int value = qEnvironmentVariableIntValue(\"JS8_LDPC_FEEDBACK\", &ok);"
              },
              {
                "line": 56,
                "text": "    return ok ? value != 0 : true;"
              },
              {
                "line": 57,
                "text": "}"
              },
              {
                "line": 58,
                "text": ""
              },
              {
                "line": 59,
                "text": "inline int ldpcFeedbackMaxPasses() {"
              }
            ]
          }
        },
        {
          "line": 59,
          "matches": [
            "ldpc"
          ],
          "snippet": {
            "start_line": 53,
            "end_line": 65,
            "lines": [
              {
                "line": 53,
                "text": "inline bool ldpcFeedbackEnabled() {"
              },
              {
                "line": 54,
                "text": "    bool ok = false;"
              },
              {
                "line": 55,
                "text": "    int value = qEnvironmentVariableIntValue(\"JS8_LDPC_FEEDBACK\", &ok);"
              },
              {
                "line": 56,
                "text": "    return ok ? value != 0 : true;"
              },
              {
                "line": 57,
                "text": "}"
              },
              {
                "line": 58,
                "text": ""
              },
              {
                "line": 59,
                "text": "inline int ldpcFeedbackMaxPasses() {"
              },
              {
                "line": 60,
                "text": "    bool ok = false;"
              },
              {
                "line": 61,
                "text": "    int value = qEnvironmentVariableIntValue(\"JS8_LDPC_MAX_PASSES\", &ok);"
              },
              {
                "line": 62,
                "text": ""
              },
              {
                "line": 63,
                "text": "    if (!ok)"
              },
              {
                "line": 64,
                "text": "        return LDPC_FEEDBACK_MAX_PASSES_DEFAULT;"
              },
              {
                "line": 65,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 61,
          "matches": [
            "ldpc"
          ],
          "snippet": {
            "start_line": 55,
            "end_line": 67,
            "lines": [
              {
                "line": 55,
                "text": "    int value = qEnvironmentVariableIntValue(\"JS8_LDPC_FEEDBACK\", &ok);"
              },
              {
                "line": 56,
                "text": "    return ok ? value != 0 : true;"
              },
              {
                "line": 57,
                "text": "}"
              },
              {
                "line": 58,
                "text": ""
              },
              {
                "line": 59,
                "text": "inline int ldpcFeedbackMaxPasses() {"
              },
              {
                "line": 60,
                "text": "    bool ok = false;"
              },
              {
                "line": 61,
                "text": "    int value = qEnvironmentVariableIntValue(\"JS8_LDPC_MAX_PASSES\", &ok);"
              },
              {
                "line": 62,
                "text": ""
              },
              {
                "line": 63,
                "text": "    if (!ok)"
              },
              {
                "line": 64,
                "text": "        return LDPC_FEEDBACK_MAX_PASSES_DEFAULT;"
              },
              {
                "line": 65,
                "text": ""
              },
              {
                "line": 66,
                "text": "    return std::clamp(value, 1, LDPC_FEEDBACK_MAX_PASSES_DEFAULT);"
              },
              {
                "line": 67,
                "text": "}"
              }
            ]
          }
        },
        {
          "line": 66,
          "matches": [
            "ldpc"
          ],
          "snippet": {
            "start_line": 60,
            "end_line": 72,
            "lines": [
              {
                "line": 60,
                "text": "    bool ok = false;"
              },
              {
                "line": 61,
                "text": "    int value = qEnvironmentVariableIntValue(\"JS8_LDPC_MAX_PASSES\", &ok);"
              },
              {
                "line": 62,
                "text": ""
              },
              {
                "line": 63,
                "text": "    if (!ok)"
              },
              {
                "line": 64,
                "text": "        return LDPC_FEEDBACK_MAX_PASSES_DEFAULT;"
              },
              {
                "line": 65,
                "text": ""
              },
              {
                "line": 66,
                "text": "    return std::clamp(value, 1, LDPC_FEEDBACK_MAX_PASSES_DEFAULT);"
              },
              {
                "line": 67,
                "text": "}"
              },
              {
                "line": 68,
                "text": ""
              },
              {
                "line": 69,
                "text": "template <std::size_t N>"
              },
              {
                "line": 70,
                "text": "void refineLlrsWithLdpcFeedback(std::array<float, N> const &llrIn,"
              },
              {
                "line": 71,
                "text": "                                std::array<int8_t, N> const &cw,"
              },
              {
                "line": 72,
                "text": "                                float erasureThreshold,"
              }
            ]
          }
        },
        {
          "line": 73,
          "matches": [
            "LLR"
          ],
          "snippet": {
            "start_line": 67,
            "end_line": 79,
            "lines": [
              {
                "line": 67,
                "text": "}"
              },
              {
                "line": 68,
                "text": ""
              },
              {
                "line": 69,
                "text": "template <std::size_t N>"
              },
              {
                "line": 70,
                "text": "void refineLlrsWithLdpcFeedback(std::array<float, N> const &llrIn,"
              },
              {
                "line": 71,
                "text": "                                std::array<int8_t, N> const &cw,"
              },
              {
                "line": 72,
                "text": "                                float erasureThreshold,"
              },
              {
                "line": 73,
                "text": "                                std::array<float, N> &llrOut,"
              },
              {
                "line": 74,
                "text": "                                int &confidentCount, int &uncertainCount) {"
              },
              {
                "line": 75,
                "text": "    llrOut = llrIn;"
              },
              {
                "line": 76,
                "text": "    confidentCount = 0;"
              },
              {
                "line": 77,
                "text": "    uncertainCount = 0;"
              },
              {
                "line": 78,
                "text": ""
              },
              {
                "line": 79,
                "text": "    for (std::size_t i = 0; i < llrOut.size(); ++i) {"
              }
            ]
          }
        },
        {
          "line": 79,
          "matches": [
            "LLR"
          ],
          "snippet": {
            "start_line": 73,
            "end_line": 85,
            "lines": [
              {
                "line": 73,
                "text": "                                std::array<float, N> &llrOut,"
              },
              {
                "line": 74,
                "text": "                                int &confidentCount, int &uncertainCount) {"
              },
              {
                "line": 75,
                "text": "    llrOut = llrIn;"
              },
              {
                "line": 76,
                "text": "    confidentCount = 0;"
              },
              {
                "line": 77,
                "text": "    uncertainCount = 0;"
              },
              {
                "line": 78,
                "text": ""
              },
              {
                "line": 79,
                "text": "    for (std::size_t i = 0; i < llrOut.size(); ++i) {"
              },
              {
                "line": 80,
                "text": "        float &value = llrOut[i];"
              },
              {
                "line": 81,
                "text": ""
              },
              {
                "line": 82,
                "text": "        if (!std::isfinite(value)) {"
              },
              {
                "line": 83,
                "text": "            value = 0.0f;"
              },
              {
                "line": 84,
                "text": "            ++uncertainCount;"
              },
              {
                "line": 85,
                "text": "            continue;"
              }
            ]
          }
        },
        {
          "line": 92,
          "matches": [
            "LLR"
          ],
          "snippet": {
            "start_line": 86,
            "end_line": 98,
            "lines": [
              {
                "line": 86,
                "text": "        }"
              },
              {
                "line": 87,
                "text": ""
              },
              {
                "line": 88,
                "text": "        bool const bitOne = cw[i] != 0;"
              },
              {
                "line": 89,
                "text": "        float const mag = std::abs(value);"
              },
              {
                "line": 90,
                "text": "        bool const signMatch = (value >= 0.0f) == bitOne;"
              },
              {
                "line": 91,
                "text": ""
              },
              {
                "line": 92,
                "text": "        if (signMatch && mag >= LLR_FEEDBACK_CONFIDENT_MIN) {"
              },
              {
                "line": 93,
                "text": "            ++confidentCount;"
              },
              {
                "line": 94,
                "text": "            float boosted = mag * LLR_FEEDBACK_CONFIDENT_BOOST;"
              },
              {
                "line": 95,
                "text": "            boosted = std::clamp(boosted, 0.0f, LLR_FEEDBACK_MAX_MAG);"
              },
              {
                "line": 96,
                "text": "            value = bitOne ? boosted : -boosted;"
              },
              {
                "line": 97,
                "text": "        } else if (!signMatch || mag <= LLR_FEEDBACK_UNCERTAIN_MAX) {"
              },
              {
                "line": 98,
                "text": "            ++uncertainCount;"
              }
            ]
          }
        },
        {
          "line": 97,
          "matches": [
            "LLR"
          ],
          "snippet": {
            "start_line": 91,
            "end_line": 103,
            "lines": [
              {
                "line": 91,
                "text": ""
              },
              {
                "line": 92,
                "text": "        if (signMatch && mag >= LLR_FEEDBACK_CONFIDENT_MIN) {"
              },
              {
                "line": 93,
                "text": "            ++confidentCount;"
              },
              {
                "line": 94,
                "text": "            float boosted = mag * LLR_FEEDBACK_CONFIDENT_BOOST;"
              },
              {
                "line": 95,
                "text": "            boosted = std::clamp(boosted, 0.0f, LLR_FEEDBACK_MAX_MAG);"
              },
              {
                "line": 96,
                "text": "            value = bitOne ? boosted : -boosted;"
              },
              {
                "line": 97,
                "text": "        } else if (!signMatch || mag <= LLR_FEEDBACK_UNCERTAIN_MAX) {"
              },
              {
                "line": 98,
                "text": "            ++uncertainCount;"
              },
              {
                "line": 99,
                "text": "            float shrunk = mag * LLR_FEEDBACK_UNCERTAIN_SHRINK;"
              },
              {
                "line": 100,
                "text": ""
              },
              {
                "line": 101,
                "text": "            if (erasureThreshold > 0.0f && shrunk < erasureThreshold) {"
              },
              {
                "line": 102,
                "text": "                value = 0.0f;"
              },
              {
                "line": 103,
                "text": "            } else {"
              }
            ]
          }
        }
      ]
    },
    {
      "path": "JS8_Mode/DecodedText.cpp",
      "exists": true,
      "bytes": 10173,
      "sha256": "1f3d3a687a0bae5ad690bceb93b80b5854dfdfd00b1fd16487acfc83e7faf65c",
      "line_count": 344,
      "phase_hits": {
        "timing_submode": 0,
        "symbol_to_soft_bits": 0,
        "bit_order_interleaver": 24,
        "whitening_erasure": 0,
        "ldpc_decode": 0,
        "message91_crc_text": 108
      },
      "function_blocks": [
        {
          "function": "submodeChar",
          "line": 33,
          "signature": "QChar submodeChar(int const submode) {",
          "snippet": {
            "start_line": 19,
            "end_line": 47,
            "lines": [
              {
                "line": 19,
                "text": "// denote it as being sketchy."
              },
              {
                "line": 20,
                "text": ""
              },
              {
                "line": 21,
                "text": "constexpr auto QUALITY_THRESHOLD = 0.17f;"
              },
              {
                "line": 22,
                "text": "} // namespace"
              },
              {
                "line": 23,
                "text": ""
              },
              {
                "line": 24,
                "text": "/******************************************************************************/"
              },
              {
                "line": 25,
                "text": "// Local Routines"
              },
              {
                "line": 26,
                "text": "/******************************************************************************/"
              },
              {
                "line": 27,
                "text": ""
              },
              {
                "line": 28,
                "text": "namespace {"
              },
              {
                "line": 29,
                "text": "// Translation of standard submode IDs to their character equivalents."
              },
              {
                "line": 30,
                "text": "// this is only used when writing out to ALL.TXT, so we've defined it"
              },
              {
                "line": 31,
                "text": "// here, but arguably it should be part of JS8::Submode or Varicode."
              },
              {
                "line": 32,
                "text": ""
              },
              {
                "line": 33,
                "text": "QChar submodeChar(int const submode) {"
              },
              {
                "line": 34,
                "text": "    switch (submode) {"
              },
              {
                "line": 35,
                "text": "    case Varicode::SubmodeType::JS8CallNormal:"
              },
              {
                "line": 36,
                "text": "        return 'A';"
              },
              {
                "line": 37,
                "text": "    case Varicode::SubmodeType::JS8CallFast:"
              },
              {
                "line": 38,
                "text": "        return 'B';"
              },
              {
                "line": 39,
                "text": "    case Varicode::SubmodeType::JS8CallTurbo:"
              },
              {
                "line": 40,
                "text": "        return 'C';"
              },
              {
                "line": 41,
                "text": "    case Varicode::SubmodeType::JS8CallSlow:"
              },
              {
                "line": 42,
                "text": "        return 'E';"
              },
              {
                "line": 43,
                "text": "    case Varicode::SubmodeType::JS8CallUltra:"
              },
              {
                "line": 44,
                "text": "        return 'I';"
              },
              {
                "line": 45,
                "text": "    default:"
              },
              {
                "line": 46,
                "text": "        return '~';"
              },
              {
                "line": 47,
                "text": "    }"
              }
            ]
          }
        },
        {
          "function": "buildCompound",
          "line": 54,
          "signature": "QString buildCompound(QStringList const &parts) {",
          "snippet": {
            "start_line": 40,
            "end_line": 68,
            "lines": [
              {
                "line": 40,
                "text": "        return 'C';"
              },
              {
                "line": 41,
                "text": "    case Varicode::SubmodeType::JS8CallSlow:"
              },
              {
                "line": 42,
                "text": "        return 'E';"
              },
              {
                "line": 43,
                "text": "    case Varicode::SubmodeType::JS8CallUltra:"
              },
              {
                "line": 44,
                "text": "        return 'I';"
              },
              {
                "line": 45,
                "text": "    default:"
              },
              {
                "line": 46,
                "text": "        return '~';"
              },
              {
                "line": 47,
                "text": "    }"
              },
              {
                "line": 48,
                "text": "}"
              },
              {
                "line": 49,
                "text": ""
              },
              {
                "line": 50,
                "text": "// Create and return a potentially compound call from the provided"
              },
              {
                "line": 51,
                "text": "// parts; the parts are at this point guaranteed to be at least of"
              },
              {
                "line": 52,
                "text": "// size 2, but any part might be empty."
              },
              {
                "line": 53,
                "text": ""
              },
              {
                "line": 54,
                "text": "QString buildCompound(QStringList const &parts) {"
              },
              {
                "line": 55,
                "text": "    auto subset = parts.mid(0, 2);"
              },
              {
                "line": 56,
                "text": "    subset.removeAll(\"\");"
              },
              {
                "line": 57,
                "text": "    return subset.join('/');"
              },
              {
                "line": 58,
                "text": "}"
              },
              {
                "line": 59,
                "text": "} // namespace"
              },
              {
                "line": 60,
                "text": ""
              },
              {
                "line": 61,
                "text": "/******************************************************************************/"
              },
              {
                "line": 62,
                "text": "// Private Implementation"
              },
              {
                "line": 63,
                "text": "/******************************************************************************/"
              },
              {
                "line": 64,
                "text": ""
              },
              {
                "line": 65,
                "text": "// Core constructor, called by the two public constructors."
              },
              {
                "line": 66,
                "text": "// Attempts to unpack, using the unpack strategies defined"
              },
              {
                "line": 67,
                "text": "// in the order of the unpack strategies array, until one"
              },
              {
                "line": 68,
                "text": "// of them works or all of them have failed."
              }
            ]
          }
        },
        {
          "function": "DecodedText::tryUnpackFastData",
          "line": 109,
          "signature": "bool DecodedText::tryUnpackFastData(QString const &m) {",
          "snippet": {
            "start_line": 95,
            "end_line": 123,
            "lines": [
              {
                "line": 95,
                "text": "    for (auto unpack : unpackStrategies) {"
              },
              {
                "line": 96,
                "text": "        if ((this->*unpack)(m))"
              },
              {
                "line": 97,
                "text": "            break;"
              },
              {
                "line": 98,
                "text": "    }"
              },
              {
                "line": 99,
                "text": "}"
              },
              {
                "line": 100,
                "text": ""
              },
              {
                "line": 101,
                "text": "/**"
              },
              {
                "line": 102,
                "text": " * @private"
              },
              {
                "line": 103,
                "text": " * @brief Try to unpack fast data message (private)"
              },
              {
                "line": 104,
                "text": " *"
              },
              {
                "line": 105,
                "text": " * @param m"
              },
              {
                "line": 106,
                "text": " * @return true"
              },
              {
                "line": 107,
                "text": " * @return false"
              },
              {
                "line": 108,
                "text": " */"
              },
              {
                "line": 109,
                "text": "bool DecodedText::tryUnpackFastData(QString const &m) {"
              },
              {
                "line": 110,
                "text": "    if ((bits_ & Varicode::JS8CallData) != Varicode::JS8CallData)"
              },
              {
                "line": 111,
                "text": "        return false;"
              },
              {
                "line": 112,
                "text": ""
              },
              {
                "line": 113,
                "text": "    if (auto const data = Varicode::unpackFastDataMessage(m); data.isEmpty()) {"
              },
              {
                "line": 114,
                "text": "        return false;"
              },
              {
                "line": 115,
                "text": "    } else {"
              },
              {
                "line": 116,
                "text": "        message_ = data;"
              },
              {
                "line": 117,
                "text": "        frameType_ = Varicode::FrameData;"
              },
              {
                "line": 118,
                "text": ""
              },
              {
                "line": 119,
                "text": "        return true;"
              },
              {
                "line": 120,
                "text": "    }"
              },
              {
                "line": 121,
                "text": "}"
              },
              {
                "line": 122,
                "text": ""
              },
              {
                "line": 123,
                "text": "/**"
              }
            ]
          }
        },
        {
          "function": "DecodedText::tryUnpackData",
          "line": 131,
          "signature": "bool DecodedText::tryUnpackData(QString const &m) {",
          "snippet": {
            "start_line": 117,
            "end_line": 145,
            "lines": [
              {
                "line": 117,
                "text": "        frameType_ = Varicode::FrameData;"
              },
              {
                "line": 118,
                "text": ""
              },
              {
                "line": 119,
                "text": "        return true;"
              },
              {
                "line": 120,
                "text": "    }"
              },
              {
                "line": 121,
                "text": "}"
              },
              {
                "line": 122,
                "text": ""
              },
              {
                "line": 123,
                "text": "/**"
              },
              {
                "line": 124,
                "text": " * @private"
              },
              {
                "line": 125,
                "text": " * @brief Try to unpack data message (private)"
              },
              {
                "line": 126,
                "text": " *"
              },
              {
                "line": 127,
                "text": " * @param m"
              },
              {
                "line": 128,
                "text": " * @return true"
              },
              {
                "line": 129,
                "text": " * @return false"
              },
              {
                "line": 130,
                "text": " */"
              },
              {
                "line": 131,
                "text": "bool DecodedText::tryUnpackData(QString const &m) {"
              },
              {
                "line": 132,
                "text": "    if ((bits_ & Varicode::JS8CallData) == Varicode::JS8CallData)"
              },
              {
                "line": 133,
                "text": "        return false;"
              },
              {
                "line": 134,
                "text": ""
              },
              {
                "line": 135,
                "text": "    if (auto const data = Varicode::unpackDataMessage(m); data.isEmpty()) {"
              },
              {
                "line": 136,
                "text": "        return false;"
              },
              {
                "line": 137,
                "text": "    } else {"
              },
              {
                "line": 138,
                "text": "        message_ = data;"
              },
              {
                "line": 139,
                "text": "        frameType_ = Varicode::FrameData;"
              },
              {
                "line": 140,
                "text": ""
              },
              {
                "line": 141,
                "text": "        return true;"
              },
              {
                "line": 142,
                "text": "    }"
              },
              {
                "line": 143,
                "text": "}"
              },
              {
                "line": 144,
                "text": ""
              },
              {
                "line": 145,
                "text": "/**"
              }
            ]
          }
        },
        {
          "function": "DecodedText::tryUnpackHeartbeat",
          "line": 153,
          "signature": "bool DecodedText::tryUnpackHeartbeat(QString const &m) {",
          "snippet": {
            "start_line": 139,
            "end_line": 167,
            "lines": [
              {
                "line": 139,
                "text": "        frameType_ = Varicode::FrameData;"
              },
              {
                "line": 140,
                "text": ""
              },
              {
                "line": 141,
                "text": "        return true;"
              },
              {
                "line": 142,
                "text": "    }"
              },
              {
                "line": 143,
                "text": "}"
              },
              {
                "line": 144,
                "text": ""
              },
              {
                "line": 145,
                "text": "/**"
              },
              {
                "line": 146,
                "text": " * @private"
              },
              {
                "line": 147,
                "text": " * @brief Try to unpack heartbeat message (private)"
              },
              {
                "line": 148,
                "text": " *"
              },
              {
                "line": 149,
                "text": " * @param m"
              },
              {
                "line": 150,
                "text": " * @return true"
              },
              {
                "line": 151,
                "text": " * @return false"
              },
              {
                "line": 152,
                "text": " */"
              },
              {
                "line": 153,
                "text": "bool DecodedText::tryUnpackHeartbeat(QString const &m) {"
              },
              {
                "line": 154,
                "text": "    if ((bits_ & Varicode::JS8CallData) == Varicode::JS8CallData)"
              },
              {
                "line": 155,
                "text": "        return false;"
              },
              {
                "line": 156,
                "text": ""
              },
              {
                "line": 157,
                "text": "    bool isAlt = false;"
              },
              {
                "line": 158,
                "text": "    quint8 type = Varicode::FrameUnknown;"
              },
              {
                "line": 159,
                "text": "    quint8 bits3 = 0;"
              },
              {
                "line": 160,
                "text": "    auto const parts ="
              },
              {
                "line": 161,
                "text": "        Varicode::unpackHeartbeatMessage(m, &type, &isAlt, &bits3);"
              },
              {
                "line": 162,
                "text": ""
              },
              {
                "line": 163,
                "text": "    if (parts.length() < 2)"
              },
              {
                "line": 164,
                "text": "        return false;"
              },
              {
                "line": 165,
                "text": ""
              },
              {
                "line": 166,
                "text": "    // Heartbeat Alt Type"
              },
              {
                "line": 167,
                "text": "    // ------------------"
              }
            ]
          }
        },
        {
          "function": "DecodedText::tryUnpackCompound",
          "line": 198,
          "signature": "bool DecodedText::tryUnpackCompound(QString const &m) {",
          "snippet": {
            "start_line": 184,
            "end_line": 212,
            "lines": [
              {
                "line": 184,
                "text": ""
              },
              {
                "line": 185,
                "text": "    message_ += ' ' % extra_ % ' ';"
              },
              {
                "line": 186,
                "text": ""
              },
              {
                "line": 187,
                "text": "    return true;"
              },
              {
                "line": 188,
                "text": "}"
              },
              {
                "line": 189,
                "text": ""
              },
              {
                "line": 190,
                "text": "/**"
              },
              {
                "line": 191,
                "text": " * @private"
              },
              {
                "line": 192,
                "text": " * @brief Try to unpack compound message (private)"
              },
              {
                "line": 193,
                "text": " *"
              },
              {
                "line": 194,
                "text": " * @param m"
              },
              {
                "line": 195,
                "text": " * @return true"
              },
              {
                "line": 196,
                "text": " * @return false"
              },
              {
                "line": 197,
                "text": " */"
              },
              {
                "line": 198,
                "text": "bool DecodedText::tryUnpackCompound(QString const &m) {"
              },
              {
                "line": 199,
                "text": "    quint8 type = Varicode::FrameUnknown;"
              },
              {
                "line": 200,
                "text": "    quint8 bits3 = 0;"
              },
              {
                "line": 201,
                "text": "    auto const parts = Varicode::unpackCompoundMessage(m, &type, &bits3);"
              },
              {
                "line": 202,
                "text": ""
              },
              {
                "line": 203,
                "text": "    if (parts.length() < 2 ||"
              },
              {
                "line": 204,
                "text": "        (bits_ & Varicode::JS8CallData) == Varicode::JS8CallData)"
              },
              {
                "line": 205,
                "text": "        return false;"
              },
              {
                "line": 206,
                "text": ""
              },
              {
                "line": 207,
                "text": "    frameType_ = type;"
              },
              {
                "line": 208,
                "text": "    extra_ = parts.mid(2).join(' ');"
              },
              {
                "line": 209,
                "text": "    compound_ = buildCompound(parts);"
              },
              {
                "line": 210,
                "text": ""
              },
              {
                "line": 211,
                "text": "    if (type == Varicode::FrameCompound) {"
              },
              {
                "line": 212,
                "text": "        message_ = compound_ % \": \";"
              }
            ]
          }
        },
        {
          "function": "DecodedText::tryUnpackDirected",
          "line": 232,
          "signature": "bool DecodedText::tryUnpackDirected(QString const &m) {",
          "snippet": {
            "start_line": 218,
            "end_line": 246,
            "lines": [
              {
                "line": 218,
                "text": "        directed_ += parts.mid(2);"
              },
              {
                "line": 219,
                "text": "    }"
              },
              {
                "line": 220,
                "text": ""
              },
              {
                "line": 221,
                "text": "    return true;"
              },
              {
                "line": 222,
                "text": "}"
              },
              {
                "line": 223,
                "text": ""
              },
              {
                "line": 224,
                "text": "/**"
              },
              {
                "line": 225,
                "text": " * @private"
              },
              {
                "line": 226,
                "text": " * @brief Try to unpack directed message (private)"
              },
              {
                "line": 227,
                "text": " *"
              },
              {
                "line": 228,
                "text": " * @param m"
              },
              {
                "line": 229,
                "text": " * @return true"
              },
              {
                "line": 230,
                "text": " * @return false"
              },
              {
                "line": 231,
                "text": " */"
              },
              {
                "line": 232,
                "text": "bool DecodedText::tryUnpackDirected(QString const &m) {"
              },
              {
                "line": 233,
                "text": "    if ((bits_ & Varicode::JS8CallData) == Varicode::JS8CallData)"
              },
              {
                "line": 234,
                "text": "        return false;"
              },
              {
                "line": 235,
                "text": ""
              },
              {
                "line": 236,
                "text": "    quint8 type = Varicode::FrameUnknown;"
              },
              {
                "line": 237,
                "text": "    QStringList const parts = Varicode::unpackDirectedMessage(m, &type);"
              },
              {
                "line": 238,
                "text": ""
              },
              {
                "line": 239,
                "text": "    if (parts.isEmpty())"
              },
              {
                "line": 240,
                "text": "        return false;"
              },
              {
                "line": 241,
                "text": ""
              },
              {
                "line": 242,
                "text": "    switch (parts.length()) {"
              },
              {
                "line": 243,
                "text": "    case 3: // Directed message         => \"0: 12 \""
              },
              {
                "line": 244,
                "text": "    case 4: // Directed numeric message => \"0: 12 3 \""
              },
              {
                "line": 245,
                "text": "        message_ ="
              },
              {
                "line": 246,
                "text": "            parts.at(0) % \": \" % parts.at(1) % parts.mid(2).join(' ') % ' ';"
              }
            ]
          }
        },
        {
          "function": "DecodedText::messageWords",
          "line": 305,
          "signature": "QStringList DecodedText::messageWords() const {",
          "snippet": {
            "start_line": 291,
            "end_line": 319,
            "lines": [
              {
                "line": 291,
                "text": " */"
              },
              {
                "line": 292,
                "text": "DecodedText::DecodedText(QString const &frame, int const bits,"
              },
              {
                "line": 293,
                "text": "                         int const submode)"
              },
              {
                "line": 294,
                "text": "    : DecodedText(frame, bits, submode, false, 0, 0, 0.0f, 0.0f) {}"
              },
              {
                "line": 295,
                "text": ""
              },
              {
                "line": 296,
                "text": "// Simple word split for free text messages; preallocate memory for"
              },
              {
                "line": 297,
                "text": "// efficiency; add whole message as item 0 to mimic regular expression"
              },
              {
                "line": 298,
                "text": "// capture list."
              },
              {
                "line": 299,
                "text": ""
              },
              {
                "line": 300,
                "text": "/**"
              },
              {
                "line": 301,
                "text": " * @brief Get the message words"
              },
              {
                "line": 302,
                "text": " *"
              },
              {
                "line": 303,
                "text": " * @return QStringList"
              },
              {
                "line": 304,
                "text": " */"
              },
              {
                "line": 305,
                "text": "QStringList DecodedText::messageWords() const {"
              },
              {
                "line": 306,
                "text": "    QStringList words;"
              },
              {
                "line": 307,
                "text": ""
              },
              {
                "line": 308,
                "text": "    words.reserve(message_.count(' ') + 2);"
              },
              {
                "line": 309,
                "text": "    words.append(message_);"
              },
              {
                "line": 310,
                "text": "    words.append(message_.split(' ', Qt::SkipEmptyParts));"
              },
              {
                "line": 311,
                "text": ""
              },
              {
                "line": 312,
                "text": "    return words;"
              },
              {
                "line": 313,
                "text": "}"
              },
              {
                "line": 314,
                "text": ""
              },
              {
                "line": 315,
                "text": "// Format as a string suitable for appending to ALL.TXT. Original"
              },
              {
                "line": 316,
                "text": "// code has no space between time and SNR; matching that here."
              },
              {
                "line": 317,
                "text": ""
              },
              {
                "line": 318,
                "text": "/**"
              },
              {
                "line": 319,
                "text": " * @brief Get the string representation suitable for ALL.TXT"
              }
            ]
          }
        },
        {
          "function": "DecodedText::string",
          "line": 323,
          "signature": "QString DecodedText::string() const {",
          "snippet": {
            "start_line": 309,
            "end_line": 337,
            "lines": [
              {
                "line": 309,
                "text": "    words.append(message_);"
              },
              {
                "line": 310,
                "text": "    words.append(message_.split(' ', Qt::SkipEmptyParts));"
              },
              {
                "line": 311,
                "text": ""
              },
              {
                "line": 312,
                "text": "    return words;"
              },
              {
                "line": 313,
                "text": "}"
              },
              {
                "line": 314,
                "text": ""
              },
              {
                "line": 315,
                "text": "// Format as a string suitable for appending to ALL.TXT. Original"
              },
              {
                "line": 316,
                "text": "// code has no space between time and SNR; matching that here."
              },
              {
                "line": 317,
                "text": ""
              },
              {
                "line": 318,
                "text": "/**"
              },
              {
                "line": 319,
                "text": " * @brief Get the string representation suitable for ALL.TXT"
              },
              {
                "line": 320,
                "text": " *"
              },
              {
                "line": 321,
                "text": " * @return QString"
              },
              {
                "line": 322,
                "text": " */"
              },
              {
                "line": 323,
                "text": "QString DecodedText::string() const {"
              },
              {
                "line": 324,
                "text": "    struct hour_minute_second hms = decode_time(time_);"
              },
              {
                "line": 325,
                "text": ""
              },
              {
                "line": 326,
                "text": "    return QStringLiteral(\"%1:%2:%3%4 %5 %6 %7  %8         %9   \")"
              },
              {
                "line": 327,
                "text": "        .arg(hms.hour, 2, 10, QChar('0'))   // Right-aligned integer with 2"
              },
              {
                "line": 328,
                "text": "                                            // characters, padded with zeroes."
              },
              {
                "line": 329,
                "text": "        .arg(hms.minute, 2, 10, QChar('0')) // Right-aligned integer with 2"
              },
              {
                "line": 330,
                "text": "                                            // characters, padded with zeroes."
              },
              {
                "line": 331,
                "text": "        .arg(hms.second, 2, 10, QChar('0')) // Right-aligned integer with 2"
              },
              {
                "line": 332,
                "text": "                                            // characters, padded with zeroes."
              },
              {
                "line": 333,
                "text": "        .arg(snr_, 3, 10, QChar(' '))       // Right-aligned integer with 3"
              },
              {
                "line": 334,
                "text": "                                            // characters, padded with spaces"
              },
              {
                "line": 335,
                "text": "        .arg(dt_, 4, 'f', 1) // Right-aligned float with 1 decimal point"
              },
              {
                "line": 336,
                "text": "        .arg(frequencyOffset_, 4, 10,"
              },
              {
                "line": 337,
                "text": "             QChar(' ')) // Right-aligned integer with 4 characters, passed with"
              }
            ]
          }
        }
      ],
      "keyword_snippets": [
        {
          "line": 2,
          "matches": [
            "DecodedText",
            "text"
          ],
          "snippet": {
            "start_line": 1,
            "end_line": 8,
            "lines": [
              {
                "line": 1,
                "text": "/**"
              },
              {
                "line": 2,
                "text": " * @file DecodedText.cpp"
              },
              {
                "line": 3,
                "text": " * @brief Implementation of DecodedText class"
              },
              {
                "line": 4,
                "text": " */"
              },
              {
                "line": 5,
                "text": ""
              },
              {
                "line": 6,
                "text": "#include \"DecodedText.h\""
              },
              {
                "line": 7,
                "text": "#include \"JS8_Include/commons.h\""
              },
              {
                "line": 8,
                "text": "#include <JS8_Main/Varicode.h>"
              }
            ]
          }
        },
        {
          "line": 6,
          "matches": [
            "DecodedText",
            "text"
          ],
          "snippet": {
            "start_line": 1,
            "end_line": 12,
            "lines": [
              {
                "line": 1,
                "text": "/**"
              },
              {
                "line": 2,
                "text": " * @file DecodedText.cpp"
              },
              {
                "line": 3,
                "text": " * @brief Implementation of DecodedText class"
              },
              {
                "line": 4,
                "text": " */"
              },
              {
                "line": 5,
                "text": ""
              },
              {
                "line": 6,
                "text": "#include \"DecodedText.h\""
              },
              {
                "line": 7,
                "text": "#include \"JS8_Include/commons.h\""
              },
              {
                "line": 8,
                "text": "#include <JS8_Main/Varicode.h>"
              },
              {
                "line": 9,
                "text": ""
              },
              {
                "line": 10,
                "text": "#include <QStringBuilder>"
              },
              {
                "line": 11,
                "text": ""
              },
              {
                "line": 12,
                "text": "/******************************************************************************/"
              }
            ]
          }
        },
        {
          "line": 31,
          "matches": [
            "Varicode"
          ],
          "snippet": {
            "start_line": 25,
            "end_line": 37,
            "lines": [
              {
                "line": 25,
                "text": "// Local Routines"
              },
              {
                "line": 26,
                "text": "/******************************************************************************/"
              },
              {
                "line": 27,
                "text": ""
              },
              {
                "line": 28,
                "text": "namespace {"
              },
              {
                "line": 29,
                "text": "// Translation of standard submode IDs to their character equivalents."
              },
              {
                "line": 30,
                "text": "// this is only used when writing out to ALL.TXT, so we've defined it"
              },
              {
                "line": 31,
                "text": "// here, but arguably it should be part of JS8::Submode or Varicode."
              },
              {
                "line": 32,
                "text": ""
              },
              {
                "line": 33,
                "text": "QChar submodeChar(int const submode) {"
              },
              {
                "line": 34,
                "text": "    switch (submode) {"
              },
              {
                "line": 35,
                "text": "    case Varicode::SubmodeType::JS8CallNormal:"
              },
              {
                "line": 36,
                "text": "        return 'A';"
              },
              {
                "line": 37,
                "text": "    case Varicode::SubmodeType::JS8CallFast:"
              }
            ]
          }
        },
        {
          "line": 37,
          "matches": [
            "Varicode"
          ],
          "snippet": {
            "start_line": 31,
            "end_line": 43,
            "lines": [
              {
                "line": 31,
                "text": "// here, but arguably it should be part of JS8::Submode or Varicode."
              },
              {
                "line": 32,
                "text": ""
              },
              {
                "line": 33,
                "text": "QChar submodeChar(int const submode) {"
              },
              {
                "line": 34,
                "text": "    switch (submode) {"
              },
              {
                "line": 35,
                "text": "    case Varicode::SubmodeType::JS8CallNormal:"
              },
              {
                "line": 36,
                "text": "        return 'A';"
              },
              {
                "line": 37,
                "text": "    case Varicode::SubmodeType::JS8CallFast:"
              },
              {
                "line": 38,
                "text": "        return 'B';"
              },
              {
                "line": 39,
                "text": "    case Varicode::SubmodeType::JS8CallTurbo:"
              },
              {
                "line": 40,
                "text": "        return 'C';"
              },
              {
                "line": 41,
                "text": "    case Varicode::SubmodeType::JS8CallSlow:"
              },
              {
                "line": 42,
                "text": "        return 'E';"
              },
              {
                "line": 43,
                "text": "    case Varicode::SubmodeType::JS8CallUltra:"
              }
            ]
          }
        },
        {
          "line": 41,
          "matches": [
            "Varicode"
          ],
          "snippet": {
            "start_line": 35,
            "end_line": 47,
            "lines": [
              {
                "line": 35,
                "text": "    case Varicode::SubmodeType::JS8CallNormal:"
              },
              {
                "line": 36,
                "text": "        return 'A';"
              },
              {
                "line": 37,
                "text": "    case Varicode::SubmodeType::JS8CallFast:"
              },
              {
                "line": 38,
                "text": "        return 'B';"
              },
              {
                "line": 39,
                "text": "    case Varicode::SubmodeType::JS8CallTurbo:"
              },
              {
                "line": 40,
                "text": "        return 'C';"
              },
              {
                "line": 41,
                "text": "    case Varicode::SubmodeType::JS8CallSlow:"
              },
              {
                "line": 42,
                "text": "        return 'E';"
              },
              {
                "line": 43,
                "text": "    case Varicode::SubmodeType::JS8CallUltra:"
              },
              {
                "line": 44,
                "text": "        return 'I';"
              },
              {
                "line": 45,
                "text": "    default:"
              },
              {
                "line": 46,
                "text": "        return '~';"
              },
              {
                "line": 47,
                "text": "    }"
              }
            ]
          }
        },
        {
          "line": 66,
          "matches": [
            "unpack"
          ],
          "snippet": {
            "start_line": 60,
            "end_line": 72,
            "lines": [
              {
                "line": 60,
                "text": ""
              },
              {
                "line": 61,
                "text": "/******************************************************************************/"
              },
              {
                "line": 62,
                "text": "// Private Implementation"
              },
              {
                "line": 63,
                "text": "/******************************************************************************/"
              },
              {
                "line": 64,
                "text": ""
              },
              {
                "line": 65,
                "text": "// Core constructor, called by the two public constructors."
              },
              {
                "line": 66,
                "text": "// Attempts to unpack, using the unpack strategies defined"
              },
              {
                "line": 67,
                "text": "// in the order of the unpack strategies array, until one"
              },
              {
                "line": 68,
                "text": "// of them works or all of them have failed."
              },
              {
                "line": 69,
                "text": ""
              },
              {
                "line": 70,
                "text": "/**"
              },
              {
                "line": 71,
                "text": " * @private"
              },
              {
                "line": 72,
                "text": " * @brief Construct a new Decoded Text:: Decoded Text object (private)"
              }
            ]
          }
        },
        {
          "line": 72,
          "matches": [
            "text"
          ],
          "snippet": {
            "start_line": 66,
            "end_line": 78,
            "lines": [
              {
                "line": 66,
                "text": "// Attempts to unpack, using the unpack strategies defined"
              },
              {
                "line": 67,
                "text": "// in the order of the unpack strategies array, until one"
              },
              {
                "line": 68,
                "text": "// of them works or all of them have failed."
              },
              {
                "line": 69,
                "text": ""
              },
              {
                "line": 70,
                "text": "/**"
              },
              {
                "line": 71,
                "text": " * @private"
              },
              {
                "line": 72,
                "text": " * @brief Construct a new Decoded Text:: Decoded Text object (private)"
              },
              {
                "line": 73,
                "text": " *"
              },
              {
                "line": 74,
                "text": " * @param frame"
              },
              {
                "line": 75,
                "text": " * @param bits"
              },
              {
                "line": 76,
                "text": " * @param submode"
              },
              {
                "line": 77,
                "text": " * @param isLowConfidence"
              },
              {
                "line": 78,
                "text": " * @param time"
              }
            ]
          }
        },
        {
          "line": 83,
          "matches": [
            "DecodedText",
            "text"
          ],
          "snippet": {
            "start_line": 77,
            "end_line": 89,
            "lines": [
              {
                "line": 77,
                "text": " * @param isLowConfidence"
              },
              {
                "line": 78,
                "text": " * @param time"
              },
              {
                "line": 79,
                "text": " * @param frequencyOffset"
              },
              {
                "line": 80,
                "text": " * @param snr"
              },
              {
                "line": 81,
                "text": " * @param dt"
              },
              {
                "line": 82,
                "text": " */"
              },
              {
                "line": 83,
                "text": "DecodedText::DecodedText(QString const &frame, int bits, int submode,"
              },
              {
                "line": 84,
                "text": "                         bool isLowConfidence, int time, int frequencyOffset,"
              },
              {
                "line": 85,
                "text": "                         float snr, float dt)"
              },
              {
                "line": 86,
                "text": "    : frameType_(Varicode::FrameUnknown), frame_(frame), isAlt_(false),"
              },
              {
                "line": 87,
                "text": "      isHeartbeat_(false), isLowConfidence_(isLowConfidence), message_(frame_),"
              },
              {
                "line": 88,
                "text": "      bits_(bits), submode_(submode), time_(time),"
              },
              {
                "line": 89,
                "text": "      frequencyOffset_(frequencyOffset), snr_(snr), dt_(dt) {"
              }
            ]
          }
        },
        {
          "line": 86,
          "matches": [
            "Varicode"
          ],
          "snippet": {
            "start_line": 80,
            "end_line": 92,
            "lines": [
              {
                "line": 80,
                "text": " * @param snr"
              },
              {
                "line": 81,
                "text": " * @param dt"
              },
              {
                "line": 82,
                "text": " */"
              },
              {
                "line": 83,
                "text": "DecodedText::DecodedText(QString const &frame, int bits, int submode,"
              },
              {
                "line": 84,
                "text": "                         bool isLowConfidence, int time, int frequencyOffset,"
              },
              {
                "line": 85,
                "text": "                         float snr, float dt)"
              },
              {
                "line": 86,
                "text": "    : frameType_(Varicode::FrameUnknown), frame_(frame), isAlt_(false),"
              },
              {
                "line": 87,
                "text": "      isHeartbeat_(false), isLowConfidence_(isLowConfidence), message_(frame_),"
              },
              {
                "line": 88,
                "text": "      bits_(bits), submode_(submode), time_(time),"
              },
              {
                "line": 89,
                "text": "      frequencyOffset_(frequencyOffset), snr_(snr), dt_(dt) {"
              },
              {
                "line": 90,
                "text": "    auto const m = message().trimmed();"
              },
              {
                "line": 91,
                "text": ""
              },
              {
                "line": 92,
                "text": "    if (m.length() < 12 || m.contains(' '))"
              }
            ]
          }
        },
        {
          "line": 95,
          "matches": [
            "unpack"
          ],
          "snippet": {
            "start_line": 89,
            "end_line": 101,
            "lines": [
              {
                "line": 89,
                "text": "      frequencyOffset_(frequencyOffset), snr_(snr), dt_(dt) {"
              },
              {
                "line": 90,
                "text": "    auto const m = message().trimmed();"
              },
              {
                "line": 91,
                "text": ""
              },
              {
                "line": 92,
                "text": "    if (m.length() < 12 || m.contains(' '))"
              },
              {
                "line": 93,
                "text": "        return;"
              },
              {
                "line": 94,
                "text": ""
              },
              {
                "line": 95,
                "text": "    for (auto unpack : unpackStrategies) {"
              },
              {
                "line": 96,
                "text": "        if ((this->*unpack)(m))"
              },
              {
                "line": 97,
                "text": "            break;"
              },
              {
                "line": 98,
                "text": "    }"
              },
              {
                "line": 99,
                "text": "}"
              },
              {
                "line": 100,
                "text": ""
              },
              {
                "line": 101,
                "text": "/**"
              }
            ]
          }
        },
        {
          "line": 96,
          "matches": [
            "unpack"
          ],
          "snippet": {
            "start_line": 90,
            "end_line": 102,
            "lines": [
              {
                "line": 90,
                "text": "    auto const m = message().trimmed();"
              },
              {
                "line": 91,
                "text": ""
              },
              {
                "line": 92,
                "text": "    if (m.length() < 12 || m.contains(' '))"
              },
              {
                "line": 93,
                "text": "        return;"
              },
              {
                "line": 94,
                "text": ""
              },
              {
                "line": 95,
                "text": "    for (auto unpack : unpackStrategies) {"
              },
              {
                "line": 96,
                "text": "        if ((this->*unpack)(m))"
              },
              {
                "line": 97,
                "text": "            break;"
              },
              {
                "line": 98,
                "text": "    }"
              },
              {
                "line": 99,
                "text": "}"
              },
              {
                "line": 100,
                "text": ""
              },
              {
                "line": 101,
                "text": "/**"
              },
              {
                "line": 102,
                "text": " * @private"
              }
            ]
          }
        },
        {
          "line": 103,
          "matches": [
            "message",
            "unpack"
          ],
          "snippet": {
            "start_line": 97,
            "end_line": 109,
            "lines": [
              {
                "line": 97,
                "text": "            break;"
              },
              {
                "line": 98,
                "text": "    }"
              },
              {
                "line": 99,
                "text": "}"
              },
              {
                "line": 100,
                "text": ""
              },
              {
                "line": 101,
                "text": "/**"
              },
              {
                "line": 102,
                "text": " * @private"
              },
              {
                "line": 103,
                "text": " * @brief Try to unpack fast data message (private)"
              },
              {
                "line": 104,
                "text": " *"
              },
              {
                "line": 105,
                "text": " * @param m"
              },
              {
                "line": 106,
                "text": " * @return true"
              },
              {
                "line": 107,
                "text": " * @return false"
              },
              {
                "line": 108,
                "text": " */"
              },
              {
                "line": 109,
                "text": "bool DecodedText::tryUnpackFastData(QString const &m) {"
              }
            ]
          }
        },
        {
          "line": 109,
          "matches": [
            "DecodedText",
            "text",
            "unpack"
          ],
          "snippet": {
            "start_line": 103,
            "end_line": 115,
            "lines": [
              {
                "line": 103,
                "text": " * @brief Try to unpack fast data message (private)"
              },
              {
                "line": 104,
                "text": " *"
              },
              {
                "line": 105,
                "text": " * @param m"
              },
              {
                "line": 106,
                "text": " * @return true"
              },
              {
                "line": 107,
                "text": " * @return false"
              },
              {
                "line": 108,
                "text": " */"
              },
              {
                "line": 109,
                "text": "bool DecodedText::tryUnpackFastData(QString const &m) {"
              },
              {
                "line": 110,
                "text": "    if ((bits_ & Varicode::JS8CallData) != Varicode::JS8CallData)"
              },
              {
                "line": 111,
                "text": "        return false;"
              },
              {
                "line": 112,
                "text": ""
              },
              {
                "line": 113,
                "text": "    if (auto const data = Varicode::unpackFastDataMessage(m); data.isEmpty()) {"
              },
              {
                "line": 114,
                "text": "        return false;"
              },
              {
                "line": 115,
                "text": "    } else {"
              }
            ]
          }
        },
        {
          "line": 113,
          "matches": [
            "message",
            "unpack",
            "Varicode"
          ],
          "snippet": {
            "start_line": 107,
            "end_line": 119,
            "lines": [
              {
                "line": 107,
                "text": " * @return false"
              },
              {
                "line": 108,
                "text": " */"
              },
              {
                "line": 109,
                "text": "bool DecodedText::tryUnpackFastData(QString const &m) {"
              },
              {
                "line": 110,
                "text": "    if ((bits_ & Varicode::JS8CallData) != Varicode::JS8CallData)"
              },
              {
                "line": 111,
                "text": "        return false;"
              },
              {
                "line": 112,
                "text": ""
              },
              {
                "line": 113,
                "text": "    if (auto const data = Varicode::unpackFastDataMessage(m); data.isEmpty()) {"
              },
              {
                "line": 114,
                "text": "        return false;"
              },
              {
                "line": 115,
                "text": "    } else {"
              },
              {
                "line": 116,
                "text": "        message_ = data;"
              },
              {
                "line": 117,
                "text": "        frameType_ = Varicode::FrameData;"
              },
              {
                "line": 118,
                "text": ""
              },
              {
                "line": 119,
                "text": "        return true;"
              }
            ]
          }
        },
        {
          "line": 116,
          "matches": [
            "message"
          ],
          "snippet": {
            "start_line": 110,
            "end_line": 122,
            "lines": [
              {
                "line": 110,
                "text": "    if ((bits_ & Varicode::JS8CallData) != Varicode::JS8CallData)"
              },
              {
                "line": 111,
                "text": "        return false;"
              },
              {
                "line": 112,
                "text": ""
              },
              {
                "line": 113,
                "text": "    if (auto const data = Varicode::unpackFastDataMessage(m); data.isEmpty()) {"
              },
              {
                "line": 114,
                "text": "        return false;"
              },
              {
                "line": 115,
                "text": "    } else {"
              },
              {
                "line": 116,
                "text": "        message_ = data;"
              },
              {
                "line": 117,
                "text": "        frameType_ = Varicode::FrameData;"
              },
              {
                "line": 118,
                "text": ""
              },
              {
                "line": 119,
                "text": "        return true;"
              },
              {
                "line": 120,
                "text": "    }"
              },
              {
                "line": 121,
                "text": "}"
              },
              {
                "line": 122,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 125,
          "matches": [
            "message",
            "unpack"
          ],
          "snippet": {
            "start_line": 119,
            "end_line": 131,
            "lines": [
              {
                "line": 119,
                "text": "        return true;"
              },
              {
                "line": 120,
                "text": "    }"
              },
              {
                "line": 121,
                "text": "}"
              },
              {
                "line": 122,
                "text": ""
              },
              {
                "line": 123,
                "text": "/**"
              },
              {
                "line": 124,
                "text": " * @private"
              },
              {
                "line": 125,
                "text": " * @brief Try to unpack data message (private)"
              },
              {
                "line": 126,
                "text": " *"
              },
              {
                "line": 127,
                "text": " * @param m"
              },
              {
                "line": 128,
                "text": " * @return true"
              },
              {
                "line": 129,
                "text": " * @return false"
              },
              {
                "line": 130,
                "text": " */"
              },
              {
                "line": 131,
                "text": "bool DecodedText::tryUnpackData(QString const &m) {"
              }
            ]
          }
        },
        {
          "line": 131,
          "matches": [
            "DecodedText",
            "text",
            "unpack"
          ],
          "snippet": {
            "start_line": 125,
            "end_line": 137,
            "lines": [
              {
                "line": 125,
                "text": " * @brief Try to unpack data message (private)"
              },
              {
                "line": 126,
                "text": " *"
              },
              {
                "line": 127,
                "text": " * @param m"
              },
              {
                "line": 128,
                "text": " * @return true"
              },
              {
                "line": 129,
                "text": " * @return false"
              },
              {
                "line": 130,
                "text": " */"
              },
              {
                "line": 131,
                "text": "bool DecodedText::tryUnpackData(QString const &m) {"
              },
              {
                "line": 132,
                "text": "    if ((bits_ & Varicode::JS8CallData) == Varicode::JS8CallData)"
              },
              {
                "line": 133,
                "text": "        return false;"
              },
              {
                "line": 134,
                "text": ""
              },
              {
                "line": 135,
                "text": "    if (auto const data = Varicode::unpackDataMessage(m); data.isEmpty()) {"
              },
              {
                "line": 136,
                "text": "        return false;"
              },
              {
                "line": 137,
                "text": "    } else {"
              }
            ]
          }
        },
        {
          "line": 138,
          "matches": [
            "message"
          ],
          "snippet": {
            "start_line": 132,
            "end_line": 144,
            "lines": [
              {
                "line": 132,
                "text": "    if ((bits_ & Varicode::JS8CallData) == Varicode::JS8CallData)"
              },
              {
                "line": 133,
                "text": "        return false;"
              },
              {
                "line": 134,
                "text": ""
              },
              {
                "line": 135,
                "text": "    if (auto const data = Varicode::unpackDataMessage(m); data.isEmpty()) {"
              },
              {
                "line": 136,
                "text": "        return false;"
              },
              {
                "line": 137,
                "text": "    } else {"
              },
              {
                "line": 138,
                "text": "        message_ = data;"
              },
              {
                "line": 139,
                "text": "        frameType_ = Varicode::FrameData;"
              },
              {
                "line": 140,
                "text": ""
              },
              {
                "line": 141,
                "text": "        return true;"
              },
              {
                "line": 142,
                "text": "    }"
              },
              {
                "line": 143,
                "text": "}"
              },
              {
                "line": 144,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 147,
          "matches": [
            "message",
            "unpack"
          ],
          "snippet": {
            "start_line": 141,
            "end_line": 153,
            "lines": [
              {
                "line": 141,
                "text": "        return true;"
              },
              {
                "line": 142,
                "text": "    }"
              },
              {
                "line": 143,
                "text": "}"
              },
              {
                "line": 144,
                "text": ""
              },
              {
                "line": 145,
                "text": "/**"
              },
              {
                "line": 146,
                "text": " * @private"
              },
              {
                "line": 147,
                "text": " * @brief Try to unpack heartbeat message (private)"
              },
              {
                "line": 148,
                "text": " *"
              },
              {
                "line": 149,
                "text": " * @param m"
              },
              {
                "line": 150,
                "text": " * @return true"
              },
              {
                "line": 151,
                "text": " * @return false"
              },
              {
                "line": 152,
                "text": " */"
              },
              {
                "line": 153,
                "text": "bool DecodedText::tryUnpackHeartbeat(QString const &m) {"
              }
            ]
          }
        },
        {
          "line": 153,
          "matches": [
            "DecodedText",
            "text",
            "unpack"
          ],
          "snippet": {
            "start_line": 147,
            "end_line": 159,
            "lines": [
              {
                "line": 147,
                "text": " * @brief Try to unpack heartbeat message (private)"
              },
              {
                "line": 148,
                "text": " *"
              },
              {
                "line": 149,
                "text": " * @param m"
              },
              {
                "line": 150,
                "text": " * @return true"
              },
              {
                "line": 151,
                "text": " * @return false"
              },
              {
                "line": 152,
                "text": " */"
              },
              {
                "line": 153,
                "text": "bool DecodedText::tryUnpackHeartbeat(QString const &m) {"
              },
              {
                "line": 154,
                "text": "    if ((bits_ & Varicode::JS8CallData) == Varicode::JS8CallData)"
              },
              {
                "line": 155,
                "text": "        return false;"
              },
              {
                "line": 156,
                "text": ""
              },
              {
                "line": 157,
                "text": "    bool isAlt = false;"
              },
              {
                "line": 158,
                "text": "    quint8 type = Varicode::FrameUnknown;"
              },
              {
                "line": 159,
                "text": "    quint8 bits3 = 0;"
              }
            ]
          }
        },
        {
          "line": 158,
          "matches": [
            "Varicode"
          ],
          "snippet": {
            "start_line": 152,
            "end_line": 164,
            "lines": [
              {
                "line": 152,
                "text": " */"
              },
              {
                "line": 153,
                "text": "bool DecodedText::tryUnpackHeartbeat(QString const &m) {"
              },
              {
                "line": 154,
                "text": "    if ((bits_ & Varicode::JS8CallData) == Varicode::JS8CallData)"
              },
              {
                "line": 155,
                "text": "        return false;"
              },
              {
                "line": 156,
                "text": ""
              },
              {
                "line": 157,
                "text": "    bool isAlt = false;"
              },
              {
                "line": 158,
                "text": "    quint8 type = Varicode::FrameUnknown;"
              },
              {
                "line": 159,
                "text": "    quint8 bits3 = 0;"
              },
              {
                "line": 160,
                "text": "    auto const parts ="
              },
              {
                "line": 161,
                "text": "        Varicode::unpackHeartbeatMessage(m, &type, &isAlt, &bits3);"
              },
              {
                "line": 162,
                "text": ""
              },
              {
                "line": 163,
                "text": "    if (parts.length() < 2)"
              },
              {
                "line": 164,
                "text": "        return false;"
              }
            ]
          }
        },
        {
          "line": 161,
          "matches": [
            "message",
            "unpack",
            "Varicode"
          ],
          "snippet": {
            "start_line": 155,
            "end_line": 167,
            "lines": [
              {
                "line": 155,
                "text": "        return false;"
              },
              {
                "line": 156,
                "text": ""
              },
              {
                "line": 157,
                "text": "    bool isAlt = false;"
              },
              {
                "line": 158,
                "text": "    quint8 type = Varicode::FrameUnknown;"
              },
              {
                "line": 159,
                "text": "    quint8 bits3 = 0;"
              },
              {
                "line": 160,
                "text": "    auto const parts ="
              },
              {
                "line": 161,
                "text": "        Varicode::unpackHeartbeatMessage(m, &type, &isAlt, &bits3);"
              },
              {
                "line": 162,
                "text": ""
              },
              {
                "line": 163,
                "text": "    if (parts.length() < 2)"
              },
              {
                "line": 164,
                "text": "        return false;"
              },
              {
                "line": 165,
                "text": ""
              },
              {
                "line": 166,
                "text": "    // Heartbeat Alt Type"
              },
              {
                "line": 167,
                "text": "    // ------------------"
              }
            ]
          }
        }
      ]
    },
    {
      "path": "JS8_Main/Varicode.cpp",
      "exists": true,
      "bytes": 72661,
      "sha256": "2b4a877e7dae1a3fdd9141f4dd8af422185977d2e9363ad23ef6bc1918eaf53a",
      "line_count": 2371,
      "phase_hits": {
        "timing_submode": 0,
        "symbol_to_soft_bits": 0,
        "bit_order_interleaver": 231,
        "whitening_erasure": 11,
        "ldpc_decode": 0,
        "message91_crc_text": 734
      },
      "function_blocks": [
        {
          "function": "mwattsToDbm",
          "line": 333,
          "signature": "int mwattsToDbm(int mwatts) {",
          "snippet": {
            "start_line": 319,
            "end_line": 347,
            "lines": [
              {
                "line": 319,
                "text": "    {37, 5000},    //    5W"
              },
              {
                "line": 320,
                "text": "    {40, 10000},   //   10W"
              },
              {
                "line": 321,
                "text": "    {43, 20000},   //   20W"
              },
              {
                "line": 322,
                "text": "    {47, 50000},   //   50W"
              },
              {
                "line": 323,
                "text": "    {50, 100000},  //  100W"
              },
              {
                "line": 324,
                "text": "    {53, 200000},  //  200W"
              },
              {
                "line": 325,
                "text": "    {57, 500000},  //  500W"
              },
              {
                "line": 326,
                "text": "    {60, 1000000}, // 1000W"
              },
              {
                "line": 327,
                "text": "};"
              },
              {
                "line": 328,
                "text": ""
              },
              {
                "line": 329,
                "text": "/*"
              },
              {
                "line": 330,
                "text": " * UTILITIES"
              },
              {
                "line": 331,
                "text": " */"
              },
              {
                "line": 332,
                "text": ""
              },
              {
                "line": 333,
                "text": "int mwattsToDbm(int mwatts) {"
              },
              {
                "line": 334,
                "text": "    int dbm = 0;"
              },
              {
                "line": 335,
                "text": "    auto values = dbm2mw.values();"
              },
              {
                "line": 336,
                "text": "    std::sort(values.begin(), values.end());"
              },
              {
                "line": 337,
                "text": "    foreach (auto mw, values) {"
              },
              {
                "line": 338,
                "text": "        if (mw < mwatts) {"
              },
              {
                "line": 339,
                "text": "            continue;"
              },
              {
                "line": 340,
                "text": "        }"
              },
              {
                "line": 341,
                "text": "        dbm = dbm2mw.key(mw);"
              },
              {
                "line": 342,
                "text": "        break;"
              },
              {
                "line": 343,
                "text": "    }"
              },
              {
                "line": 344,
                "text": ""
              },
              {
                "line": 345,
                "text": "    return dbm;"
              },
              {
                "line": 346,
                "text": "}"
              },
              {
                "line": 347,
                "text": ""
              }
            ]
          }
        },
        {
          "function": "dbmTomwatts",
          "line": 348,
          "signature": "int dbmTomwatts(int dbm) {",
          "snippet": {
            "start_line": 334,
            "end_line": 362,
            "lines": [
              {
                "line": 334,
                "text": "    int dbm = 0;"
              },
              {
                "line": 335,
                "text": "    auto values = dbm2mw.values();"
              },
              {
                "line": 336,
                "text": "    std::sort(values.begin(), values.end());"
              },
              {
                "line": 337,
                "text": "    foreach (auto mw, values) {"
              },
              {
                "line": 338,
                "text": "        if (mw < mwatts) {"
              },
              {
                "line": 339,
                "text": "            continue;"
              },
              {
                "line": 340,
                "text": "        }"
              },
              {
                "line": 341,
                "text": "        dbm = dbm2mw.key(mw);"
              },
              {
                "line": 342,
                "text": "        break;"
              },
              {
                "line": 343,
                "text": "    }"
              },
              {
                "line": 344,
                "text": ""
              },
              {
                "line": 345,
                "text": "    return dbm;"
              },
              {
                "line": 346,
                "text": "}"
              },
              {
                "line": 347,
                "text": ""
              },
              {
                "line": 348,
                "text": "int dbmTomwatts(int dbm) {"
              },
              {
                "line": 349,
                "text": "    if (dbm2mw.contains(dbm)) {"
              },
              {
                "line": 350,
                "text": "        return dbm2mw[dbm];"
              },
              {
                "line": 351,
                "text": "    }"
              },
              {
                "line": 352,
                "text": "    auto iter = dbm2mw.lowerBound(dbm);"
              },
              {
                "line": 353,
                "text": "    if (iter == dbm2mw.end()) {"
              },
              {
                "line": 354,
                "text": "        return dbm2mw.last();"
              },
              {
                "line": 355,
                "text": "    }"
              },
              {
                "line": 356,
                "text": "    return iter.value();"
              },
              {
                "line": 357,
                "text": "}"
              },
              {
                "line": 358,
                "text": ""
              },
              {
                "line": 359,
                "text": "QString Varicode::extendedChars() {"
              },
              {
                "line": 360,
                "text": "    static QString c;"
              },
              {
                "line": 361,
                "text": "    if (c.size() == 0) {"
              },
              {
                "line": 362,
                "text": "        for (quint32 i = 0; i < JSC::prefixSize; i++) {"
              }
            ]
          }
        },
        {
          "function": "Varicode::extendedChars",
          "line": 359,
          "signature": "QString Varicode::extendedChars() {",
          "snippet": {
            "start_line": 345,
            "end_line": 373,
            "lines": [
              {
                "line": 345,
                "text": "    return dbm;"
              },
              {
                "line": 346,
                "text": "}"
              },
              {
                "line": 347,
                "text": ""
              },
              {
                "line": 348,
                "text": "int dbmTomwatts(int dbm) {"
              },
              {
                "line": 349,
                "text": "    if (dbm2mw.contains(dbm)) {"
              },
              {
                "line": 350,
                "text": "        return dbm2mw[dbm];"
              },
              {
                "line": 351,
                "text": "    }"
              },
              {
                "line": 352,
                "text": "    auto iter = dbm2mw.lowerBound(dbm);"
              },
              {
                "line": 353,
                "text": "    if (iter == dbm2mw.end()) {"
              },
              {
                "line": 354,
                "text": "        return dbm2mw.last();"
              },
              {
                "line": 355,
                "text": "    }"
              },
              {
                "line": 356,
                "text": "    return iter.value();"
              },
              {
                "line": 357,
                "text": "}"
              },
              {
                "line": 358,
                "text": ""
              },
              {
                "line": 359,
                "text": "QString Varicode::extendedChars() {"
              },
              {
                "line": 360,
                "text": "    static QString c;"
              },
              {
                "line": 361,
                "text": "    if (c.size() == 0) {"
              },
              {
                "line": 362,
                "text": "        for (quint32 i = 0; i < JSC::prefixSize; i++) {"
              },
              {
                "line": 363,
                "text": "            if (JSC::prefix[i].size != 1) {"
              },
              {
                "line": 364,
                "text": "                continue;"
              },
              {
                "line": 365,
                "text": "            }"
              },
              {
                "line": 366,
                "text": "            c.append(QLatin1String(JSC::prefix[i].str, 1));"
              },
              {
                "line": 367,
                "text": "        }"
              },
              {
                "line": 368,
                "text": "    }"
              },
              {
                "line": 369,
                "text": "    return c;"
              },
              {
                "line": 370,
                "text": "}"
              },
              {
                "line": 371,
                "text": ""
              },
              {
                "line": 372,
                "text": "QString Varicode::escape(const QString &text) {"
              },
              {
                "line": 373,
                "text": "    static const int size = 6;"
              }
            ]
          }
        },
        {
          "function": "Varicode::escape",
          "line": 372,
          "signature": "QString Varicode::escape(const QString &text) {",
          "snippet": {
            "start_line": 358,
            "end_line": 386,
            "lines": [
              {
                "line": 358,
                "text": ""
              },
              {
                "line": 359,
                "text": "QString Varicode::extendedChars() {"
              },
              {
                "line": 360,
                "text": "    static QString c;"
              },
              {
                "line": 361,
                "text": "    if (c.size() == 0) {"
              },
              {
                "line": 362,
                "text": "        for (quint32 i = 0; i < JSC::prefixSize; i++) {"
              },
              {
                "line": 363,
                "text": "            if (JSC::prefix[i].size != 1) {"
              },
              {
                "line": 364,
                "text": "                continue;"
              },
              {
                "line": 365,
                "text": "            }"
              },
              {
                "line": 366,
                "text": "            c.append(QLatin1String(JSC::prefix[i].str, 1));"
              },
              {
                "line": 367,
                "text": "        }"
              },
              {
                "line": 368,
                "text": "    }"
              },
              {
                "line": 369,
                "text": "    return c;"
              },
              {
                "line": 370,
                "text": "}"
              },
              {
                "line": 371,
                "text": ""
              },
              {
                "line": 372,
                "text": "QString Varicode::escape(const QString &text) {"
              },
              {
                "line": 373,
                "text": "    static const int size = 6;"
              },
              {
                "line": 374,
                "text": "    QString escaped;"
              },
              {
                "line": 375,
                "text": "    escaped.reserve(size * text.size());"
              },
              {
                "line": 376,
                "text": "    for (QString::const_iterator it = text.begin(); it != text.end(); ++it) {"
              },
              {
                "line": 377,
                "text": "        QChar ch = *it;"
              },
              {
                "line": 378,
                "text": "        ushort code = ch.unicode();"
              },
              {
                "line": 379,
                "text": "        if (code < 0x80) {"
              },
              {
                "line": 380,
                "text": "            escaped += ch;"
              },
              {
                "line": 381,
                "text": "        } else {"
              },
              {
                "line": 382,
                "text": "#if JS8_USE_ESCAPE_SUB_CHAR"
              },
              {
                "line": 383,
                "text": "            // escaped += \"\\x1A\"; // substitute char"
              },
              {
                "line": 384,
                "text": "#else"
              },
              {
                "line": 385,
                "text": "            escaped += \"\\\\U\"; // \"U+\"; // substitute char"
              },
              {
                "line": 386,
                "text": "#endif"
              }
            ]
          }
        },
        {
          "function": "Varicode::unescape",
          "line": 394,
          "signature": "QString Varicode::unescape(const QString &text) {",
          "snippet": {
            "start_line": 380,
            "end_line": 408,
            "lines": [
              {
                "line": 380,
                "text": "            escaped += ch;"
              },
              {
                "line": 381,
                "text": "        } else {"
              },
              {
                "line": 382,
                "text": "#if JS8_USE_ESCAPE_SUB_CHAR"
              },
              {
                "line": 383,
                "text": "            // escaped += \"\\x1A\"; // substitute char"
              },
              {
                "line": 384,
                "text": "#else"
              },
              {
                "line": 385,
                "text": "            escaped += \"\\\\U\"; // \"U+\"; // substitute char"
              },
              {
                "line": 386,
                "text": "#endif"
              },
              {
                "line": 387,
                "text": "            escaped += QString::number(code, 16).rightJustified(4, '0');"
              },
              {
                "line": 388,
                "text": "        }"
              },
              {
                "line": 389,
                "text": "    }"
              },
              {
                "line": 390,
                "text": ""
              },
              {
                "line": 391,
                "text": "    return escaped;"
              },
              {
                "line": 392,
                "text": "}"
              },
              {
                "line": 393,
                "text": ""
              },
              {
                "line": 394,
                "text": "QString Varicode::unescape(const QString &text) {"
              },
              {
                "line": 395,
                "text": "    QString unescaped(text);"
              },
              {
                "line": 396,
                "text": "#if JS8_USE_ESCAPE_SUB_CHAR"
              },
              {
                "line": 397,
                "text": "    static const int size = 5;"
              },
              {
                "line": 398,
                "text": "    QRegularExpression r(\"([\\\\x1A][0-9a-fA-F]{4})\");"
              },
              {
                "line": 399,
                "text": "#else"
              },
              {
                "line": 400,
                "text": "    static const int size = 6;"
              },
              {
                "line": 401,
                "text": "    QRegularExpression r(\"(([uU][+]|\\\\\\\\[uU])[0-9a-fA-F]{4})\");"
              },
              {
                "line": 402,
                "text": "#endif"
              },
              {
                "line": 403,
                "text": "    qsizetype pos = 0;"
              },
              {
                "line": 404,
                "text": "    QRegularExpressionMatch match;"
              },
              {
                "line": 405,
                "text": "    while ((pos = unescaped.indexOf(r, pos, &match)) != -1) {"
              },
              {
                "line": 406,
                "text": "        unescaped.replace(pos++, size,"
              },
              {
                "line": 407,
                "text": "                          QChar(match.captured(1).right(4).toUShort(0, 16)));"
              },
              {
                "line": 408,
                "text": "    }"
              }
            ]
          }
        },
        {
          "function": "Varicode::rstrip",
          "line": 413,
          "signature": "QString Varicode::rstrip(const QString &str) {",
          "snippet": {
            "start_line": 399,
            "end_line": 427,
            "lines": [
              {
                "line": 399,
                "text": "#else"
              },
              {
                "line": 400,
                "text": "    static const int size = 6;"
              },
              {
                "line": 401,
                "text": "    QRegularExpression r(\"(([uU][+]|\\\\\\\\[uU])[0-9a-fA-F]{4})\");"
              },
              {
                "line": 402,
                "text": "#endif"
              },
              {
                "line": 403,
                "text": "    qsizetype pos = 0;"
              },
              {
                "line": 404,
                "text": "    QRegularExpressionMatch match;"
              },
              {
                "line": 405,
                "text": "    while ((pos = unescaped.indexOf(r, pos, &match)) != -1) {"
              },
              {
                "line": 406,
                "text": "        unescaped.replace(pos++, size,"
              },
              {
                "line": 407,
                "text": "                          QChar(match.captured(1).right(4).toUShort(0, 16)));"
              },
              {
                "line": 408,
                "text": "    }"
              },
              {
                "line": 409,
                "text": ""
              },
              {
                "line": 410,
                "text": "    return unescaped;"
              },
              {
                "line": 411,
                "text": "}"
              },
              {
                "line": 412,
                "text": ""
              },
              {
                "line": 413,
                "text": "QString Varicode::rstrip(const QString &str) {"
              },
              {
                "line": 414,
                "text": "    qsizetype n = str.size() - 1;"
              },
              {
                "line": 415,
                "text": "    for (; n >= 0; --n) {"
              },
              {
                "line": 416,
                "text": "        if (str.at(n).isSpace()) {"
              },
              {
                "line": 417,
                "text": "            continue;"
              },
              {
                "line": 418,
                "text": "        }"
              },
              {
                "line": 419,
                "text": "        return str.left(n + 1);"
              },
              {
                "line": 420,
                "text": "    }"
              },
              {
                "line": 421,
                "text": "    return \"\";"
              },
              {
                "line": 422,
                "text": "}"
              },
              {
                "line": 423,
                "text": ""
              },
              {
                "line": 424,
                "text": "QString Varicode::lstrip(const QString &str) {"
              },
              {
                "line": 425,
                "text": "    qsizetype len = str.size();"
              },
              {
                "line": 426,
                "text": "    for (int n = 0; n < len; n++) {"
              },
              {
                "line": 427,
                "text": "        if (str.at(n).isSpace()) {"
              }
            ]
          }
        },
        {
          "function": "Varicode::lstrip",
          "line": 424,
          "signature": "QString Varicode::lstrip(const QString &str) {",
          "snippet": {
            "start_line": 410,
            "end_line": 438,
            "lines": [
              {
                "line": 410,
                "text": "    return unescaped;"
              },
              {
                "line": 411,
                "text": "}"
              },
              {
                "line": 412,
                "text": ""
              },
              {
                "line": 413,
                "text": "QString Varicode::rstrip(const QString &str) {"
              },
              {
                "line": 414,
                "text": "    qsizetype n = str.size() - 1;"
              },
              {
                "line": 415,
                "text": "    for (; n >= 0; --n) {"
              },
              {
                "line": 416,
                "text": "        if (str.at(n).isSpace()) {"
              },
              {
                "line": 417,
                "text": "            continue;"
              },
              {
                "line": 418,
                "text": "        }"
              },
              {
                "line": 419,
                "text": "        return str.left(n + 1);"
              },
              {
                "line": 420,
                "text": "    }"
              },
              {
                "line": 421,
                "text": "    return \"\";"
              },
              {
                "line": 422,
                "text": "}"
              },
              {
                "line": 423,
                "text": ""
              },
              {
                "line": 424,
                "text": "QString Varicode::lstrip(const QString &str) {"
              },
              {
                "line": 425,
                "text": "    qsizetype len = str.size();"
              },
              {
                "line": 426,
                "text": "    for (int n = 0; n < len; n++) {"
              },
              {
                "line": 427,
                "text": "        if (str.at(n).isSpace()) {"
              },
              {
                "line": 428,
                "text": "            continue;"
              },
              {
                "line": 429,
                "text": "        }"
              },
              {
                "line": 430,
                "text": "        return str.mid(n);"
              },
              {
                "line": 431,
                "text": "    }"
              },
              {
                "line": 432,
                "text": "    return \"\";"
              },
              {
                "line": 433,
                "text": "}"
              },
              {
                "line": 434,
                "text": ""
              },
              {
                "line": 435,
                "text": "/*"
              },
              {
                "line": 436,
                "text": " * VARICODE"
              },
              {
                "line": 437,
                "text": " */"
              },
              {
                "line": 438,
                "text": "QMap<QString, QString> Varicode::defaultHuffTable() { return hufftable; }"
              }
            ]
          }
        },
        {
          "function": "Varicode::cqString",
          "line": 440,
          "signature": "QString Varicode::cqString(int number) {",
          "snippet": {
            "start_line": 426,
            "end_line": 454,
            "lines": [
              {
                "line": 426,
                "text": "    for (int n = 0; n < len; n++) {"
              },
              {
                "line": 427,
                "text": "        if (str.at(n).isSpace()) {"
              },
              {
                "line": 428,
                "text": "            continue;"
              },
              {
                "line": 429,
                "text": "        }"
              },
              {
                "line": 430,
                "text": "        return str.mid(n);"
              },
              {
                "line": 431,
                "text": "    }"
              },
              {
                "line": 432,
                "text": "    return \"\";"
              },
              {
                "line": 433,
                "text": "}"
              },
              {
                "line": 434,
                "text": ""
              },
              {
                "line": 435,
                "text": "/*"
              },
              {
                "line": 436,
                "text": " * VARICODE"
              },
              {
                "line": 437,
                "text": " */"
              },
              {
                "line": 438,
                "text": "QMap<QString, QString> Varicode::defaultHuffTable() { return hufftable; }"
              },
              {
                "line": 439,
                "text": ""
              },
              {
                "line": 440,
                "text": "QString Varicode::cqString(int number) {"
              },
              {
                "line": 441,
                "text": "    if (!cqs.contains(number)) {"
              },
              {
                "line": 442,
                "text": "        return QString{};"
              },
              {
                "line": 443,
                "text": "    }"
              },
              {
                "line": 444,
                "text": "    return cqs[number];"
              },
              {
                "line": 445,
                "text": "}"
              },
              {
                "line": 446,
                "text": ""
              },
              {
                "line": 447,
                "text": "QString Varicode::hbString(int number) {"
              },
              {
                "line": 448,
                "text": "    if (!hbs.contains(number)) {"
              },
              {
                "line": 449,
                "text": "        return QString{};"
              },
              {
                "line": 450,
                "text": "    }"
              },
              {
                "line": 451,
                "text": "    return hbs[number];"
              },
              {
                "line": 452,
                "text": "}"
              },
              {
                "line": 453,
                "text": ""
              },
              {
                "line": 454,
                "text": "bool Varicode::startsWithCQ(QString text) {"
              }
            ]
          }
        },
        {
          "function": "Varicode::hbString",
          "line": 447,
          "signature": "QString Varicode::hbString(int number) {",
          "snippet": {
            "start_line": 433,
            "end_line": 461,
            "lines": [
              {
                "line": 433,
                "text": "}"
              },
              {
                "line": 434,
                "text": ""
              },
              {
                "line": 435,
                "text": "/*"
              },
              {
                "line": 436,
                "text": " * VARICODE"
              },
              {
                "line": 437,
                "text": " */"
              },
              {
                "line": 438,
                "text": "QMap<QString, QString> Varicode::defaultHuffTable() { return hufftable; }"
              },
              {
                "line": 439,
                "text": ""
              },
              {
                "line": 440,
                "text": "QString Varicode::cqString(int number) {"
              },
              {
                "line": 441,
                "text": "    if (!cqs.contains(number)) {"
              },
              {
                "line": 442,
                "text": "        return QString{};"
              },
              {
                "line": 443,
                "text": "    }"
              },
              {
                "line": 444,
                "text": "    return cqs[number];"
              },
              {
                "line": 445,
                "text": "}"
              },
              {
                "line": 446,
                "text": ""
              },
              {
                "line": 447,
                "text": "QString Varicode::hbString(int number) {"
              },
              {
                "line": 448,
                "text": "    if (!hbs.contains(number)) {"
              },
              {
                "line": 449,
                "text": "        return QString{};"
              },
              {
                "line": 450,
                "text": "    }"
              },
              {
                "line": 451,
                "text": "    return hbs[number];"
              },
              {
                "line": 452,
                "text": "}"
              },
              {
                "line": 453,
                "text": ""
              },
              {
                "line": 454,
                "text": "bool Varicode::startsWithCQ(QString text) {"
              },
              {
                "line": 455,
                "text": "    foreach (auto cq, cqs.values()) {"
              },
              {
                "line": 456,
                "text": "        if (text.startsWith(cq)) {"
              },
              {
                "line": 457,
                "text": "            return true;"
              },
              {
                "line": 458,
                "text": "        }"
              },
              {
                "line": 459,
                "text": "    }"
              },
              {
                "line": 460,
                "text": "    return false;"
              },
              {
                "line": 461,
                "text": "}"
              }
            ]
          }
        },
        {
          "function": "Varicode::startsWithCQ",
          "line": 454,
          "signature": "bool Varicode::startsWithCQ(QString text) {",
          "snippet": {
            "start_line": 440,
            "end_line": 468,
            "lines": [
              {
                "line": 440,
                "text": "QString Varicode::cqString(int number) {"
              },
              {
                "line": 441,
                "text": "    if (!cqs.contains(number)) {"
              },
              {
                "line": 442,
                "text": "        return QString{};"
              },
              {
                "line": 443,
                "text": "    }"
              },
              {
                "line": 444,
                "text": "    return cqs[number];"
              },
              {
                "line": 445,
                "text": "}"
              },
              {
                "line": 446,
                "text": ""
              },
              {
                "line": 447,
                "text": "QString Varicode::hbString(int number) {"
              },
              {
                "line": 448,
                "text": "    if (!hbs.contains(number)) {"
              },
              {
                "line": 449,
                "text": "        return QString{};"
              },
              {
                "line": 450,
                "text": "    }"
              },
              {
                "line": 451,
                "text": "    return hbs[number];"
              },
              {
                "line": 452,
                "text": "}"
              },
              {
                "line": 453,
                "text": ""
              },
              {
                "line": 454,
                "text": "bool Varicode::startsWithCQ(QString text) {"
              },
              {
                "line": 455,
                "text": "    foreach (auto cq, cqs.values()) {"
              },
              {
                "line": 456,
                "text": "        if (text.startsWith(cq)) {"
              },
              {
                "line": 457,
                "text": "            return true;"
              },
              {
                "line": 458,
                "text": "        }"
              },
              {
                "line": 459,
                "text": "    }"
              },
              {
                "line": 460,
                "text": "    return false;"
              },
              {
                "line": 461,
                "text": "}"
              },
              {
                "line": 462,
                "text": ""
              },
              {
                "line": 463,
                "text": "bool Varicode::startsWithHB(QString text) {"
              },
              {
                "line": 464,
                "text": "    foreach (auto hb, hbs.values()) {"
              },
              {
                "line": 465,
                "text": "        if (text.startsWith(hb)) {"
              },
              {
                "line": 466,
                "text": "            return true;"
              },
              {
                "line": 467,
                "text": "        }"
              },
              {
                "line": 468,
                "text": "    }"
              }
            ]
          }
        },
        {
          "function": "Varicode::startsWithHB",
          "line": 463,
          "signature": "bool Varicode::startsWithHB(QString text) {",
          "snippet": {
            "start_line": 449,
            "end_line": 477,
            "lines": [
              {
                "line": 449,
                "text": "        return QString{};"
              },
              {
                "line": 450,
                "text": "    }"
              },
              {
                "line": 451,
                "text": "    return hbs[number];"
              },
              {
                "line": 452,
                "text": "}"
              },
              {
                "line": 453,
                "text": ""
              },
              {
                "line": 454,
                "text": "bool Varicode::startsWithCQ(QString text) {"
              },
              {
                "line": 455,
                "text": "    foreach (auto cq, cqs.values()) {"
              },
              {
                "line": 456,
                "text": "        if (text.startsWith(cq)) {"
              },
              {
                "line": 457,
                "text": "            return true;"
              },
              {
                "line": 458,
                "text": "        }"
              },
              {
                "line": 459,
                "text": "    }"
              },
              {
                "line": 460,
                "text": "    return false;"
              },
              {
                "line": 461,
                "text": "}"
              },
              {
                "line": 462,
                "text": ""
              },
              {
                "line": 463,
                "text": "bool Varicode::startsWithHB(QString text) {"
              },
              {
                "line": 464,
                "text": "    foreach (auto hb, hbs.values()) {"
              },
              {
                "line": 465,
                "text": "        if (text.startsWith(hb)) {"
              },
              {
                "line": 466,
                "text": "            return true;"
              },
              {
                "line": 467,
                "text": "        }"
              },
              {
                "line": 468,
                "text": "    }"
              },
              {
                "line": 469,
                "text": "    return false;"
              },
              {
                "line": 470,
                "text": "}"
              },
              {
                "line": 471,
                "text": ""
              },
              {
                "line": 472,
                "text": "QString Varicode::formatSNR(int snr) {"
              },
              {
                "line": 473,
                "text": "    if (snr < -60 || snr > 60) {"
              },
              {
                "line": 474,
                "text": "        return QString();"
              },
              {
                "line": 475,
                "text": "    }"
              },
              {
                "line": 476,
                "text": ""
              },
              {
                "line": 477,
                "text": "    return QString(\"%1%2\")"
              }
            ]
          }
        },
        {
          "function": "Varicode::formatSNR",
          "line": 472,
          "signature": "QString Varicode::formatSNR(int snr) {",
          "snippet": {
            "start_line": 458,
            "end_line": 486,
            "lines": [
              {
                "line": 458,
                "text": "        }"
              },
              {
                "line": 459,
                "text": "    }"
              },
              {
                "line": 460,
                "text": "    return false;"
              },
              {
                "line": 461,
                "text": "}"
              },
              {
                "line": 462,
                "text": ""
              },
              {
                "line": 463,
                "text": "bool Varicode::startsWithHB(QString text) {"
              },
              {
                "line": 464,
                "text": "    foreach (auto hb, hbs.values()) {"
              },
              {
                "line": 465,
                "text": "        if (text.startsWith(hb)) {"
              },
              {
                "line": 466,
                "text": "            return true;"
              },
              {
                "line": 467,
                "text": "        }"
              },
              {
                "line": 468,
                "text": "    }"
              },
              {
                "line": 469,
                "text": "    return false;"
              },
              {
                "line": 470,
                "text": "}"
              },
              {
                "line": 471,
                "text": ""
              },
              {
                "line": 472,
                "text": "QString Varicode::formatSNR(int snr) {"
              },
              {
                "line": 473,
                "text": "    if (snr < -60 || snr > 60) {"
              },
              {
                "line": 474,
                "text": "        return QString();"
              },
              {
                "line": 475,
                "text": "    }"
              },
              {
                "line": 476,
                "text": ""
              },
              {
                "line": 477,
                "text": "    return QString(\"%1%2\")"
              },
              {
                "line": 478,
                "text": "        .arg(snr >= 0 ? \"+\" : \"\")"
              },
              {
                "line": 479,
                "text": "        .arg(snr, snr < 0 ? 3 : 2, 10, QChar('0'));"
              },
              {
                "line": 480,
                "text": "}"
              },
              {
                "line": 481,
                "text": ""
              },
              {
                "line": 482,
                "text": "QString Varicode::checksum16(QString const &input) {"
              },
              {
                "line": 483,
                "text": "    auto fromBytes = input.toLocal8Bit();"
              },
              {
                "line": 484,
                "text": "    auto crc = CRC::Calculate(fromBytes.data(), fromBytes.length(),"
              },
              {
                "line": 485,
                "text": "                              CRC::CRC_16_KERMIT());"
              },
              {
                "line": 486,
                "text": "    auto checksum = Varicode::pack16bits(crc);"
              }
            ]
          }
        }
      ],
      "keyword_snippets": [
        {
          "line": 2,
          "matches": [
            "Varicode"
          ],
          "snippet": {
            "start_line": 1,
            "end_line": 8,
            "lines": [
              {
                "line": 1,
                "text": "/**"
              },
              {
                "line": 2,
                "text": " * @file Varicode.cpp"
              },
              {
                "line": 3,
                "text": " * @brief implementation of encoder"
              },
              {
                "line": 4,
                "text": " * (C) 2018 Jordan Sherer <kn4crd@gmail.com> - All Rights Reserved"
              },
              {
                "line": 5,
                "text": " *"
              },
              {
                "line": 6,
                "text": " */"
              },
              {
                "line": 7,
                "text": ""
              },
              {
                "line": 8,
                "text": "#include \"Varicode.h\""
              }
            ]
          }
        },
        {
          "line": 8,
          "matches": [
            "Varicode"
          ],
          "snippet": {
            "start_line": 2,
            "end_line": 14,
            "lines": [
              {
                "line": 2,
                "text": " * @file Varicode.cpp"
              },
              {
                "line": 3,
                "text": " * @brief implementation of encoder"
              },
              {
                "line": 4,
                "text": " * (C) 2018 Jordan Sherer <kn4crd@gmail.com> - All Rights Reserved"
              },
              {
                "line": 5,
                "text": " *"
              },
              {
                "line": 6,
                "text": " */"
              },
              {
                "line": 7,
                "text": ""
              },
              {
                "line": 8,
                "text": "#include \"Varicode.h\""
              },
              {
                "line": 9,
                "text": "#include \"JS8_JSC/JSC.h\""
              },
              {
                "line": 10,
                "text": "#include \"JS8_Mode/DecodedText.h\""
              },
              {
                "line": 11,
                "text": ""
              },
              {
                "line": 12,
                "text": "#include <QLoggingCategory>"
              },
              {
                "line": 13,
                "text": "#include <QMap>"
              },
              {
                "line": 14,
                "text": "#include <QSet>"
              }
            ]
          }
        },
        {
          "line": 16,
          "matches": [
            "crc"
          ],
          "snippet": {
            "start_line": 10,
            "end_line": 22,
            "lines": [
              {
                "line": 10,
                "text": "#include \"JS8_Mode/DecodedText.h\""
              },
              {
                "line": 11,
                "text": ""
              },
              {
                "line": 12,
                "text": "#include <QLoggingCategory>"
              },
              {
                "line": 13,
                "text": "#include <QMap>"
              },
              {
                "line": 14,
                "text": "#include <QSet>"
              },
              {
                "line": 15,
                "text": "#include <boost/format.hpp>"
              },
              {
                "line": 16,
                "text": "#include <vendor/CRCpp/CRC.h>"
              },
              {
                "line": 17,
                "text": ""
              },
              {
                "line": 18,
                "text": "#include <cmath>"
              },
              {
                "line": 19,
                "text": "#include <stdexcept>"
              },
              {
                "line": 20,
                "text": ""
              },
              {
                "line": 21,
                "text": "#define CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS"
              },
              {
                "line": 22,
                "text": "#define CRCPP_USE_CPP11"
              }
            ]
          }
        },
        {
          "line": 21,
          "matches": [
            "crc"
          ],
          "snippet": {
            "start_line": 15,
            "end_line": 27,
            "lines": [
              {
                "line": 15,
                "text": "#include <boost/format.hpp>"
              },
              {
                "line": 16,
                "text": "#include <vendor/CRCpp/CRC.h>"
              },
              {
                "line": 17,
                "text": ""
              },
              {
                "line": 18,
                "text": "#include <cmath>"
              },
              {
                "line": 19,
                "text": "#include <stdexcept>"
              },
              {
                "line": 20,
                "text": ""
              },
              {
                "line": 21,
                "text": "#define CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS"
              },
              {
                "line": 22,
                "text": "#define CRCPP_USE_CPP11"
              },
              {
                "line": 23,
                "text": ""
              },
              {
                "line": 24,
                "text": "Q_DECLARE_LOGGING_CATEGORY(varicode_js8)"
              },
              {
                "line": 25,
                "text": ""
              },
              {
                "line": 26,
                "text": "const int nalphabet = 41;"
              },
              {
                "line": 27,
                "text": "QString alphabet = {"
              }
            ]
          }
        },
        {
          "line": 43,
          "matches": [
            "pack"
          ],
          "snippet": {
            "start_line": 37,
            "end_line": 49,
            "lines": [
              {
                "line": 37,
                "text": "QString base_callsign_pattern = {"
              },
              {
                "line": 38,
                "text": "    R\"((?<callsign>\\b(?<base>([0-9A-Z])?([0-9A-Z])([0-9])([A-Z])?([A-Z])?([A-Z])?)(?<portable>[/][P])?\\b))\"};"
              },
              {
                "line": 39,
                "text": "// QString compound_callsign_pattern ="
              },
              {
                "line": 40,
                "text": "// {R\"((?<callsign>\\b(?<prefix>[A-Z0-9]{1,4}\\/)?(?<base>([0-9A-Z])?([0-9A-Z])([0-9])([A-Z])?([A-Z])?([A-Z])?)(?<suffix>\\/[A-Z0-9]{1,4})?)\\b)\"};"
              },
              {
                "line": 41,
                "text": "QString compound_callsign_pattern = {"
              },
              {
                "line": 42,
                "text": "    R\"((?<callsign>(?:[@]?|\\b)(?<extended>[A-Z0-9\\/@][A-Z0-9\\/]{0,2}[\\/]?[A-Z0-9\\/]{0,3}[\\/]?[A-Z0-9\\/]{0,3})\\b))\"};"
              },
              {
                "line": 43,
                "text": "QString pack_callsign_pattern = {"
              },
              {
                "line": 44,
                "text": "    R\"(([0-9A-Z ])([0-9A-Z])([0-9])([A-Z ])([A-Z ])([A-Z ]))\"};"
              },
              {
                "line": 45,
                "text": "QString alphanumeric = {"
              },
              {
                "line": 46,
                "text": "    \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ /@\"}; // callsign and grid alphabet"
              },
              {
                "line": 47,
                "text": ""
              },
              {
                "line": 48,
                "text": "QMap<QString, int> directed_cmds = {"
              },
              {
                "line": 49,
                "text": "    // any changes here need to be made also in the directed regular xpression"
              }
            ]
          }
        },
        {
          "line": 62,
          "matches": [
            "bits"
          ],
          "snippet": {
            "start_line": 56,
            "end_line": 68,
            "lines": [
              {
                "line": 56,
                "text": "    {\" CQ\", -1}, // this is my cq (unused except for faux processing of CQs as"
              },
              {
                "line": 57,
                "text": "                 // directed commands)"
              },
              {
                "line": 58,
                "text": ""
              },
              {
                "line": 59,
                "text": "    {\" SNR?\", 0}, // query snr"
              },
              {
                "line": 60,
                "text": "    {\"?\", 0},     // compat"
              },
              {
                "line": 61,
                "text": ""
              },
              {
                "line": 62,
                "text": "    {\" DIT DIT\", 1}, // two bits"
              },
              {
                "line": 63,
                "text": ""
              },
              {
                "line": 64,
                "text": "    {\" HEARING?\", 3}, // query station calls heard"
              },
              {
                "line": 65,
                "text": ""
              },
              {
                "line": 66,
                "text": "    {\" GRID?\", 4}, // query grid"
              },
              {
                "line": 67,
                "text": ""
              },
              {
                "line": 68,
                "text": "    {\">\", 5}, // relay message"
              }
            ]
          }
        },
        {
          "line": 68,
          "matches": [
            "message"
          ],
          "snippet": {
            "start_line": 62,
            "end_line": 74,
            "lines": [
              {
                "line": 62,
                "text": "    {\" DIT DIT\", 1}, // two bits"
              },
              {
                "line": 63,
                "text": ""
              },
              {
                "line": 64,
                "text": "    {\" HEARING?\", 3}, // query station calls heard"
              },
              {
                "line": 65,
                "text": ""
              },
              {
                "line": 66,
                "text": "    {\" GRID?\", 4}, // query grid"
              },
              {
                "line": 67,
                "text": ""
              },
              {
                "line": 68,
                "text": "    {\">\", 5}, // relay message"
              },
              {
                "line": 69,
                "text": ""
              },
              {
                "line": 70,
                "text": "    {\" STATUS?\", 6}, // query idle message"
              },
              {
                "line": 71,
                "text": ""
              },
              {
                "line": 72,
                "text": "    {\" STATUS\", 7}, // this is my status"
              },
              {
                "line": 73,
                "text": ""
              },
              {
                "line": 74,
                "text": "    {\" HEARING\", 8}, // these are the stations i'm hearing"
              }
            ]
          }
        },
        {
          "line": 76,
          "matches": [
            "message"
          ],
          "snippet": {
            "start_line": 70,
            "end_line": 82,
            "lines": [
              {
                "line": 70,
                "text": "    {\" STATUS?\", 6}, // query idle message"
              },
              {
                "line": 71,
                "text": ""
              },
              {
                "line": 72,
                "text": "    {\" STATUS\", 7}, // this is my status"
              },
              {
                "line": 73,
                "text": ""
              },
              {
                "line": 74,
                "text": "    {\" HEARING\", 8}, // these are the stations i'm hearing"
              },
              {
                "line": 75,
                "text": ""
              },
              {
                "line": 76,
                "text": "    {\" MSG\", 9}, // this is a complete message"
              },
              {
                "line": 77,
                "text": ""
              },
              {
                "line": 78,
                "text": "    {\" MSG TO:\", 10}, // store message at a station"
              },
              {
                "line": 79,
                "text": ""
              },
              {
                "line": 80,
                "text": "    {\" QUERY\", 11}, // generic query"
              },
              {
                "line": 81,
                "text": ""
              },
              {
                "line": 82,
                "text": "    {\" QUERY MSGS\", 12},  // do you have any stored messages?"
              }
            ]
          }
        },
        {
          "line": 82,
          "matches": [
            "message"
          ],
          "snippet": {
            "start_line": 76,
            "end_line": 88,
            "lines": [
              {
                "line": 76,
                "text": "    {\" MSG\", 9}, // this is a complete message"
              },
              {
                "line": 77,
                "text": ""
              },
              {
                "line": 78,
                "text": "    {\" MSG TO:\", 10}, // store message at a station"
              },
              {
                "line": 79,
                "text": ""
              },
              {
                "line": 80,
                "text": "    {\" QUERY\", 11}, // generic query"
              },
              {
                "line": 81,
                "text": ""
              },
              {
                "line": 82,
                "text": "    {\" QUERY MSGS\", 12},  // do you have any stored messages?"
              },
              {
                "line": 83,
                "text": "    {\" QUERY MSGS?\", 12}, // do you have any stored messages?"
              },
              {
                "line": 84,
                "text": ""
              },
              {
                "line": 85,
                "text": "    {\" QUERY CALL\", 13}, // can you transmit a ping to callsign?"
              },
              {
                "line": 86,
                "text": ""
              },
              {
                "line": 87,
                "text": "    // {\" \",           14  }, // reserved"
              },
              {
                "line": 88,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 91,
          "matches": [
            "message"
          ],
          "snippet": {
            "start_line": 85,
            "end_line": 97,
            "lines": [
              {
                "line": 85,
                "text": "    {\" QUERY CALL\", 13}, // can you transmit a ping to callsign?"
              },
              {
                "line": 86,
                "text": ""
              },
              {
                "line": 87,
                "text": "    // {\" \",           14  }, // reserved"
              },
              {
                "line": 88,
                "text": ""
              },
              {
                "line": 89,
                "text": "    {\" GRID\", 15}, // this is my current grid locator"
              },
              {
                "line": 90,
                "text": ""
              },
              {
                "line": 91,
                "text": "    {\" INFO?\", 16}, // what is your info message?"
              },
              {
                "line": 92,
                "text": "    {\" INFO\", 17},  // this is my info message"
              },
              {
                "line": 93,
                "text": ""
              },
              {
                "line": 94,
                "text": "    {\" FB\", 18},      // fine business"
              },
              {
                "line": 95,
                "text": "    {\" HW CPY?\", 19}, // how do you copy?"
              },
              {
                "line": 96,
                "text": "    {\" SK\", 20},      // end of contact"
              },
              {
                "line": 97,
                "text": "    {\" RR\", 21},      // roger roger"
              }
            ]
          }
        },
        {
          "line": 114,
          "matches": [
            "message"
          ],
          "snippet": {
            "start_line": 108,
            "end_line": 120,
            "lines": [
              {
                "line": 108,
                "text": ""
              },
              {
                "line": 109,
                "text": "    {\" NACK\", 2}, // negative acknowledge"
              },
              {
                "line": 110,
                "text": "    {\" ACK\", 14}, // acknowledge (was reserved in 2.1)"
              },
              {
                "line": 111,
                "text": ""
              },
              {
                "line": 112,
                "text": "    {\" HEARTBEAT SNR\", 29}, // (was ACK in 2.1, now deprecated)"
              },
              {
                "line": 113,
                "text": ""
              },
              {
                "line": 114,
                "text": "    {\" AGN?\", 30}, // repeat message"
              },
              {
                "line": 115,
                "text": "    {\"  \", 31},    // send freetext (weird artifact)"
              },
              {
                "line": 116,
                "text": "    {\" \", 31},     // send freetext"
              },
              {
                "line": 117,
                "text": "};"
              },
              {
                "line": 118,
                "text": ""
              },
              {
                "line": 119,
                "text": "// commands allowed to be processed"
              },
              {
                "line": 120,
                "text": "QSet<int> allowed_cmds = {-1, 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,"
              }
            ]
          }
        },
        {
          "line": 133,
          "matches": [
            "crc",
            "checksum"
          ],
          "snippet": {
            "start_line": 127,
            "end_line": 139,
            "lines": [
              {
                "line": 127,
                "text": "// commands that should be buffered"
              },
              {
                "line": 128,
                "text": "QSet<int> buffered_cmds = {5, 9, 10, 11, 12, 13, 15, 24};"
              },
              {
                "line": 129,
                "text": ""
              },
              {
                "line": 130,
                "text": "// commands that may include an SNR value"
              },
              {
                "line": 131,
                "text": "QSet<int> snr_cmds = {25, 29};"
              },
              {
                "line": 132,
                "text": ""
              },
              {
                "line": 133,
                "text": "// commands that are checksummed and their crc size"
              },
              {
                "line": 134,
                "text": "QMap<int, int> checksum_cmds = {{5, 16},  {9, 16},  {10, 16}, {11, 16},"
              },
              {
                "line": 135,
                "text": "                                {12, 16}, {13, 16}, {15, 0},  {24, 16}};"
              },
              {
                "line": 136,
                "text": ""
              },
              {
                "line": 137,
                "text": "QString callsign_pattern = QString(\"(?<callsign>[@]?[A-Z0-9/]+)\");"
              },
              {
                "line": 138,
                "text": "QString optional_cmd_pattern ="
              },
              {
                "line": 139,
                "text": "    QString(\"(?<cmd>\\\\s?(?:AGN[?]|QSL[?]|HW CPY[?]|MSG \""
              }
            ]
          }
        },
        {
          "line": 159,
          "matches": [
            "message"
          ],
          "snippet": {
            "start_line": 153,
            "end_line": 165,
            "lines": [
              {
                "line": 153,
                "text": "QRegularExpression heartbeat_re("
              },
              {
                "line": 154,
                "text": "    R\"(^\\s*(?<callsign>[@](?:ALLCALL|HB)\\s+)?(?<type>CQ CQ CQ|CQ DX|CQ QRP|CQ CONTEST|CQ FIELD|CQ FD|CQ CQ|CQ|HB|HEARTBEAT(?!\\s+SNR))(?:\\s(?<grid>[A-R]{2}[0-9]{2}))?\\b)\");"
              },
              {
                "line": 155,
                "text": ""
              },
              {
                "line": 156,
                "text": "QRegularExpression"
              },
              {
                "line": 157,
                "text": "    compound_re(\"^\\\\s*[`]\" + callsign_pattern + \"(?<extra>\" +"
              },
              {
                "line": 158,
                "text": "                optional_grid_pattern + // there's a reason this is first (see:"
              },
              {
                "line": 159,
                "text": "                                        // buildMessageFrames)"
              },
              {
                "line": 160,
                "text": "                optional_cmd_pattern + optional_num_pattern + \")\");"
              },
              {
                "line": 161,
                "text": ""
              },
              {
                "line": 162,
                "text": "QMap<QString, QString> hufftable = {"
              },
              {
                "line": 163,
                "text": "    // char   code                 weight"
              },
              {
                "line": 164,
                "text": "    {\" \", \"01\"},       // 1.0"
              },
              {
                "line": 165,
                "text": "    {\"E\", \"100\"},      // 0.5"
              }
            ]
          }
        },
        {
          "line": 292,
          "matches": [
            "message"
          ],
          "snippet": {
            "start_line": 286,
            "end_line": 298,
            "lines": [
              {
                "line": 286,
                "text": ""
              },
              {
                "line": 287,
                "text": "QMap<quint32, QString> cqs = {"
              },
              {
                "line": 288,
                "text": "    {0, \"CQ CQ CQ\"}, {1, \"CQ DX\"}, {2, \"CQ QRP\"}, {3, \"CQ CONTEST\"},"
              },
              {
                "line": 289,
                "text": "    {4, \"CQ FIELD\"}, {5, \"CQ FD\"}, {6, \"CQ CQ\"},  {7, \"CQ\"},"
              },
              {
                "line": 290,
                "text": "};"
              },
              {
                "line": 291,
                "text": ""
              },
              {
                "line": 292,
                "text": "// status flags in HB messages are deprecated as of 2.2, later versions will"
              },
              {
                "line": 293,
                "text": "// likely repurpose these flags keep in mind if you change any of these to not"
              },
              {
                "line": 294,
                "text": "// start with HB you'll have to address the packHeartbeatMessage and how the"
              },
              {
                "line": 295,
                "text": "// function computes the isAlt flag."
              },
              {
                "line": 296,
                "text": "QMap<quint32, QString> hbs = {"
              },
              {
                "line": 297,
                "text": "    {0, \"HB\"}, // HB"
              },
              {
                "line": 298,
                "text": "    {1, \"HB\"}, // HB AUTO"
              }
            ]
          }
        },
        {
          "line": 359,
          "matches": [
            "Varicode"
          ],
          "snippet": {
            "start_line": 353,
            "end_line": 365,
            "lines": [
              {
                "line": 353,
                "text": "    if (iter == dbm2mw.end()) {"
              },
              {
                "line": 354,
                "text": "        return dbm2mw.last();"
              },
              {
                "line": 355,
                "text": "    }"
              },
              {
                "line": 356,
                "text": "    return iter.value();"
              },
              {
                "line": 357,
                "text": "}"
              },
              {
                "line": 358,
                "text": ""
              },
              {
                "line": 359,
                "text": "QString Varicode::extendedChars() {"
              },
              {
                "line": 360,
                "text": "    static QString c;"
              },
              {
                "line": 361,
                "text": "    if (c.size() == 0) {"
              },
              {
                "line": 362,
                "text": "        for (quint32 i = 0; i < JSC::prefixSize; i++) {"
              },
              {
                "line": 363,
                "text": "            if (JSC::prefix[i].size != 1) {"
              },
              {
                "line": 364,
                "text": "                continue;"
              },
              {
                "line": 365,
                "text": "            }"
              }
            ]
          }
        },
        {
          "line": 362,
          "matches": [
            "JSC"
          ],
          "snippet": {
            "start_line": 356,
            "end_line": 368,
            "lines": [
              {
                "line": 356,
                "text": "    return iter.value();"
              },
              {
                "line": 357,
                "text": "}"
              },
              {
                "line": 358,
                "text": ""
              },
              {
                "line": 359,
                "text": "QString Varicode::extendedChars() {"
              },
              {
                "line": 360,
                "text": "    static QString c;"
              },
              {
                "line": 361,
                "text": "    if (c.size() == 0) {"
              },
              {
                "line": 362,
                "text": "        for (quint32 i = 0; i < JSC::prefixSize; i++) {"
              },
              {
                "line": 363,
                "text": "            if (JSC::prefix[i].size != 1) {"
              },
              {
                "line": 364,
                "text": "                continue;"
              },
              {
                "line": 365,
                "text": "            }"
              },
              {
                "line": 366,
                "text": "            c.append(QLatin1String(JSC::prefix[i].str, 1));"
              },
              {
                "line": 367,
                "text": "        }"
              },
              {
                "line": 368,
                "text": "    }"
              }
            ]
          }
        },
        {
          "line": 366,
          "matches": [
            "JSC"
          ],
          "snippet": {
            "start_line": 360,
            "end_line": 372,
            "lines": [
              {
                "line": 360,
                "text": "    static QString c;"
              },
              {
                "line": 361,
                "text": "    if (c.size() == 0) {"
              },
              {
                "line": 362,
                "text": "        for (quint32 i = 0; i < JSC::prefixSize; i++) {"
              },
              {
                "line": 363,
                "text": "            if (JSC::prefix[i].size != 1) {"
              },
              {
                "line": 364,
                "text": "                continue;"
              },
              {
                "line": 365,
                "text": "            }"
              },
              {
                "line": 366,
                "text": "            c.append(QLatin1String(JSC::prefix[i].str, 1));"
              },
              {
                "line": 367,
                "text": "        }"
              },
              {
                "line": 368,
                "text": "    }"
              },
              {
                "line": 369,
                "text": "    return c;"
              },
              {
                "line": 370,
                "text": "}"
              },
              {
                "line": 371,
                "text": ""
              },
              {
                "line": 372,
                "text": "QString Varicode::escape(const QString &text) {"
              }
            ]
          }
        },
        {
          "line": 372,
          "matches": [
            "Varicode"
          ],
          "snippet": {
            "start_line": 366,
            "end_line": 378,
            "lines": [
              {
                "line": 366,
                "text": "            c.append(QLatin1String(JSC::prefix[i].str, 1));"
              },
              {
                "line": 367,
                "text": "        }"
              },
              {
                "line": 368,
                "text": "    }"
              },
              {
                "line": 369,
                "text": "    return c;"
              },
              {
                "line": 370,
                "text": "}"
              },
              {
                "line": 371,
                "text": ""
              },
              {
                "line": 372,
                "text": "QString Varicode::escape(const QString &text) {"
              },
              {
                "line": 373,
                "text": "    static const int size = 6;"
              },
              {
                "line": 374,
                "text": "    QString escaped;"
              },
              {
                "line": 375,
                "text": "    escaped.reserve(size * text.size());"
              },
              {
                "line": 376,
                "text": "    for (QString::const_iterator it = text.begin(); it != text.end(); ++it) {"
              },
              {
                "line": 377,
                "text": "        QChar ch = *it;"
              },
              {
                "line": 378,
                "text": "        ushort code = ch.unicode();"
              }
            ]
          }
        },
        {
          "line": 394,
          "matches": [
            "Varicode"
          ],
          "snippet": {
            "start_line": 388,
            "end_line": 400,
            "lines": [
              {
                "line": 388,
                "text": "        }"
              },
              {
                "line": 389,
                "text": "    }"
              },
              {
                "line": 390,
                "text": ""
              },
              {
                "line": 391,
                "text": "    return escaped;"
              },
              {
                "line": 392,
                "text": "}"
              },
              {
                "line": 393,
                "text": ""
              },
              {
                "line": 394,
                "text": "QString Varicode::unescape(const QString &text) {"
              },
              {
                "line": 395,
                "text": "    QString unescaped(text);"
              },
              {
                "line": 396,
                "text": "#if JS8_USE_ESCAPE_SUB_CHAR"
              },
              {
                "line": 397,
                "text": "    static const int size = 5;"
              },
              {
                "line": 398,
                "text": "    QRegularExpression r(\"([\\\\x1A][0-9a-fA-F]{4})\");"
              },
              {
                "line": 399,
                "text": "#else"
              },
              {
                "line": 400,
                "text": "    static const int size = 6;"
              }
            ]
          }
        },
        {
          "line": 413,
          "matches": [
            "Varicode"
          ],
          "snippet": {
            "start_line": 407,
            "end_line": 419,
            "lines": [
              {
                "line": 407,
                "text": "                          QChar(match.captured(1).right(4).toUShort(0, 16)));"
              },
              {
                "line": 408,
                "text": "    }"
              },
              {
                "line": 409,
                "text": ""
              },
              {
                "line": 410,
                "text": "    return unescaped;"
              },
              {
                "line": 411,
                "text": "}"
              },
              {
                "line": 412,
                "text": ""
              },
              {
                "line": 413,
                "text": "QString Varicode::rstrip(const QString &str) {"
              },
              {
                "line": 414,
                "text": "    qsizetype n = str.size() - 1;"
              },
              {
                "line": 415,
                "text": "    for (; n >= 0; --n) {"
              },
              {
                "line": 416,
                "text": "        if (str.at(n).isSpace()) {"
              },
              {
                "line": 417,
                "text": "            continue;"
              },
              {
                "line": 418,
                "text": "        }"
              },
              {
                "line": 419,
                "text": "        return str.left(n + 1);"
              }
            ]
          }
        },
        {
          "line": 424,
          "matches": [
            "Varicode"
          ],
          "snippet": {
            "start_line": 418,
            "end_line": 430,
            "lines": [
              {
                "line": 418,
                "text": "        }"
              },
              {
                "line": 419,
                "text": "        return str.left(n + 1);"
              },
              {
                "line": 420,
                "text": "    }"
              },
              {
                "line": 421,
                "text": "    return \"\";"
              },
              {
                "line": 422,
                "text": "}"
              },
              {
                "line": 423,
                "text": ""
              },
              {
                "line": 424,
                "text": "QString Varicode::lstrip(const QString &str) {"
              },
              {
                "line": 425,
                "text": "    qsizetype len = str.size();"
              },
              {
                "line": 426,
                "text": "    for (int n = 0; n < len; n++) {"
              },
              {
                "line": 427,
                "text": "        if (str.at(n).isSpace()) {"
              },
              {
                "line": 428,
                "text": "            continue;"
              },
              {
                "line": 429,
                "text": "        }"
              },
              {
                "line": 430,
                "text": "        return str.mid(n);"
              }
            ]
          }
        },
        {
          "line": 436,
          "matches": [
            "Varicode"
          ],
          "snippet": {
            "start_line": 430,
            "end_line": 442,
            "lines": [
              {
                "line": 430,
                "text": "        return str.mid(n);"
              },
              {
                "line": 431,
                "text": "    }"
              },
              {
                "line": 432,
                "text": "    return \"\";"
              },
              {
                "line": 433,
                "text": "}"
              },
              {
                "line": 434,
                "text": ""
              },
              {
                "line": 435,
                "text": "/*"
              },
              {
                "line": 436,
                "text": " * VARICODE"
              },
              {
                "line": 437,
                "text": " */"
              },
              {
                "line": 438,
                "text": "QMap<QString, QString> Varicode::defaultHuffTable() { return hufftable; }"
              },
              {
                "line": 439,
                "text": ""
              },
              {
                "line": 440,
                "text": "QString Varicode::cqString(int number) {"
              },
              {
                "line": 441,
                "text": "    if (!cqs.contains(number)) {"
              },
              {
                "line": 442,
                "text": "        return QString{};"
              }
            ]
          }
        }
      ]
    },
    {
      "path": "JS8_Main/Varicode.h",
      "exists": true,
      "bytes": 8286,
      "sha256": "dd7b8bf50466d0d2dc42b8c9ec05a72126363b3cd02c7492c5e2dcc9c9abb99d",
      "line_count": 222,
      "phase_hits": {
        "timing_submode": 0,
        "symbol_to_soft_bits": 0,
        "bit_order_interleaver": 32,
        "whitening_erasure": 0,
        "ldpc_decode": 0,
        "message91_crc_text": 85
      },
      "function_blocks": [
        {
          "function": "frameTypeString",
          "line": 62,
          "signature": "static QString frameTypeString(quint8 type) {",
          "snippet": {
            "start_line": 48,
            "end_line": 76,
            "lines": [
              {
                "line": 48,
                "text": "    enum FrameType {"
              },
              {
                "line": 49,
                "text": "        FrameUnknown = 255,        // [11111111] <- only used as a sentinel"
              },
              {
                "line": 50,
                "text": "        FrameHeartbeat = 0,        // [000]"
              },
              {
                "line": 51,
                "text": "        FrameCompound = 1,         // [001]"
              },
              {
                "line": 52,
                "text": "        FrameCompoundDirected = 2, // [010]"
              },
              {
                "line": 53,
                "text": "        FrameDirected = 3,         // [011]"
              },
              {
                "line": 54,
                "text": "        FrameData = 4, // [10X] // but this only encodes the first 2 msb bits"
              },
              {
                "line": 55,
                "text": "                       // and drops the lsb"
              },
              {
                "line": 56,
                "text": "        FrameDataCompressed = 6, // [11X] // but this only encodes the first 2"
              },
              {
                "line": 57,
                "text": "                                 // msb bits and drops the lsb"
              },
              {
                "line": 58,
                "text": "    };"
              },
              {
                "line": 59,
                "text": ""
              },
              {
                "line": 60,
                "text": "    static const quint8 FrameTypeMax = 6;"
              },
              {
                "line": 61,
                "text": ""
              },
              {
                "line": 62,
                "text": "    static QString frameTypeString(quint8 type) {"
              },
              {
                "line": 63,
                "text": "        const char *FrameTypeStrings[] = {"
              },
              {
                "line": 64,
                "text": "            \"FrameHeartbeat\",      \"FrameCompound\", \"FrameCompoundDirected\","
              },
              {
                "line": 65,
                "text": "            \"FrameDirected\",       \"FrameData\","
              },
              {
                "line": 66,
                "text": "            \"FrameUnknown\", // 5"
              },
              {
                "line": 67,
                "text": "            \"FrameDataCompressed\","
              },
              {
                "line": 68,
                "text": "        };"
              },
              {
                "line": 69,
                "text": ""
              },
              {
                "line": 70,
                "text": "        if (type > FrameTypeMax) {"
              },
              {
                "line": 71,
                "text": "            return \"FrameUnknown\";"
              },
              {
                "line": 72,
                "text": "        }"
              },
              {
                "line": 73,
                "text": "        return FrameTypeStrings[type];"
              },
              {
                "line": 74,
                "text": "    }"
              },
              {
                "line": 75,
                "text": ""
              },
              {
                "line": 76,
                "text": "    // Varicode();"
              }
            ]
          }
        }
      ],
      "keyword_snippets": [
        {
          "line": 1,
          "matches": [
            "Varicode"
          ],
          "snippet": {
            "start_line": 1,
            "end_line": 7,
            "lines": [
              {
                "line": 1,
                "text": "#ifndef VARICODE_H"
              },
              {
                "line": 2,
                "text": "#define VARICODE_H"
              },
              {
                "line": 3,
                "text": ""
              },
              {
                "line": 4,
                "text": "/**"
              },
              {
                "line": 5,
                "text": " * (C) 2018 Jordan Sherer <kn4crd@gmail.com> - All Rights Reserved"
              },
              {
                "line": 6,
                "text": " **/"
              },
              {
                "line": 7,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 14,
          "matches": [
            "Varicode"
          ],
          "snippet": {
            "start_line": 8,
            "end_line": 20,
            "lines": [
              {
                "line": 8,
                "text": "#include <QBitArray>"
              },
              {
                "line": 9,
                "text": "#include <QRegularExpression>"
              },
              {
                "line": 10,
                "text": "#include <QString>"
              },
              {
                "line": 11,
                "text": "#include <QThread>"
              },
              {
                "line": 12,
                "text": "#include <QVector>"
              },
              {
                "line": 13,
                "text": ""
              },
              {
                "line": 14,
                "text": "class Varicode {"
              },
              {
                "line": 15,
                "text": "  public:"
              },
              {
                "line": 16,
                "text": "    // extra information out of buildMessageFrames"
              },
              {
                "line": 17,
                "text": "    struct MessageInfo {"
              },
              {
                "line": 18,
                "text": "        QString dirTo;"
              },
              {
                "line": 19,
                "text": "        QString dirCmd;"
              },
              {
                "line": 20,
                "text": "        QString dirNum;"
              }
            ]
          }
        },
        {
          "line": 16,
          "matches": [
            "message"
          ],
          "snippet": {
            "start_line": 10,
            "end_line": 22,
            "lines": [
              {
                "line": 10,
                "text": "#include <QString>"
              },
              {
                "line": 11,
                "text": "#include <QThread>"
              },
              {
                "line": 12,
                "text": "#include <QVector>"
              },
              {
                "line": 13,
                "text": ""
              },
              {
                "line": 14,
                "text": "class Varicode {"
              },
              {
                "line": 15,
                "text": "  public:"
              },
              {
                "line": 16,
                "text": "    // extra information out of buildMessageFrames"
              },
              {
                "line": 17,
                "text": "    struct MessageInfo {"
              },
              {
                "line": 18,
                "text": "        QString dirTo;"
              },
              {
                "line": 19,
                "text": "        QString dirCmd;"
              },
              {
                "line": 20,
                "text": "        QString dirNum;"
              },
              {
                "line": 21,
                "text": "    };"
              },
              {
                "line": 22,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 34,
          "matches": [
            "message"
          ],
          "snippet": {
            "start_line": 28,
            "end_line": 40,
            "lines": [
              {
                "line": 28,
                "text": "        JS8CallSlow = 4,"
              },
              {
                "line": 29,
                "text": "        JS8CallUltra = 8"
              },
              {
                "line": 30,
                "text": "    };"
              },
              {
                "line": 31,
                "text": ""
              },
              {
                "line": 32,
                "text": "    // frame type transmitted via itype and decoded by the ft8 decoded"
              },
              {
                "line": 33,
                "text": "    enum TransmissionType {"
              },
              {
                "line": 34,
                "text": "        JS8Call = 0,      // [000] <- any other frame of the message"
              },
              {
                "line": 35,
                "text": "        JS8CallFirst = 1, // [001] <- the first frame of a message"
              },
              {
                "line": 36,
                "text": "        JS8CallLast = 2,  // [010] <- the last frame of a message"
              },
              {
                "line": 37,
                "text": "        JS8CallData = 4,  // [100] <- flagged frame (no frame type header)"
              },
              {
                "line": 38,
                "text": "    };"
              },
              {
                "line": 39,
                "text": ""
              },
              {
                "line": 40,
                "text": "    /*"
              }
            ]
          }
        },
        {
          "line": 36,
          "matches": [
            "message"
          ],
          "snippet": {
            "start_line": 30,
            "end_line": 42,
            "lines": [
              {
                "line": 30,
                "text": "    };"
              },
              {
                "line": 31,
                "text": ""
              },
              {
                "line": 32,
                "text": "    // frame type transmitted via itype and decoded by the ft8 decoded"
              },
              {
                "line": 33,
                "text": "    enum TransmissionType {"
              },
              {
                "line": 34,
                "text": "        JS8Call = 0,      // [000] <- any other frame of the message"
              },
              {
                "line": 35,
                "text": "        JS8CallFirst = 1, // [001] <- the first frame of a message"
              },
              {
                "line": 36,
                "text": "        JS8CallLast = 2,  // [010] <- the last frame of a message"
              },
              {
                "line": 37,
                "text": "        JS8CallData = 4,  // [100] <- flagged frame (no frame type header)"
              },
              {
                "line": 38,
                "text": "    };"
              },
              {
                "line": 39,
                "text": ""
              },
              {
                "line": 40,
                "text": "    /*"
              },
              {
                "line": 41,
                "text": ""
              },
              {
                "line": 42,
                "text": "    000 = heartbeat"
              }
            ]
          }
        },
        {
          "line": 76,
          "matches": [
            "Varicode"
          ],
          "snippet": {
            "start_line": 70,
            "end_line": 82,
            "lines": [
              {
                "line": 70,
                "text": "        if (type > FrameTypeMax) {"
              },
              {
                "line": 71,
                "text": "            return \"FrameUnknown\";"
              },
              {
                "line": 72,
                "text": "        }"
              },
              {
                "line": 73,
                "text": "        return FrameTypeStrings[type];"
              },
              {
                "line": 74,
                "text": "    }"
              },
              {
                "line": 75,
                "text": ""
              },
              {
                "line": 76,
                "text": "    // Varicode();"
              },
              {
                "line": 77,
                "text": ""
              },
              {
                "line": 78,
                "text": "    static SubmodeType intToSubmode(int sm);"
              },
              {
                "line": 79,
                "text": ""
              },
              {
                "line": 80,
                "text": "    static QString extendedChars();"
              },
              {
                "line": 81,
                "text": ""
              },
              {
                "line": 82,
                "text": "    static QString escape(const QString &text);"
              }
            ]
          }
        },
        {
          "line": 120,
          "matches": [
            "pack",
            "unpack"
          ],
          "snippet": {
            "start_line": 114,
            "end_line": 126,
            "lines": [
              {
                "line": 114,
                "text": ""
              },
              {
                "line": 115,
                "text": "    static QVector<bool> intToBits(quint64 value, int expected = 0);"
              },
              {
                "line": 116,
                "text": "    static quint64 bitsToInt(QVector<bool> const value);"
              },
              {
                "line": 117,
                "text": "    static quint64 bitsToInt(QVector<bool>::ConstIterator start, int n);"
              },
              {
                "line": 118,
                "text": "    static QVector<bool> bitsListToBits(QList<QVector<bool>> &list);"
              },
              {
                "line": 119,
                "text": ""
              },
              {
                "line": 120,
                "text": "    static quint8 unpack5bits(QString const &value);"
              },
              {
                "line": 121,
                "text": "    static QString pack5bits(quint8 packed);"
              },
              {
                "line": 122,
                "text": ""
              },
              {
                "line": 123,
                "text": "    static quint8 unpack6bits(QString const &value);"
              },
              {
                "line": 124,
                "text": "    static QString pack6bits(quint8 packed);"
              },
              {
                "line": 125,
                "text": ""
              },
              {
                "line": 126,
                "text": "    static quint16 unpack16bits(QString const &value);"
              }
            ]
          }
        },
        {
          "line": 121,
          "matches": [
            "pack"
          ],
          "snippet": {
            "start_line": 115,
            "end_line": 127,
            "lines": [
              {
                "line": 115,
                "text": "    static QVector<bool> intToBits(quint64 value, int expected = 0);"
              },
              {
                "line": 116,
                "text": "    static quint64 bitsToInt(QVector<bool> const value);"
              },
              {
                "line": 117,
                "text": "    static quint64 bitsToInt(QVector<bool>::ConstIterator start, int n);"
              },
              {
                "line": 118,
                "text": "    static QVector<bool> bitsListToBits(QList<QVector<bool>> &list);"
              },
              {
                "line": 119,
                "text": ""
              },
              {
                "line": 120,
                "text": "    static quint8 unpack5bits(QString const &value);"
              },
              {
                "line": 121,
                "text": "    static QString pack5bits(quint8 packed);"
              },
              {
                "line": 122,
                "text": ""
              },
              {
                "line": 123,
                "text": "    static quint8 unpack6bits(QString const &value);"
              },
              {
                "line": 124,
                "text": "    static QString pack6bits(quint8 packed);"
              },
              {
                "line": 125,
                "text": ""
              },
              {
                "line": 126,
                "text": "    static quint16 unpack16bits(QString const &value);"
              },
              {
                "line": 127,
                "text": "    static QString pack16bits(quint16 packed);"
              }
            ]
          }
        },
        {
          "line": 126,
          "matches": [
            "pack",
            "unpack"
          ],
          "snippet": {
            "start_line": 120,
            "end_line": 132,
            "lines": [
              {
                "line": 120,
                "text": "    static quint8 unpack5bits(QString const &value);"
              },
              {
                "line": 121,
                "text": "    static QString pack5bits(quint8 packed);"
              },
              {
                "line": 122,
                "text": ""
              },
              {
                "line": 123,
                "text": "    static quint8 unpack6bits(QString const &value);"
              },
              {
                "line": 124,
                "text": "    static QString pack6bits(quint8 packed);"
              },
              {
                "line": 125,
                "text": ""
              },
              {
                "line": 126,
                "text": "    static quint16 unpack16bits(QString const &value);"
              },
              {
                "line": 127,
                "text": "    static QString pack16bits(quint16 packed);"
              },
              {
                "line": 128,
                "text": ""
              },
              {
                "line": 129,
                "text": "    static quint32 unpack32bits(QString const &value);"
              },
              {
                "line": 130,
                "text": "    static QString pack32bits(quint32 packed);"
              },
              {
                "line": 131,
                "text": ""
              },
              {
                "line": 132,
                "text": "    static quint64 unpack64bits(QString const &value);"
              }
            ]
          }
        },
        {
          "line": 132,
          "matches": [
            "pack",
            "unpack"
          ],
          "snippet": {
            "start_line": 126,
            "end_line": 138,
            "lines": [
              {
                "line": 126,
                "text": "    static quint16 unpack16bits(QString const &value);"
              },
              {
                "line": 127,
                "text": "    static QString pack16bits(quint16 packed);"
              },
              {
                "line": 128,
                "text": ""
              },
              {
                "line": 129,
                "text": "    static quint32 unpack32bits(QString const &value);"
              },
              {
                "line": 130,
                "text": "    static QString pack32bits(quint32 packed);"
              },
              {
                "line": 131,
                "text": ""
              },
              {
                "line": 132,
                "text": "    static quint64 unpack64bits(QString const &value);"
              },
              {
                "line": 133,
                "text": "    static QString pack64bits(quint64 packed);"
              },
              {
                "line": 134,
                "text": ""
              },
              {
                "line": 135,
                "text": "    static quint64 unpack72bits(QString const &value, quint8 *pRem);"
              },
              {
                "line": 136,
                "text": "    static QString pack72bits(quint64 value, quint8 rem);"
              },
              {
                "line": 137,
                "text": ""
              },
              {
                "line": 138,
                "text": "    static quint32 packAlphaNumeric22(QString const &value, bool isFlag);"
              }
            ]
          }
        },
        {
          "line": 136,
          "matches": [
            "pack"
          ],
          "snippet": {
            "start_line": 130,
            "end_line": 142,
            "lines": [
              {
                "line": 130,
                "text": "    static QString pack32bits(quint32 packed);"
              },
              {
                "line": 131,
                "text": ""
              },
              {
                "line": 132,
                "text": "    static quint64 unpack64bits(QString const &value);"
              },
              {
                "line": 133,
                "text": "    static QString pack64bits(quint64 packed);"
              },
              {
                "line": 134,
                "text": ""
              },
              {
                "line": 135,
                "text": "    static quint64 unpack72bits(QString const &value, quint8 *pRem);"
              },
              {
                "line": 136,
                "text": "    static QString pack72bits(quint64 value, quint8 rem);"
              },
              {
                "line": 137,
                "text": ""
              },
              {
                "line": 138,
                "text": "    static quint32 packAlphaNumeric22(QString const &value, bool isFlag);"
              },
              {
                "line": 139,
                "text": "    static QString unpackAlphaNumeric22(quint32 packed, bool *isFlag);"
              },
              {
                "line": 140,
                "text": ""
              },
              {
                "line": 141,
                "text": "    static quint64 packAlphaNumeric50(QString const &value);"
              },
              {
                "line": 142,
                "text": "    static QString unpackAlphaNumeric50(quint64 packed);"
              }
            ]
          }
        },
        {
          "line": 141,
          "matches": [
            "pack"
          ],
          "snippet": {
            "start_line": 135,
            "end_line": 147,
            "lines": [
              {
                "line": 135,
                "text": "    static quint64 unpack72bits(QString const &value, quint8 *pRem);"
              },
              {
                "line": 136,
                "text": "    static QString pack72bits(quint64 value, quint8 rem);"
              },
              {
                "line": 137,
                "text": ""
              },
              {
                "line": 138,
                "text": "    static quint32 packAlphaNumeric22(QString const &value, bool isFlag);"
              },
              {
                "line": 139,
                "text": "    static QString unpackAlphaNumeric22(quint32 packed, bool *isFlag);"
              },
              {
                "line": 140,
                "text": ""
              },
              {
                "line": 141,
                "text": "    static quint64 packAlphaNumeric50(QString const &value);"
              },
              {
                "line": 142,
                "text": "    static QString unpackAlphaNumeric50(quint64 packed);"
              },
              {
                "line": 143,
                "text": ""
              },
              {
                "line": 144,
                "text": "    static quint32 packCallsign(QString const &value, bool *pPortable);"
              },
              {
                "line": 145,
                "text": "    static QString unpackCallsign(quint32 value, bool portable);"
              },
              {
                "line": 146,
                "text": ""
              },
              {
                "line": 147,
                "text": "    static QString deg2grid(float dlong, float dlat);"
              }
            ]
          }
        },
        {
          "line": 149,
          "matches": [
            "pack"
          ],
          "snippet": {
            "start_line": 143,
            "end_line": 155,
            "lines": [
              {
                "line": 143,
                "text": ""
              },
              {
                "line": 144,
                "text": "    static quint32 packCallsign(QString const &value, bool *pPortable);"
              },
              {
                "line": 145,
                "text": "    static QString unpackCallsign(quint32 value, bool portable);"
              },
              {
                "line": 146,
                "text": ""
              },
              {
                "line": 147,
                "text": "    static QString deg2grid(float dlong, float dlat);"
              },
              {
                "line": 148,
                "text": "    static QPair<float, float> grid2deg(QString const &grid);"
              },
              {
                "line": 149,
                "text": "    static quint16 packGrid(QString const &value);"
              },
              {
                "line": 150,
                "text": "    static QString unpackGrid(quint16 value);"
              },
              {
                "line": 151,
                "text": ""
              },
              {
                "line": 152,
                "text": "    static quint8 packNum(QString const &num, bool *ok);"
              },
              {
                "line": 153,
                "text": "    static quint8 packPwr(QString const &pwr, bool *ok);"
              },
              {
                "line": 154,
                "text": "    static quint8 packCmd(quint8 cmd, quint8 num, bool *pPackedNum);"
              },
              {
                "line": 155,
                "text": "    static quint8 unpackCmd(quint8 value, quint8 *pNum);"
              }
            ]
          }
        },
        {
          "line": 152,
          "matches": [
            "pack"
          ],
          "snippet": {
            "start_line": 146,
            "end_line": 158,
            "lines": [
              {
                "line": 146,
                "text": ""
              },
              {
                "line": 147,
                "text": "    static QString deg2grid(float dlong, float dlat);"
              },
              {
                "line": 148,
                "text": "    static QPair<float, float> grid2deg(QString const &grid);"
              },
              {
                "line": 149,
                "text": "    static quint16 packGrid(QString const &value);"
              },
              {
                "line": 150,
                "text": "    static QString unpackGrid(quint16 value);"
              },
              {
                "line": 151,
                "text": ""
              },
              {
                "line": 152,
                "text": "    static quint8 packNum(QString const &num, bool *ok);"
              },
              {
                "line": 153,
                "text": "    static quint8 packPwr(QString const &pwr, bool *ok);"
              },
              {
                "line": 154,
                "text": "    static quint8 packCmd(quint8 cmd, quint8 num, bool *pPackedNum);"
              },
              {
                "line": 155,
                "text": "    static quint8 unpackCmd(quint8 value, quint8 *pNum);"
              },
              {
                "line": 156,
                "text": ""
              },
              {
                "line": 157,
                "text": "    static bool isSNRCommand(const QString &cmd);"
              },
              {
                "line": 158,
                "text": "    static bool isCommandAllowed(const QString &cmd);"
              }
            ]
          }
        },
        {
          "line": 166,
          "matches": [
            "pack",
            "message"
          ],
          "snippet": {
            "start_line": 160,
            "end_line": 172,
            "lines": [
              {
                "line": 160,
                "text": "    static int isCommandChecksumed(const QString &cmd);"
              },
              {
                "line": 161,
                "text": "    static bool isCommandAutoreply(const QString &cmd);"
              },
              {
                "line": 162,
                "text": "    static bool isValidCallsign(const QString &callsign, bool *pIsCompound);"
              },
              {
                "line": 163,
                "text": "    static bool isCompoundCallsign(const QString &callsign);"
              },
              {
                "line": 164,
                "text": "    static bool isGroupAllowed(const QString &group);"
              },
              {
                "line": 165,
                "text": ""
              },
              {
                "line": 166,
                "text": "    static QString packHeartbeatMessage(QString const &text,"
              },
              {
                "line": 167,
                "text": "                                        QString const &callsign, int *n);"
              },
              {
                "line": 168,
                "text": "    static QStringList unpackHeartbeatMessage(const QString &text,"
              },
              {
                "line": 169,
                "text": "                                              quint8 *pType, bool *isAlt,"
              },
              {
                "line": 170,
                "text": "                                              quint8 *pBits3);"
              },
              {
                "line": 171,
                "text": ""
              },
              {
                "line": 172,
                "text": "    static QString packCompoundMessage(QString const &text, int *n);"
              }
            ]
          }
        },
        {
          "line": 172,
          "matches": [
            "pack",
            "message"
          ],
          "snippet": {
            "start_line": 166,
            "end_line": 178,
            "lines": [
              {
                "line": 166,
                "text": "    static QString packHeartbeatMessage(QString const &text,"
              },
              {
                "line": 167,
                "text": "                                        QString const &callsign, int *n);"
              },
              {
                "line": 168,
                "text": "    static QStringList unpackHeartbeatMessage(const QString &text,"
              },
              {
                "line": 169,
                "text": "                                              quint8 *pType, bool *isAlt,"
              },
              {
                "line": 170,
                "text": "                                              quint8 *pBits3);"
              },
              {
                "line": 171,
                "text": ""
              },
              {
                "line": 172,
                "text": "    static QString packCompoundMessage(QString const &text, int *n);"
              },
              {
                "line": 173,
                "text": "    static QStringList unpackCompoundMessage(const QString &text, quint8 *pType,"
              },
              {
                "line": 174,
                "text": "                                             quint8 *pBits3);"
              },
              {
                "line": 175,
                "text": ""
              },
              {
                "line": 176,
                "text": "    static QString packCompoundFrame(const QString &callsign, quint8 type,"
              },
              {
                "line": 177,
                "text": "                                     quint16 num, quint8 bits3);"
              },
              {
                "line": 178,
                "text": "    static QStringList unpackCompoundFrame(const QString &text, quint8 *pType,"
              }
            ]
          }
        },
        {
          "line": 176,
          "matches": [
            "pack"
          ],
          "snippet": {
            "start_line": 170,
            "end_line": 182,
            "lines": [
              {
                "line": 170,
                "text": "                                              quint8 *pBits3);"
              },
              {
                "line": 171,
                "text": ""
              },
              {
                "line": 172,
                "text": "    static QString packCompoundMessage(QString const &text, int *n);"
              },
              {
                "line": 173,
                "text": "    static QStringList unpackCompoundMessage(const QString &text, quint8 *pType,"
              },
              {
                "line": 174,
                "text": "                                             quint8 *pBits3);"
              },
              {
                "line": 175,
                "text": ""
              },
              {
                "line": 176,
                "text": "    static QString packCompoundFrame(const QString &callsign, quint8 type,"
              },
              {
                "line": 177,
                "text": "                                     quint16 num, quint8 bits3);"
              },
              {
                "line": 178,
                "text": "    static QStringList unpackCompoundFrame(const QString &text, quint8 *pType,"
              },
              {
                "line": 179,
                "text": "                                           quint16 *pNum, quint8 *pBits3);"
              },
              {
                "line": 180,
                "text": ""
              },
              {
                "line": 181,
                "text": "    static QString packDirectedMessage(QString const &text,"
              },
              {
                "line": 182,
                "text": "                                       QString const &mycall, QString *pTo,"
              }
            ]
          }
        },
        {
          "line": 181,
          "matches": [
            "pack",
            "message"
          ],
          "snippet": {
            "start_line": 175,
            "end_line": 187,
            "lines": [
              {
                "line": 175,
                "text": ""
              },
              {
                "line": 176,
                "text": "    static QString packCompoundFrame(const QString &callsign, quint8 type,"
              },
              {
                "line": 177,
                "text": "                                     quint16 num, quint8 bits3);"
              },
              {
                "line": 178,
                "text": "    static QStringList unpackCompoundFrame(const QString &text, quint8 *pType,"
              },
              {
                "line": 179,
                "text": "                                           quint16 *pNum, quint8 *pBits3);"
              },
              {
                "line": 180,
                "text": ""
              },
              {
                "line": 181,
                "text": "    static QString packDirectedMessage(QString const &text,"
              },
              {
                "line": 182,
                "text": "                                       QString const &mycall, QString *pTo,"
              },
              {
                "line": 183,
                "text": "                                       bool *pToCompound, QString *pCmd,"
              },
              {
                "line": 184,
                "text": "                                       QString *pNum, int *n);"
              },
              {
                "line": 185,
                "text": "    static QStringList unpackDirectedMessage(QString const &text,"
              },
              {
                "line": 186,
                "text": "                                             quint8 *pType);"
              },
              {
                "line": 187,
                "text": ""
              }
            ]
          }
        },
        {
          "line": 188,
          "matches": [
            "pack",
            "message"
          ],
          "snippet": {
            "start_line": 182,
            "end_line": 194,
            "lines": [
              {
                "line": 182,
                "text": "                                       QString const &mycall, QString *pTo,"
              },
              {
                "line": 183,
                "text": "                                       bool *pToCompound, QString *pCmd,"
              },
              {
                "line": 184,
                "text": "                                       QString *pNum, int *n);"
              },
              {
                "line": 185,
                "text": "    static QStringList unpackDirectedMessage(QString const &text,"
              },
              {
                "line": 186,
                "text": "                                             quint8 *pType);"
              },
              {
                "line": 187,
                "text": ""
              },
              {
                "line": 188,
                "text": "    static QString packDataMessage(QString const &text, int *n);"
              },
              {
                "line": 189,
                "text": "    static QString unpackDataMessage(QString const &text);"
              },
              {
                "line": 190,
                "text": ""
              },
              {
                "line": 191,
                "text": "    static QString packFastDataMessage(QString const &text, int *n);"
              },
              {
                "line": 192,
                "text": "    static QString unpackFastDataMessage(QString const &text);"
              },
              {
                "line": 193,
                "text": ""
              },
              {
                "line": 194,
                "text": "    static QList<QPair<QString, int>>"
              }
            ]
          }
        },
        {
          "line": 191,
          "matches": [
            "pack",
            "message"
          ],
          "snippet": {
            "start_line": 185,
            "end_line": 197,
            "lines": [
              {
                "line": 185,
                "text": "    static QStringList unpackDirectedMessage(QString const &text,"
              },
              {
                "line": 186,
                "text": "                                             quint8 *pType);"
              },
              {
                "line": 187,
                "text": ""
              },
              {
                "line": 188,
                "text": "    static QString packDataMessage(QString const &text, int *n);"
              },
              {
                "line": 189,
                "text": "    static QString unpackDataMessage(QString const &text);"
              },
              {
                "line": 190,
                "text": ""
              },
              {
                "line": 191,
                "text": "    static QString packFastDataMessage(QString const &text, int *n);"
              },
              {
                "line": 192,
                "text": "    static QString unpackFastDataMessage(QString const &text);"
              },
              {
                "line": 193,
                "text": ""
              },
              {
                "line": 194,
                "text": "    static QList<QPair<QString, int>>"
              },
              {
                "line": 195,
                "text": "    buildMessageFrames(QString const &mycall, QString const &mygrid,"
              },
              {
                "line": 196,
                "text": "                       QString const &selectedCall, QString const &text,"
              },
              {
                "line": 197,
                "text": "                       bool forceIdentify, bool forceData, int submode,"
              }
            ]
          }
        },
        {
          "line": 198,
          "matches": [
            "message"
          ],
          "snippet": {
            "start_line": 192,
            "end_line": 204,
            "lines": [
              {
                "line": 192,
                "text": "    static QString unpackFastDataMessage(QString const &text);"
              },
              {
                "line": 193,
                "text": ""
              },
              {
                "line": 194,
                "text": "    static QList<QPair<QString, int>>"
              },
              {
                "line": 195,
                "text": "    buildMessageFrames(QString const &mycall, QString const &mygrid,"
              },
              {
                "line": 196,
                "text": "                       QString const &selectedCall, QString const &text,"
              },
              {
                "line": 197,
                "text": "                       bool forceIdentify, bool forceData, int submode,"
              },
              {
                "line": 198,
                "text": "                       MessageInfo *pInfo = nullptr);"
              },
              {
                "line": 199,
                "text": "};"
              },
              {
                "line": 200,
                "text": ""
              },
              {
                "line": 201,
                "text": "class BuildMessageFramesThread : public QThread {"
              },
              {
                "line": 202,
                "text": "    Q_OBJECT"
              },
              {
                "line": 203,
                "text": "  public:"
              },
              {
                "line": 204,
                "text": "    BuildMessageFramesThread(QString const &mycall, QString const &mygrid,"
              }
            ]
          }
        },
        {
          "line": 201,
          "matches": [
            "message"
          ],
          "snippet": {
            "start_line": 195,
            "end_line": 207,
            "lines": [
              {
                "line": 195,
                "text": "    buildMessageFrames(QString const &mycall, QString const &mygrid,"
              },
              {
                "line": 196,
                "text": "                       QString const &selectedCall, QString const &text,"
              },
              {
                "line": 197,
                "text": "                       bool forceIdentify, bool forceData, int submode,"
              },
              {
                "line": 198,
                "text": "                       MessageInfo *pInfo = nullptr);"
              },
              {
                "line": 199,
                "text": "};"
              },
              {
                "line": 200,
                "text": ""
              },
              {
                "line": 201,
                "text": "class BuildMessageFramesThread : public QThread {"
              },
              {
                "line": 202,
                "text": "    Q_OBJECT"
              },
              {
                "line": 203,
                "text": "  public:"
              },
              {
                "line": 204,
                "text": "    BuildMessageFramesThread(QString const &mycall, QString const &mygrid,"
              },
              {
                "line": 205,
                "text": "                             QString const &selectedCall, QString const &text,"
              },
              {
                "line": 206,
                "text": "                             bool forceIdentify, bool forceData, int submode,"
              },
              {
                "line": 207,
                "text": "                             QObject *parent = nullptr);"
              }
            ]
          }
        }
      ]
    },
    {
      "path": "JS8_JSC/JSC_map.cpp",
      "exists": true,
      "bytes": 7082880,
      "sha256": "ab2bd62ef594f4629a2c93b6de43f5469b1fd6fe67ebf4d24f915bd11ccef813",
      "line_count": 262172,
      "phase_hits": {
        "timing_submode": 0,
        "symbol_to_soft_bits": 590,
        "bit_order_interleaver": 398,
        "whitening_erasure": 119,
        "ldpc_decode": 6,
        "message91_crc_text": 152
      },
      "function_blocks": [],
      "keyword_snippets": [
        {
          "line": 2,
          "matches": [
            "map",
            "JSC"
          ],
          "snippet": {
            "start_line": 1,
            "end_line": 8,
            "lines": [
              {
                "line": 1,
                "text": "/**"
              },
              {
                "line": 2,
                "text": " * @file JSC_map.cpp"
              },
              {
                "line": 3,
                "text": " * @brief Implementation of JSC character map"
              },
              {
                "line": 4,
                "text": " *"
              },
              {
                "line": 5,
                "text": " * This file is part of JS8Call."
              },
              {
                "line": 6,
                "text": " *"
              },
              {
                "line": 7,
                "text": " * This program is free software: you can redistribute it and/or modify"
              },
              {
                "line": 8,
                "text": " * it under the terms of the GNU General Public License as published by"
              }
            ]
          }
        },
        {
          "line": 23,
          "matches": [
            "JSC"
          ],
          "snippet": {
            "start_line": 17,
            "end_line": 29,
            "lines": [
              {
                "line": 17,
                "text": " * You should have received a copy of the GNU General Public License"
              },
              {
                "line": 18,
                "text": " * along with this program.  If not, see <https://www.gnu.org/licenses/>."
              },
              {
                "line": 19,
                "text": " *"
              },
              {
                "line": 20,
                "text": " * (C) 2018 Jordan Sherer <kn4crd@gmail.com> - All Rights Reserved"
              },
              {
                "line": 21,
                "text": " */"
              },
              {
                "line": 22,
                "text": ""
              },
              {
                "line": 23,
                "text": "#include \"JSC.h\""
              },
              {
                "line": 24,
                "text": ""
              },
              {
                "line": 25,
                "text": "const Tuple JSC::map[262144] = {"
              },
              {
                "line": 26,
                "text": "    // str, len, index"
              },
              {
                "line": 27,
                "text": "    {\"E\", 1, 0},"
              },
              {
                "line": 28,
                "text": "    {\"T\", 1, 1},"
              },
              {
                "line": 29,
                "text": "    {\"A\", 1, 2},"
              }
            ]
          }
        },
        {
          "line": 2142,
          "matches": [
            "map"
          ],
          "snippet": {
            "start_line": 2136,
            "end_line": 2148,
            "lines": [
              {
                "line": 2136,
                "text": "    {\"PER\", 3, 2108},"
              },
              {
                "line": 2137,
                "text": "    {\"FIRE\", 4, 2109},"
              },
              {
                "line": 2138,
                "text": "    {\"YKO\", 3, 2110},"
              },
              {
                "line": 2139,
                "text": "    {\"CAMERAS\", 7, 2111},"
              },
              {
                "line": 2140,
                "text": "    {\"HEFA\", 4, 2112},"
              },
              {
                "line": 2141,
                "text": "    {\"OGW\", 3, 2113},"
              },
              {
                "line": 2142,
                "text": "    {\"MAPS\", 4, 2114},"
              },
              {
                "line": 2143,
                "text": "    {\"NGWI\", 4, 2115},"
              },
              {
                "line": 2144,
                "text": "    {\"SPORT\", 5, 2116},"
              },
              {
                "line": 2145,
                "text": "    {\"UXI\", 3, 2117},"
              },
              {
                "line": 2146,
                "text": "    {\"BANK\", 4, 2118},"
              },
              {
                "line": 2147,
                "text": "    {\"RATINGS\", 7, 2119},"
              },
              {
                "line": 2148,
                "text": "    {\"WRONG\", 5, 2120},"
              }
            ]
          }
        },
        {
          "line": 3552,
          "matches": [
            "map"
          ],
          "snippet": {
            "start_line": 3546,
            "end_line": 3558,
            "lines": [
              {
                "line": 3546,
                "text": "    {\"YLY\", 3, 3518},"
              },
              {
                "line": 3547,
                "text": "    {\"WASB\", 4, 3519},"
              },
              {
                "line": 3548,
                "text": "    {\"LYBE\", 4, 3520},"
              },
              {
                "line": 3549,
                "text": "    {\"IMMEDIATELY\", 11, 3521},"
              },
              {
                "line": 3550,
                "text": "    {\"ELEMENT\", 7, 3522},"
              },
              {
                "line": 3551,
                "text": "    {\"CONVERSATION\", 12, 3523},"
              },
              {
                "line": 3552,
                "text": "    {\"SITEMAP\", 7, 3524},"
              },
              {
                "line": 3553,
                "text": "    {\"RECOMMENDATIONS\", 15, 3525},"
              },
              {
                "line": 3554,
                "text": "    {\"ECHN\", 4, 3526},"
              },
              {
                "line": 3555,
                "text": "    {\"MOVED\", 5, 3527},"
              },
              {
                "line": 3556,
                "text": "    {\"HOUSTON\", 7, 3528},"
              },
              {
                "line": 3557,
                "text": "    {\"PMEN\", 4, 3529},"
              },
              {
                "line": 3558,
                "text": "    {\"IONP\", 4, 3530},"
              }
            ]
          }
        },
        {
          "line": 3673,
          "matches": [
            "code"
          ],
          "snippet": {
            "start_line": 3667,
            "end_line": 3679,
            "lines": [
              {
                "line": 3667,
                "text": "    {\"UALI\", 4, 3639},"
              },
              {
                "line": 3668,
                "text": "    {\"ATTEMPT\", 7, 3640},"
              },
              {
                "line": 3669,
                "text": "    {\"RUSSIA\", 6, 3641},"
              },
              {
                "line": 3670,
                "text": "    {\"VATI\", 4, 3642},"
              },
              {
                "line": 3671,
                "text": "    {\"ITAN\", 4, 3643},"
              },
              {
                "line": 3672,
                "text": "    {\"GONE\", 4, 3644},"
              },
              {
                "line": 3673,
                "text": "    {\"CODES\", 5, 3645},"
              },
              {
                "line": 3674,
                "text": "    {\"KINDS\", 5, 3646},"
              },
              {
                "line": 3675,
                "text": "    {\"BEGINNING\", 9, 3647},"
              },
              {
                "line": 3676,
                "text": "    {\"SEATTLE\", 7, 3648},"
              },
              {
                "line": 3677,
                "text": "    {\"ARDT\", 4, 3649},"
              },
              {
                "line": 3678,
                "text": "    {\"LCON\", 4, 3650},"
              },
              {
                "line": 3679,
                "text": "    {\"RESIDENT\", 8, 3651},"
              }
            ]
          }
        },
        {
          "line": 4835,
          "matches": [
            "map"
          ],
          "snippet": {
            "start_line": 4829,
            "end_line": 4841,
            "lines": [
              {
                "line": 4829,
                "text": "    {\"OBJECTIVES\", 10, 4801},"
              },
              {
                "line": 4830,
                "text": "    {\"NTWA\", 4, 4802},"
              },
              {
                "line": 4831,
                "text": "    {\"SCIENTIFIC\", 10, 4803},"
              },
              {
                "line": 4832,
                "text": "    {\"STATIONS\", 8, 4804},"
              },
              {
                "line": 4833,
                "text": "    {\"EOPE\", 4, 4805},"
              },
              {
                "line": 4834,
                "text": "    {\"EMOC\", 4, 4806},"
              },
              {
                "line": 4835,
                "text": "    {\"MAP\", 3, 4807},"
              },
              {
                "line": 4836,
                "text": "    {\"ERIG\", 4, 4808},"
              },
              {
                "line": 4837,
                "text": "    {\"SUGGESTED\", 9, 4809},"
              },
              {
                "line": 4838,
                "text": "    {\"GPS\", 3, 4810},"
              },
              {
                "line": 4839,
                "text": "    {\"OKV\", 3, 4811},"
              },
              {
                "line": 4840,
                "text": "    {\"MENTAL\", 6, 4812},"
              },
              {
                "line": 4841,
                "text": "    {\"REMAINS\", 7, 4813},"
              }
            ]
          }
        },
        {
          "line": 5154,
          "matches": [
            "code"
          ],
          "snippet": {
            "start_line": 5148,
            "end_line": 5160,
            "lines": [
              {
                "line": 5148,
                "text": "    {\"IONM\", 4, 5120},"
              },
              {
                "line": 5149,
                "text": "    {\"DWOR\", 4, 5121},"
              },
              {
                "line": 5150,
                "text": "    {\"SIGNIFICANTLY\", 13, 5122},"
              },
              {
                "line": 5151,
                "text": "    {\"SPEAKING\", 8, 5123},"
              },
              {
                "line": 5152,
                "text": "    {\"INTERNAL\", 8, 5124},"
              },
              {
                "line": 5153,
                "text": "    {\"PHOTOGRAPH\", 10, 5125},"
              },
              {
                "line": 5154,
                "text": "    {\"CODE\", 4, 5126},"
              },
              {
                "line": 5155,
                "text": "    {\"SPONSORS\", 8, 5127},"
              },
              {
                "line": 5156,
                "text": "    {\"FOX\", 3, 5128},"
              },
              {
                "line": 5157,
                "text": "    {\"UNLIMITED\", 9, 5129},"
              },
              {
                "line": 5158,
                "text": "    {\"NLYT\", 4, 5130},"
              },
              {
                "line": 5159,
                "text": "    {\"SETTING\", 7, 5131},"
              },
              {
                "line": 5160,
                "text": "    {\"NGDO\", 4, 5132},"
              }
            ]
          }
        },
        {
          "line": 6012,
          "matches": [
            "bits"
          ],
          "snippet": {
            "start_line": 6006,
            "end_line": 6018,
            "lines": [
              {
                "line": 6006,
                "text": "    {\"GPRO\", 4, 5978},"
              },
              {
                "line": 6007,
                "text": "    {\"WNTH\", 4, 5979},"
              },
              {
                "line": 6008,
                "text": "    {\"STOG\", 4, 5980},"
              },
              {
                "line": 6009,
                "text": "    {\"FLOW\", 4, 5981},"
              },
              {
                "line": 6010,
                "text": "    {\"WTHA\", 4, 5982},"
              },
              {
                "line": 6011,
                "text": "    {\"BEACH\", 5, 5983},"
              },
              {
                "line": 6012,
                "text": "    {\"BITS\", 4, 5984},"
              },
              {
                "line": 6013,
                "text": "    {\"HOUSEHOLD\", 9, 5985},"
              },
              {
                "line": 6014,
                "text": "    {\"NDMI\", 4, 5986},"
              },
              {
                "line": 6015,
                "text": "    {\"ATWI\", 4, 5987},"
              },
              {
                "line": 6016,
                "text": "    {\"CREAM\", 5, 5988},"
              },
              {
                "line": 6017,
                "text": "    {\"EXPERIMENT\", 10, 5989},"
              },
              {
                "line": 6018,
                "text": "    {\"OUHA\", 4, 5990},"
              }
            ]
          }
        },
        {
          "line": 6084,
          "matches": [
            "map"
          ],
          "snippet": {
            "start_line": 6078,
            "end_line": 6090,
            "lines": [
              {
                "line": 6078,
                "text": "    {\"COPY\", 4, 6050},"
              },
              {
                "line": 6079,
                "text": "    {\"LOVED\", 5, 6051},"
              },
              {
                "line": 6080,
                "text": "    {\"ALLB\", 4, 6052},"
              },
              {
                "line": 6081,
                "text": "    {\"NGRO\", 4, 6053},"
              },
              {
                "line": 6082,
                "text": "    {\"FAVOURITES\", 10, 6054},"
              },
              {
                "line": 6083,
                "text": "    {\"ERPO\", 4, 6055},"
              },
              {
                "line": 6084,
                "text": "    {\"MAPPING\", 7, 6056},"
              },
              {
                "line": 6085,
                "text": "    {\"LIBERAL\", 7, 6057},"
              },
              {
                "line": 6086,
                "text": "    {\"FEWER\", 5, 6058},"
              },
              {
                "line": 6087,
                "text": "    {\"OWHE\", 4, 6059},"
              },
              {
                "line": 6088,
                "text": "    {\"BIRDS\", 5, 6060},"
              },
              {
                "line": 6089,
                "text": "    {\"DEFINITELY\", 10, 6061},"
              },
              {
                "line": 6090,
                "text": "    {\"REPRESENTS\", 10, 6062},"
              }
            ]
          }
        },
        {
          "line": 29018,
          "matches": [
            "map"
          ],
          "snippet": {
            "start_line": 29012,
            "end_line": 29024,
            "lines": [
              {
                "line": 29012,
                "text": "    {\"YSOM\", 4, 28984},"
              },
              {
                "line": 29013,
                "text": "    {\"MIRACLE\", 7, 28985},"
              },
              {
                "line": 29014,
                "text": "    {\"TALT\", 4, 28986},"
              },
              {
                "line": 29015,
                "text": "    {\"CHASE\", 5, 28987},"
              },
              {
                "line": 29016,
                "text": "    {\"STYLISH\", 7, 28988},"
              },
              {
                "line": 29017,
                "text": "    {\"SLIM\", 4, 28989},"
              },
              {
                "line": 29018,
                "text": "    {\"MAPLE\", 5, 28990},"
              },
              {
                "line": 29019,
                "text": "    {\"LUKE\", 4, 28991},"
              },
              {
                "line": 29020,
                "text": "    {\"ARCHITECT\", 9, 28992},"
              },
              {
                "line": 29021,
                "text": "    {\"GWHI\", 4, 28993},"
              },
              {
                "line": 29022,
                "text": "    {\"LTOT\", 4, 28994},"
              },
              {
                "line": 29023,
                "text": "    {\"SQB\", 3, 28995},"
              },
              {
                "line": 29024,
                "text": "    {\"PIANO\", 5, 28996},"
              }
            ]
          }
        },
        {
          "line": 31660,
          "matches": [
            "bits"
          ],
          "snippet": {
            "start_line": 31654,
            "end_line": 31666,
            "lines": [
              {
                "line": 31654,
                "text": "    {\"KELKOO\", 6, 31626},"
              },
              {
                "line": 31655,
                "text": "    {\"STEEP\", 5, 31627},"
              },
              {
                "line": 31656,
                "text": "    {\"O'CLOCK\", 7, 31628},"
              },
              {
                "line": 31657,
                "text": "    {\"ADOU\", 4, 31629},"
              },
              {
                "line": 31658,
                "text": "    {\"YPOL\", 4, 31630},"
              },
              {
                "line": 31659,
                "text": "    {\"RETRIEVED\", 9, 31631},"
              },
              {
                "line": 31660,
                "text": "    {\"EXHIBITS\", 8, 31632},"
              },
              {
                "line": 31661,
                "text": "    {\"OLOS\", 4, 31633},"
              },
              {
                "line": 31662,
                "text": "    {\"CONSORTIUM\", 10, 31634},"
              },
              {
                "line": 31663,
                "text": "    {\"DIES\", 4, 31635},"
              },
              {
                "line": 31664,
                "text": "    {\"UWAN\", 4, 31636},"
              },
              {
                "line": 31665,
                "text": "    {\"TERRACE\", 7, 31637},"
              },
              {
                "line": 31666,
                "text": "    {\"SHARPLY\", 7, 31638},"
              }
            ]
          }
        },
        {
          "line": 34407,
          "matches": [
            "bits"
          ],
          "snippet": {
            "start_line": 34401,
            "end_line": 34413,
            "lines": [
              {
                "line": 34401,
                "text": "    {\"EKSA\", 4, 34373},"
              },
              {
                "line": 34402,
                "text": "    {\"GUED\", 4, 34374},"
              },
              {
                "line": 34403,
                "text": "    {\"SOWH\", 4, 34375},"
              },
              {
                "line": 34404,
                "text": "    {\"ASGI\", 4, 34376},"
              },
              {
                "line": 34405,
                "text": "    {\"COMPARABLE\", 10, 34377},"
              },
              {
                "line": 34406,
                "text": "    {\"ONOV\", 4, 34378},"
              },
              {
                "line": 34407,
                "text": "    {\"HABITS\", 6, 34379},"
              },
              {
                "line": 34408,
                "text": "    {\"YOFL\", 4, 34380},"
              },
              {
                "line": 34409,
                "text": "    {\"SAFR\", 4, 34381},"
              },
              {
                "line": 34410,
                "text": "    {\"INFECTIOUS\", 10, 34382},"
              },
              {
                "line": 34411,
                "text": "    {\"PODCASTS\", 8, 34383},"
              },
              {
                "line": 34412,
                "text": "    {\"STEAK\", 5, 34384},"
              },
              {
                "line": 34413,
                "text": "    {\"GEDB\", 4, 34385},"
              }
            ]
          }
        },
        {
          "line": 37431,
          "matches": [
            "code"
          ],
          "snippet": {
            "start_line": 37425,
            "end_line": 37437,
            "lines": [
              {
                "line": 37425,
                "text": "    {\"ATFR\", 4, 37397},"
              },
              {
                "line": 37426,
                "text": "    {\"LDFI\", 4, 37398},"
              },
              {
                "line": 37427,
                "text": "    {\"SHIFTS\", 6, 37399},"
              },
              {
                "line": 37428,
                "text": "    {\"INACTIVE\", 8, 37400},"
              },
              {
                "line": 37429,
                "text": "    {\"LANSING\", 7, 37401},"
              },
              {
                "line": 37430,
                "text": "    {\"TRAVELED\", 8, 37402},"
              },
              {
                "line": 37431,
                "text": "    {\"BARCODE\", 7, 37403},"
              },
              {
                "line": 37432,
                "text": "    {\"WINC\", 4, 37404},"
              },
              {
                "line": 37433,
                "text": "    {\"TSBY\", 4, 37405},"
              },
              {
                "line": 37434,
                "text": "    {\"PECU\", 4, 37406},"
              },
              {
                "line": 37435,
                "text": "    {\"EXTRACTED\", 9, 37407},"
              },
              {
                "line": 37436,
                "text": "    {\"URTR\", 4, 37408},"
              },
              {
                "line": 37437,
                "text": "    {\"ACCESSION\", 9, 37409},"
              }
            ]
          }
        },
        {
          "line": 37459,
          "matches": [
            "code"
          ],
          "snippet": {
            "start_line": 37453,
            "end_line": 37465,
            "lines": [
              {
                "line": 37453,
                "text": "    {\"HIPB\", 4, 37425},"
              },
              {
                "line": 37454,
                "text": "    {\"FUELS\", 5, 37426},"
              },
              {
                "line": 37455,
                "text": "    {\"UTBY\", 4, 37427},"
              },
              {
                "line": 37456,
                "text": "    {\"ELFW\", 4, 37428},"
              },
              {
                "line": 37457,
                "text": "    {\"GERF\", 4, 37429},"
              },
              {
                "line": 37458,
                "text": "    {\"ELYL\", 4, 37430},"
              },
              {
                "line": 37459,
                "text": "    {\"POSTCODE\", 8, 37431},"
              },
              {
                "line": 37460,
                "text": "    {\"DATR\", 4, 37432},"
              },
              {
                "line": 37461,
                "text": "    {\"SFRA\", 4, 37433},"
              },
              {
                "line": 37462,
                "text": "    {\"BRETT\", 5, 37434},"
              },
              {
                "line": 37463,
                "text": "    {\"EJAP\", 4, 37435},"
              },
              {
                "line": 37464,
                "text": "    {\"MAKEFILE\", 8, 37436},"
              },
              {
                "line": 37465,
                "text": "    {\"ULOU\", 4, 37437},"
              }
            ]
          }
        },
        {
          "line": 38181,
          "matches": [
            "code"
          ],
          "snippet": {
            "start_line": 38175,
            "end_line": 38187,
            "lines": [
              {
                "line": 38175,
                "text": "    {\"RECOGNIZES\", 10, 38147},"
              },
              {
                "line": 38176,
                "text": "    {\"PLUGS\", 5, 38148},"
              },
              {
                "line": 38177,
                "text": "    {\"DOFO\", 4, 38149},"
              },
              {
                "line": 38178,
                "text": "    {\"GUPA\", 4, 38150},"
              },
              {
                "line": 38179,
                "text": "    {\"RESPONSIVE\", 10, 38151},"
              },
              {
                "line": 38180,
                "text": "    {\"DFAI\", 4, 38152},"
              },
              {
                "line": 38181,
                "text": "    {\"CODED\", 5, 38153},"
              },
              {
                "line": 38182,
                "text": "    {\"SUPRA\", 5, 38154},"
              },
              {
                "line": 38183,
                "text": "    {\"OMITTED\", 7, 38155},"
              },
              {
                "line": 38184,
                "text": "    {\"NFIV\", 4, 38156},"
              },
              {
                "line": 38185,
                "text": "    {\"MOLLY\", 5, 38157},"
              },
              {
                "line": 38186,
                "text": "    {\"PROXIMITY\", 9, 38158},"
              },
              {
                "line": 38187,
                "text": "    {\"WWHE\", 4, 38159},"
              }
            ]
          }
        },
        {
          "line": 40590,
          "matches": [
            "code"
          ],
          "snippet": {
            "start_line": 40584,
            "end_line": 40596,
            "lines": [
              {
                "line": 40584,
                "text": "    {\"SWINGING\", 8, 40556},"
              },
              {
                "line": 40585,
                "text": "    {\"ACCOUNTABLE\", 11, 40557},"
              },
              {
                "line": 40586,
                "text": "    {\"THRUST\", 6, 40558},"
              },
              {
                "line": 40587,
                "text": "    {\"PROVING\", 7, 40559},"
              },
              {
                "line": 40588,
                "text": "    {\"ZWR\", 3, 40560},"
              },
              {
                "line": 40589,
                "text": "    {\"QUEA\", 4, 40561},"
              },
              {
                "line": 40590,
                "text": "    {\"UNICODE\", 7, 40562},"
              },
              {
                "line": 40591,
                "text": "    {\"OPPOSING\", 8, 40563},"
              },
              {
                "line": 40592,
                "text": "    {\"PROD\", 4, 40564},"
              },
              {
                "line": 40593,
                "text": "    {\"OCOV\", 4, 40565},"
              },
              {
                "line": 40594,
                "text": "    {\"NOVICE\", 6, 40566},"
              },
              {
                "line": 40595,
                "text": "    {\"NLYN\", 4, 40567},"
              },
              {
                "line": 40596,
                "text": "    {\"LEQU\", 4, 40568},"
              }
            ]
          }
        },
        {
          "line": 40615,
          "matches": [
            "code"
          ],
          "snippet": {
            "start_line": 40609,
            "end_line": 40621,
            "lines": [
              {
                "line": 40609,
                "text": "    {\"CRUISING\", 8, 40581},"
              },
              {
                "line": 40610,
                "text": "    {\"AFIL\", 4, 40582},"
              },
              {
                "line": 40611,
                "text": "    {\"FURY\", 4, 40583},"
              },
              {
                "line": 40612,
                "text": "    {\"PERSONALITIES\", 13, 40584},"
              },
              {
                "line": 40613,
                "text": "    {\"DISCOGRAPHY\", 11, 40585},"
              },
              {
                "line": 40614,
                "text": "    {\"ECAB\", 4, 40586},"
              },
              {
                "line": 40615,
                "text": "    {\"ENCODED\", 7, 40587},"
              },
              {
                "line": 40616,
                "text": "    {\"LSUR\", 4, 40588},"
              },
              {
                "line": 40617,
                "text": "    {\"ABAM\", 4, 40589},"
              },
              {
                "line": 40618,
                "text": "    {\"RESEARCHING\", 11, 40590},"
              },
              {
                "line": 40619,
                "text": "    {\"WORE\", 4, 40591},"
              },
              {
                "line": 40620,
                "text": "    {\"CHRISTCHURCH\", 12, 40592},"
              },
              {
                "line": 40621,
                "text": "    {\"LZM\", 3, 40593},"
              }
            ]
          }
        },
        {
          "line": 40648,
          "matches": [
            "map"
          ],
          "snippet": {
            "start_line": 40642,
            "end_line": 40654,
            "lines": [
              {
                "line": 40642,
                "text": "    {\"SCATTERING\", 10, 40614},"
              },
              {
                "line": 40643,
                "text": "    {\"RGUA\", 4, 40615},"
              },
              {
                "line": 40644,
                "text": "    {\"DIDY\", 4, 40616},"
              },
              {
                "line": 40645,
                "text": "    {\"SECRETARIES\", 11, 40617},"
              },
              {
                "line": 40646,
                "text": "    {\"ONSITE\", 6, 40618},"
              },
              {
                "line": 40647,
                "text": "    {\"RUNW\", 4, 40619},"
              },
              {
                "line": 40648,
                "text": "    {\"MAPQUEST\", 8, 40620},"
              },
              {
                "line": 40649,
                "text": "    {\"CONTRACTED\", 10, 40621},"
              },
              {
                "line": 40650,
                "text": "    {\"MGOI\", 4, 40622},"
              },
              {
                "line": 40651,
                "text": "    {\"DEIG\", 4, 40623},"
              },
              {
                "line": 40652,
                "text": "    {\"FIGHTS\", 6, 40624},"
              },
              {
                "line": 40653,
                "text": "    {\"DELETING\", 8, 40625},"
              },
              {
                "line": 40654,
                "text": "    {\"ECTB\", 4, 40626},"
              }
            ]
          }
        },
        {
          "line": 41342,
          "matches": [
            "map"
          ],
          "snippet": {
            "start_line": 41336,
            "end_line": 41348,
            "lines": [
              {
                "line": 41336,
                "text": "    {\"LUED\", 4, 41308},"
              },
              {
                "line": 41337,
                "text": "    {\"REVEALING\", 9, 41309},"
              },
              {
                "line": 41338,
                "text": "    {\"DATM\", 4, 41310},"
              },
              {
                "line": 41339,
                "text": "    {\"FGAM\", 4, 41311},"
              },
              {
                "line": 41340,
                "text": "    {\"REPRINTED\", 9, 41312},"
              },
              {
                "line": 41341,
                "text": "    {\"FERNANDO\", 8, 41313},"
              },
              {
                "line": 41342,
                "text": "    {\"MAPPED\", 6, 41314},"
              },
              {
                "line": 41343,
                "text": "    {\"SORW\", 4, 41315},"
              },
              {
                "line": 41344,
                "text": "    {\"IERW\", 4, 41316},"
              },
              {
                "line": 41345,
                "text": "    {\"RESURRECTION\", 12, 41317},"
              },
              {
                "line": 41346,
                "text": "    {\"LIEU\", 4, 41318},"
              },
              {
                "line": 41347,
                "text": "    {\"DECREE\", 6, 41319},"
              },
              {
                "line": 41348,
                "text": "    {\"YUNT\", 4, 41320},"
              }
            ]
          }
        },
        {
          "line": 42365,
          "matches": [
            "code"
          ],
          "snippet": {
            "start_line": 42359,
            "end_line": 42371,
            "lines": [
              {
                "line": 42359,
                "text": "    {\"DECKER\", 6, 42331},"
              },
              {
                "line": 42360,
                "text": "    {\"EXTERN\", 6, 42332},"
              },
              {
                "line": 42361,
                "text": "    {\"SORF\", 4, 42333},"
              },
              {
                "line": 42362,
                "text": "    {\"BADGES\", 6, 42334},"
              },
              {
                "line": 42363,
                "text": "    {\"ENRON\", 5, 42335},"
              },
              {
                "line": 42364,
                "text": "    {\"KITTEN\", 6, 42336},"
              },
              {
                "line": 42365,
                "text": "    {\"CODEC\", 5, 42337},"
              },
              {
                "line": 42366,
                "text": "    {\"FBUT\", 4, 42338},"
              },
              {
                "line": 42367,
                "text": "    {\"BROADCASTS\", 10, 42339},"
              },
              {
                "line": 42368,
                "text": "    {\"BRIDES\", 6, 42340},"
              },
              {
                "line": 42369,
                "text": "    {\"IXTU\", 4, 42341},"
              },
              {
                "line": 42370,
                "text": "    {\"CHECKSUM\", 8, 42342},"
              },
              {
                "line": 42371,
                "text": "    {\"STEALING\", 8, 42343},"
              }
            ]
          }
        },
        {
          "line": 42614,
          "matches": [
            "bits"
          ],
          "snippet": {
            "start_line": 42608,
            "end_line": 42620,
            "lines": [
              {
                "line": 42608,
                "text": "    {\"OQUA\", 4, 42580},"
              },
              {
                "line": 42609,
                "text": "    {\"MALAYSIAN\", 9, 42581},"
              },
              {
                "line": 42610,
                "text": "    {\"EAUC\", 4, 42582},"
              },
              {
                "line": 42611,
                "text": "    {\"CLUES\", 5, 42583},"
              },
              {
                "line": 42612,
                "text": "    {\"INFLAMMATION\", 12, 42584},"
              },
              {
                "line": 42613,
                "text": "    {\"QUEB\", 4, 42585},"
              },
              {
                "line": 42614,
                "text": "    {\"RABBITS\", 7, 42586},"
              },
              {
                "line": 42615,
                "text": "    {\"PSFO\", 4, 42587},"
              },
              {
                "line": 42616,
                "text": "    {\"ORAV\", 4, 42588},"
              },
              {
                "line": 42617,
                "text": "    {\"TRANSPORTED\", 11, 42589},"
              },
              {
                "line": 42618,
                "text": "    {\"CREWS\", 5, 42590},"
              },
              {
                "line": 42619,
                "text": "    {\"TOFY\", 4, 42591},"
              },
              {
                "line": 42620,
                "text": "    {\"EASTON\", 6, 42592},"
              }
            ]
          }
        },
        {
          "line": 43476,
          "matches": [
            "code"
          ],
          "snippet": {
            "start_line": 43470,
            "end_line": 43482,
            "lines": [
              {
                "line": 43470,
                "text": "    {\"BLASTER\", 7, 43442},"
              },
              {
                "line": 43471,
                "text": "    {\"YORD\", 4, 43443},"
              },
              {
                "line": 43472,
                "text": "    {\"DDAT\", 4, 43444},"
              },
              {
                "line": 43473,
                "text": "    {\"TVIR\", 4, 43445},"
              },
              {
                "line": 43474,
                "text": "    {\"REMEDIATION\", 11, 43446},"
              },
              {
                "line": 43475,
                "text": "    {\"WASTING\", 7, 43447},"
              },
              {
                "line": 43476,
                "text": "    {\"DECODER\", 7, 43448},"
              },
              {
                "line": 43477,
                "text": "    {\"FELO\", 4, 43449},"
              },
              {
                "line": 43478,
                "text": "    {\"GENOCIDE\", 8, 43450},"
              },
              {
                "line": 43479,
                "text": "    {\"ACCLAIMED\", 9, 43451},"
              },
              {
                "line": 43480,
                "text": "    {\"HEATHROW\", 8, 43452},"
              },
              {
                "line": 43481,
                "text": "    {\"INDY\", 4, 43453},"
              },
              {
                "line": 43482,
                "text": "    {\"URWI\", 4, 43454},"
              }
            ]
          }
        }
      ]
    },
    {
      "path": "JS8_JSC/JSC_list.cpp",
      "exists": true,
      "bytes": 7085560,
      "sha256": "993811813f1cd6e00e399f25352a34ae477b7e1b50745204c32d3df0058a0491",
      "line_count": 262278,
      "phase_hits": {
        "timing_submode": 0,
        "symbol_to_soft_bits": 590,
        "bit_order_interleaver": 398,
        "whitening_erasure": 119,
        "ldpc_decode": 6,
        "message91_crc_text": 153
      },
      "function_blocks": [],
      "keyword_snippets": [
        {
          "line": 2,
          "matches": [
            "list",
            "JSC"
          ],
          "snippet": {
            "start_line": 1,
            "end_line": 8,
            "lines": [
              {
                "line": 1,
                "text": "/**"
              },
              {
                "line": 2,
                "text": " * @file JSC_list.cpp"
              },
              {
                "line": 3,
                "text": " * @brief Tuple list for JSC callsigns"
              },
              {
                "line": 4,
                "text": " *"
              },
              {
                "line": 5,
                "text": " * This file is part of JS8Call."
              },
              {
                "line": 6,
                "text": " *"
              },
              {
                "line": 7,
                "text": " * This program is free software: you can redistribute it and/or modify"
              },
              {
                "line": 8,
                "text": " * it under the terms of the GNU General Public License as published by"
              }
            ]
          }
        },
        {
          "line": 23,
          "matches": [
            "JSC"
          ],
          "snippet": {
            "start_line": 17,
            "end_line": 29,
            "lines": [
              {
                "line": 17,
                "text": " * You should have received a copy of the GNU General Public License"
              },
              {
                "line": 18,
                "text": " * along with this program.  If not, see <https://www.gnu.org/licenses/>."
              },
              {
                "line": 19,
                "text": " *"
              },
              {
                "line": 20,
                "text": " * (C) 2018 Jordan Sherer <kn4crd@gmail.com> - All Rights Reserved"
              },
              {
                "line": 21,
                "text": " */"
              },
              {
                "line": 22,
                "text": ""
              },
              {
                "line": 23,
                "text": "#include \"JSC.h\""
              },
              {
                "line": 24,
                "text": ""
              },
              {
                "line": 25,
                "text": "const Tuple JSC::list[262144] = {"
              },
              {
                "line": 26,
                "text": "    // str, len, index"
              },
              {
                "line": 27,
                "text": "    {\"~\", 1, 66},"
              },
              {
                "line": 28,
                "text": "    {\"}\", 1, 61},"
              },
              {
                "line": 29,
                "text": "    {\"|\", 1, 62},"
              }
            ]
          }
        },
        {
          "line": 1142,
          "matches": [
            "code"
          ],
          "snippet": {
            "start_line": 1136,
            "end_line": 1148,
            "lines": [
              {
                "line": 1136,
                "text": "    {\"ZIPING\", 6, 205320},"
              },
              {
                "line": 1137,
                "text": "    {\"ZIPI\", 4, 178964},"
              },
              {
                "line": 1138,
                "text": "    {\"ZIPFILE\", 7, 197461},"
              },
              {
                "line": 1139,
                "text": "    {\"ZIPF\", 4, 181942},"
              },
              {
                "line": 1140,
                "text": "    {\"ZIPE\", 4, 218162},"
              },
              {
                "line": 1141,
                "text": "    {\"ZIPDATA\", 7, 195897},"
              },
              {
                "line": 1142,
                "text": "    {\"ZIPCODES\", 8, 134542},"
              },
              {
                "line": 1143,
                "text": "    {\"ZIPCODE\", 7, 55313},"
              },
              {
                "line": 1144,
                "text": "    {\"ZIPC\", 4, 92212},"
              },
              {
                "line": 1145,
                "text": "    {\"ZIPA\", 4, 103112},"
              },
              {
                "line": 1146,
                "text": "    {\"ZIP\", 3, 284},"
              },
              {
                "line": 1147,
                "text": "    {\"ZIOW\", 4, 201565},"
              },
              {
                "line": 1148,
                "text": "    {\"ZIOR\", 4, 179771},"
              }
            ]
          }
        },
        {
          "line": 1206,
          "matches": [
            "list"
          ],
          "snippet": {
            "start_line": 1200,
            "end_line": 1212,
            "lines": [
              {
                "line": 1200,
                "text": "    {\"ZIMMERLI\", 8, 223980},"
              },
              {
                "line": 1201,
                "text": "    {\"ZIMMER\", 6, 56556},"
              },
              {
                "line": 1202,
                "text": "    {\"ZIMM\", 4, 233412},"
              },
              {
                "line": 1203,
                "text": "    {\"ZIMI\", 4, 128387},"
              },
              {
                "line": 1204,
                "text": "    {\"ZIME\", 4, 216448},"
              },
              {
                "line": 1205,
                "text": "    {\"ZIMBRA\", 6, 140743},"
              },
              {
                "line": 1206,
                "text": "    {\"ZIMBALIST\", 9, 209838},"
              },
              {
                "line": 1207,
                "text": "    {\"ZIMBABWEANS\", 11, 139393},"
              },
              {
                "line": 1208,
                "text": "    {\"ZIMBABWEAN\", 10, 92913},"
              },
              {
                "line": 1209,
                "text": "    {\"ZIMBABWE\", 8, 28311},"
              },
              {
                "line": 1210,
                "text": "    {\"ZIMBABAWE\", 9, 228606},"
              },
              {
                "line": 1211,
                "text": "    {\"ZIMB\", 4, 53822},"
              },
              {
                "line": 1212,
                "text": "    {\"ZIMAGE\", 6, 230394},"
              }
            ]
          }
        },
        {
          "line": 8185,
          "matches": [
            "code"
          ],
          "snippet": {
            "start_line": 8179,
            "end_line": 8191,
            "lines": [
              {
                "line": 8179,
                "text": "    {\"XCOP\", 4, 208111},"
              },
              {
                "line": 8180,
                "text": "    {\"XCOO\", 4, 254220},"
              },
              {
                "line": 8181,
                "text": "    {\"XCONQ\", 5, 169112},"
              },
              {
                "line": 8182,
                "text": "    {\"XCONFIG\", 7, 209763},"
              },
              {
                "line": 8183,
                "text": "    {\"XCOM\", 4, 204470},"
              },
              {
                "line": 8184,
                "text": "    {\"XCOL\", 4, 81498},"
              },
              {
                "line": 8185,
                "text": "    {\"XCODE\", 5, 101097},"
              },
              {
                "line": 8186,
                "text": "    {\"XCOD\", 4, 118995},"
              },
              {
                "line": 8187,
                "text": "    {\"XCOA\", 4, 174454},"
              },
              {
                "line": 8188,
                "text": "    {\"XCO\", 3, 1141},"
              },
              {
                "line": 8189,
                "text": "    {\"XCLUSIVE\", 8, 246585},"
              },
              {
                "line": 8190,
                "text": "    {\"XCLU\", 4, 32546},"
              },
              {
                "line": 8191,
                "text": "    {\"XCLO\", 4, 117585},"
              }
            ]
          }
        },
        {
          "line": 8878,
          "matches": [
            "list"
          ],
          "snippet": {
            "start_line": 8872,
            "end_line": 8884,
            "lines": [
              {
                "line": 8872,
                "text": "    {\"WWWDRAGONBALL\", 13, 233935},"
              },
              {
                "line": 8873,
                "text": "    {\"WWWDOWNLOAD\", 11, 233591},"
              },
              {
                "line": 8874,
                "text": "    {\"WWWDOGPILECOM\", 13, 233831},"
              },
              {
                "line": 8875,
                "text": "    {\"WWWDOCS\", 7, 213725},"
              },
              {
                "line": 8876,
                "text": "    {\"WWWDMVGOV\", 9, 234103},"
              },
              {
                "line": 8877,
                "text": "    {\"WWWDMVCAGOV\", 11, 234071},"
              },
              {
                "line": 8878,
                "text": "    {\"WWWDLISTATEPAUS\", 15, 234104},"
              },
              {
                "line": 8879,
                "text": "    {\"WWWDISNEY\", 9, 232637},"
              },
              {
                "line": 8880,
                "text": "    {\"WWWDISCOVERY\", 12, 234005},"
              },
              {
                "line": 8881,
                "text": "    {\"WWWDIGIMON\", 10, 234050},"
              },
              {
                "line": 8882,
                "text": "    {\"WWWDELLCOM\", 10, 233038},"
              },
              {
                "line": 8883,
                "text": "    {\"WWWDELL\", 7, 232526},"
              },
              {
                "line": 8884,
                "text": "    {\"WWWDAUMNET\", 10, 233936},"
              }
            ]
          }
        },
        {
          "line": 10115,
          "matches": [
            "list"
          ],
          "snippet": {
            "start_line": 10109,
            "end_line": 10121,
            "lines": [
              {
                "line": 10109,
                "text": "    {\"WORKMANS\", 8, 252910},"
              },
              {
                "line": 10110,
                "text": "    {\"WORKMANLIKE\", 11, 193541},"
              },
              {
                "line": 10111,
                "text": "    {\"WORKMAN\", 7, 64785},"
              },
              {
                "line": 10112,
                "text": "    {\"WORKLOG\", 7, 249332},"
              },
              {
                "line": 10113,
                "text": "    {\"WORKLOADS\", 9, 78358},"
              },
              {
                "line": 10114,
                "text": "    {\"WORKLOAD\", 8, 43287},"
              },
              {
                "line": 10115,
                "text": "    {\"WORKLIST\", 8, 160843},"
              },
              {
                "line": 10116,
                "text": "    {\"WORKLIFE\", 8, 135827},"
              },
              {
                "line": 10117,
                "text": "    {\"WORKKEYS\", 8, 223452},"
              },
              {
                "line": 10118,
                "text": "    {\"WORKINGTON\", 10, 113628},"
              },
              {
                "line": 10119,
                "text": "    {\"WORKINGS\", 8, 56310},"
              },
              {
                "line": 10120,
                "text": "    {\"WORKINGMEN\", 10, 247479},"
              },
              {
                "line": 10121,
                "text": "    {\"WORKINGMAN\", 10, 230516},"
              }
            ]
          }
        },
        {
          "line": 10194,
          "matches": [
            "list"
          ],
          "snippet": {
            "start_line": 10188,
            "end_line": 10200,
            "lines": [
              {
                "line": 10188,
                "text": "    {\"WORDPERFECT\", 11, 55951},"
              },
              {
                "line": 10189,
                "text": "    {\"WORDPAD\", 7, 131842},"
              },
              {
                "line": 10190,
                "text": "    {\"WORDNET\", 7, 64406},"
              },
              {
                "line": 10191,
                "text": "    {\"WORDMARK\", 8, 109529},"
              },
              {
                "line": 10192,
                "text": "    {\"WORDMAP\", 7, 186165},"
              },
              {
                "line": 10193,
                "text": "    {\"WORDLY\", 6, 217014},"
              },
              {
                "line": 10194,
                "text": "    {\"WORDLISTS\", 9, 249284},"
              },
              {
                "line": 10195,
                "text": "    {\"WORDLIST\", 8, 140035},"
              },
              {
                "line": 10196,
                "text": "    {\"WORDLET\", 7, 62465},"
              },
              {
                "line": 10197,
                "text": "    {\"WORDLESS\", 8, 139918},"
              },
              {
                "line": 10198,
                "text": "    {\"WORDINGS\", 8, 167281},"
              },
              {
                "line": 10199,
                "text": "    {\"WORDING\", 7, 44892},"
              },
              {
                "line": 10200,
                "text": "    {\"WORDINDEX\", 9, 203561},"
              }
            ]
          }
        },
        {
          "line": 11469,
          "matches": [
            "list"
          ],
          "snippet": {
            "start_line": 11463,
            "end_line": 11475,
            "lines": [
              {
                "line": 11463,
                "text": "    {\"WISL\", 4, 86239},"
              },
              {
                "line": 11464,
                "text": "    {\"WISKUNDE\", 8, 191467},"
              },
              {
                "line": 11465,
                "text": "    {\"WISK\", 4, 256565},"
              },
              {
                "line": 11466,
                "text": "    {\"WISJ\", 4, 140617},"
              },
              {
                "line": 11467,
                "text": "    {\"WISHY\", 5, 146582},"
              },
              {
                "line": 11468,
                "text": "    {\"WISHMASTER\", 10, 203883},"
              },
              {
                "line": 11469,
                "text": "    {\"WISHLISTS\", 9, 105588},"
              },
              {
                "line": 11470,
                "text": "    {\"WISHLIST\", 8, 8077},"
              },
              {
                "line": 11471,
                "text": "    {\"WISHING\", 7, 623},"
              },
              {
                "line": 11472,
                "text": "    {\"WISHIN\", 6, 215031},"
              },
              {
                "line": 11473,
                "text": "    {\"WISHFUL\", 7, 80801},"
              },
              {
                "line": 11474,
                "text": "    {\"WISHES\", 6, 622},"
              },
              {
                "line": 11475,
                "text": "    {\"WISHERS\", 7, 153242},"
              }
            ]
          }
        },
        {
          "line": 11992,
          "matches": [
            "list"
          ],
          "snippet": {
            "start_line": 11986,
            "end_line": 11998,
            "lines": [
              {
                "line": 11986,
                "text": "    {\"WILLMAR\", 7, 122914},"
              },
              {
                "line": 11987,
                "text": "    {\"WILLMAN\", 7, 212055},"
              },
              {
                "line": 11988,
                "text": "    {\"WILLL\", 5, 200439},"
              },
              {
                "line": 11989,
                "text": "    {\"WILLKOMMEN\", 10, 113187},"
              },
              {
                "line": 11990,
                "text": "    {\"WILLKIE\", 7, 236293},"
              },
              {
                "line": 11991,
                "text": "    {\"WILLITS\", 7, 102873},"
              },
              {
                "line": 11992,
                "text": "    {\"WILLISTON\", 9, 72274},"
              },
              {
                "line": 11993,
                "text": "    {\"WILLISON\", 8, 132171},"
              },
              {
                "line": 11994,
                "text": "    {\"WILLISMS\", 8, 246254},"
              },
              {
                "line": 11995,
                "text": "    {\"WILLIS\", 6, 38331},"
              },
              {
                "line": 11996,
                "text": "    {\"WILLIRAYE\", 9, 216928},"
              },
              {
                "line": 11997,
                "text": "    {\"WILLINGTON\", 10, 140698},"
              },
              {
                "line": 11998,
                "text": "    {\"WILLINGNESS\", 11, 32551},"
              }
            ]
          }
        },
        {
          "line": 12170,
          "matches": [
            "list"
          ],
          "snippet": {
            "start_line": 12164,
            "end_line": 12176,
            "lines": [
              {
                "line": 12164,
                "text": "    {\"WIKKA\", 5, 151396},"
              },
              {
                "line": 12165,
                "text": "    {\"WIKIWORDS\", 9, 126343},"
              },
              {
                "line": 12166,
                "text": "    {\"WIKIWORD\", 8, 106717},"
              },
              {
                "line": 12167,
                "text": "    {\"WIKIWIKIWEB\", 11, 185766},"
              },
              {
                "line": 12168,
                "text": "    {\"WIKIWIKI\", 8, 194318},"
              },
              {
                "line": 12169,
                "text": "    {\"WIKIWEBMASTER\", 13, 126029},"
              },
              {
                "line": 12170,
                "text": "    {\"WIKIWEBLIST\", 11, 212771},"
              },
              {
                "line": 12171,
                "text": "    {\"WIKIVERSITY\", 11, 237228},"
              },
              {
                "line": 12172,
                "text": "    {\"WIKIVERSION\", 11, 131922},"
              },
              {
                "line": 12173,
                "text": "    {\"WIKIUSERSTOPIC\", 14, 145174},"
              },
              {
                "line": 12174,
                "text": "    {\"WIKIUSERNAME\", 12, 89012},"
              },
              {
                "line": 12175,
                "text": "    {\"WIKITRAVEL\", 10, 175249},"
              },
              {
                "line": 12176,
                "text": "    {\"WIKITOOLNAME\", 12, 111221},"
              }
            ]
          }
        },
        {
          "line": 12522,
          "matches": [
            "list"
          ],
          "snippet": {
            "start_line": 12516,
            "end_line": 12528,
            "lines": [
              {
                "line": 12516,
                "text": "    {\"WHOMSOEVER\", 10, 118297},"
              },
              {
                "line": 12517,
                "text": "    {\"WHOMEVER\", 8, 69165},"
              },
              {
                "line": 12518,
                "text": "    {\"WHOME\", 5, 164401},"
              },
              {
                "line": 12519,
                "text": "    {\"WHOM\", 4, 3131},"
              },
              {
                "line": 12520,
                "text": "    {\"WHOLSALE\", 8, 238016},"
              },
              {
                "line": 12521,
                "text": "    {\"WHOLLY\", 6, 37797},"
              },
              {
                "line": 12522,
                "text": "    {\"WHOLISTIC\", 9, 157282},"
              },
              {
                "line": 12523,
                "text": "    {\"WHOLEVIEW\", 9, 234660},"
              },
              {
                "line": 12524,
                "text": "    {\"WHOLESOMENESS\", 13, 207416},"
              },
              {
                "line": 12525,
                "text": "    {\"WHOLESOME\", 9, 67095},"
              },
              {
                "line": 12526,
                "text": "    {\"WHOLESALING\", 11, 106014},"
              },
              {
                "line": 12527,
                "text": "    {\"WHOLESALES\", 10, 139335},"
              },
              {
                "line": 12528,
                "text": "    {\"WHOLESALERS\", 11, 40130},"
              }
            ]
          }
        },
        {
          "line": 12652,
          "matches": [
            "list"
          ],
          "snippet": {
            "start_line": 12646,
            "end_line": 12658,
            "lines": [
              {
                "line": 12646,
                "text": "    {\"WHITENER\", 8, 135371},"
              },
              {
                "line": 12647,
                "text": "    {\"WHITENED\", 8, 205059},"
              },
              {
                "line": 12648,
                "text": "    {\"WHITEN\", 6, 156305},"
              },
              {
                "line": 12649,
                "text": "    {\"WHITEMARSH\", 10, 261845},"
              },
              {
                "line": 12650,
                "text": "    {\"WHITEMAN\", 8, 98792},"
              },
              {
                "line": 12651,
                "text": "    {\"WHITELY\", 7, 240962},"
              },
              {
                "line": 12652,
                "text": "    {\"WHITELIST\", 9, 116997},"
              },
              {
                "line": 12653,
                "text": "    {\"WHITELEY\", 8, 106899},"
              },
              {
                "line": 12654,
                "text": "    {\"WHITELAW\", 8, 134868},"
              },
              {
                "line": 12655,
                "text": "    {\"WHITELAND\", 9, 197173},"
              },
              {
                "line": 12656,
                "text": "    {\"WHITEHURST\", 10, 134802},"
              },
              {
                "line": 12657,
                "text": "    {\"WHITEHOUSE\", 10, 69013},"
              },
              {
                "line": 12658,
                "text": "    {\"WHITEHORSE\", 10, 79659},"
              }
            ]
          }
        },
        {
          "line": 13618,
          "matches": [
            "list"
          ],
          "snippet": {
            "start_line": 13612,
            "end_line": 13624,
            "lines": [
              {
                "line": 13612,
                "text": "    {\"WELB\", 4, 133953},"
              },
              {
                "line": 13613,
                "text": "    {\"WELA\", 4, 72086},"
              },
              {
                "line": 13614,
                "text": "    {\"WEKN\", 4, 38136},"
              },
              {
                "line": 13615,
                "text": "    {\"WEKIVA\", 6, 227426},"
              },
              {
                "line": 13616,
                "text": "    {\"WEKI\", 4, 105251},"
              },
              {
                "line": 13617,
                "text": "    {\"WEKE\", 4, 76422},"
              },
              {
                "line": 13618,
                "text": "    {\"WEKALIST\", 8, 181789},"
              },
              {
                "line": 13619,
                "text": "    {\"WEKA\", 4, 152147},"
              },
              {
                "line": 13620,
                "text": "    {\"WEJU\", 4, 44620},"
              },
              {
                "line": 13621,
                "text": "    {\"WEJO\", 4, 165574},"
              },
              {
                "line": 13622,
                "text": "    {\"WEJ\", 3, 1628},"
              },
              {
                "line": 13623,
                "text": "    {\"WEIZMANN\", 8, 106634},"
              },
              {
                "line": 13624,
                "text": "    {\"WEIZ\", 4, 140425},"
              }
            ]
          }
        },
        {
          "line": 13917,
          "matches": [
            "list"
          ],
          "snippet": {
            "start_line": 13911,
            "end_line": 13923,
            "lines": [
              {
                "line": 13911,
                "text": "    {\"WEBUI\", 5, 167008},"
              },
              {
                "line": 13912,
                "text": "    {\"WEBTV\", 5, 88636},"
              },
              {
                "line": 13913,
                "text": "    {\"WEBTRENDS\", 9, 61423},"
              },
              {
                "line": 13914,
                "text": "    {\"WEBTRADE\", 8, 211022},"
              },
              {
                "line": 13915,
                "text": "    {\"WEBTOURIST\", 10, 121680},"
              },
              {
                "line": 13916,
                "text": "    {\"WEBTOPICVIEWTEMPLATE\", 20, 189992},"
              },
              {
                "line": 13917,
                "text": "    {\"WEBTOPICLIST\", 12, 86217},"
              },
              {
                "line": 13918,
                "text": "    {\"WEBTOPICEDITTEMPLATE\", 20, 139106},"
              },
              {
                "line": 13919,
                "text": "    {\"WEBTOP\", 6, 208855},"
              },
              {
                "line": 13920,
                "text": "    {\"WEBTOOLS\", 8, 135354},"
              },
              {
                "line": 13921,
                "text": "    {\"WEBTEST\", 7, 132472},"
              },
              {
                "line": 13922,
                "text": "    {\"WEBTENDER\", 9, 191217},"
              },
              {
                "line": 13923,
                "text": "    {\"WEBTECH\", 7, 174945},"
              }
            ]
          }
        },
        {
          "line": 14019,
          "matches": [
            "list"
          ],
          "snippet": {
            "start_line": 14013,
            "end_line": 14025,
            "lines": [
              {
                "line": 14013,
                "text": "    {\"WEBLOGIC\", 8, 50073},"
              },
              {
                "line": 14014,
                "text": "    {\"WEBLOGGING\", 10, 86727},"
              },
              {
                "line": 14015,
                "text": "    {\"WEBLOGGERS\", 10, 156420},"
              },
              {
                "line": 14016,
                "text": "    {\"WEBLOGGER\", 9, 146225},"
              },
              {
                "line": 14017,
                "text": "    {\"WEBLOGG\", 7, 128727},"
              },
              {
                "line": 14018,
                "text": "    {\"WEBLOG\", 6, 5292},"
              },
              {
                "line": 14019,
                "text": "    {\"WEBLISTS\", 8, 156425},"
              },
              {
                "line": 14020,
                "text": "    {\"WEBLIST\", 7, 88692},"
              },
              {
                "line": 14021,
                "text": "    {\"WEBLIOGRAPHY\", 12, 253671},"
              },
              {
                "line": 14022,
                "text": "    {\"WEBLINKS\", 8, 61668},"
              },
              {
                "line": 14023,
                "text": "    {\"WEBLINK\", 7, 96415},"
              },
              {
                "line": 14024,
                "text": "    {\"WEBLEY\", 6, 192822},"
              },
              {
                "line": 14025,
                "text": "    {\"WEBLEFTBAR\", 10, 123981},"
              }
            ]
          }
        },
        {
          "line": 14919,
          "matches": [
            "list"
          ],
          "snippet": {
            "start_line": 14913,
            "end_line": 14925,
            "lines": [
              {
                "line": 14913,
                "text": "    {\"WATCHTOWER\", 10, 84655},"
              },
              {
                "line": 14914,
                "text": "    {\"WATCHMEN\", 8, 109980},"
              },
              {
                "line": 14915,
                "text": "    {\"WATCHMAN\", 8, 83983},"
              },
              {
                "line": 14916,
                "text": "    {\"WATCHMAKING\", 11, 136059},"
              },
              {
                "line": 14917,
                "text": "    {\"WATCHMAKERS\", 11, 174423},"
              },
              {
                "line": 14918,
                "text": "    {\"WATCHMAKER\", 10, 110330},"
              },
              {
                "line": 14919,
                "text": "    {\"WATCHLISTS\", 10, 227853},"
              },
              {
                "line": 14920,
                "text": "    {\"WATCHLIST\", 9, 51304},"
              },
              {
                "line": 14921,
                "text": "    {\"WATCHING\", 8, 5606},"
              },
              {
                "line": 14922,
                "text": "    {\"WATCHIN\", 7, 120196},"
              },
              {
                "line": 14923,
                "text": "    {\"WATCHGUARD\", 10, 89761},"
              },
              {
                "line": 14924,
                "text": "    {\"WATCHFULNESS\", 12, 217558},"
              },
              {
                "line": 14925,
                "text": "    {\"WATCHFUL\", 8, 77748},"
              }
            ]
          }
        },
        {
          "line": 15298,
          "matches": [
            "list"
          ],
          "snippet": {
            "start_line": 15292,
            "end_line": 15304,
            "lines": [
              {
                "line": 15292,
                "text": "    {\"WANU\", 4, 97631},"
              },
              {
                "line": 15293,
                "text": "    {\"WANTS\", 5, 3845},"
              },
              {
                "line": 15294,
                "text": "    {\"WANTONNESSE\", 11, 203886},"
              },
              {
                "line": 15295,
                "text": "    {\"WANTONNESS\", 10, 256868},"
              },
              {
                "line": 15296,
                "text": "    {\"WANTONLY\", 8, 177252},"
              },
              {
                "line": 15297,
                "text": "    {\"WANTON\", 6, 80104},"
              },
              {
                "line": 15298,
                "text": "    {\"WANTLIST\", 8, 164558},"
              },
              {
                "line": 15299,
                "text": "    {\"WANTIRNA\", 8, 190980},"
              },
              {
                "line": 15300,
                "text": "    {\"WANTING\", 7, 31750},"
              },
              {
                "line": 15301,
                "text": "    {\"WANTIN\", 6, 250740},"
              },
              {
                "line": 15302,
                "text": "    {\"WANTED\", 6, 2130},"
              },
              {
                "line": 15303,
                "text": "    {\"WANTAGH\", 7, 140140},"
              },
              {
                "line": 15304,
                "text": "    {\"WANTAGE\", 7, 118376},"
              }
            ]
          }
        },
        {
          "line": 15633,
          "matches": [
            "list"
          ],
          "snippet": {
            "start_line": 15627,
            "end_line": 15639,
            "lines": [
              {
                "line": 15627,
                "text": "    {\"WAITS\", 5, 45852},"
              },
              {
                "line": 15628,
                "text": "    {\"WAITROSE\", 8, 130711},"
              },
              {
                "line": 15629,
                "text": "    {\"WAITRESSES\", 10, 103821},"
              },
              {
                "line": 15630,
                "text": "    {\"WAITRESS\", 8, 59450},"
              },
              {
                "line": 15631,
                "text": "    {\"WAITPID\", 7, 196529},"
              },
              {
                "line": 15632,
                "text": "    {\"WAITOMO\", 7, 160380},"
              },
              {
                "line": 15633,
                "text": "    {\"WAITLISTED\", 10, 209143},"
              },
              {
                "line": 15634,
                "text": "    {\"WAITLIST\", 8, 114442},"
              },
              {
                "line": 15635,
                "text": "    {\"WAITLEY\", 7, 247186},"
              },
              {
                "line": 15636,
                "text": "    {\"WAITING\", 7, 4139},"
              },
              {
                "line": 15637,
                "text": "    {\"WAITIN\", 6, 102497},"
              },
              {
                "line": 15638,
                "text": "    {\"WAITH\", 5, 140827},"
              },
              {
                "line": 15639,
                "text": "    {\"WAITES\", 6, 201362},"
              }
            ]
          }
        },
        {
          "line": 16974,
          "matches": [
            "code"
          ],
          "snippet": {
            "start_line": 16968,
            "end_line": 16980,
            "lines": [
              {
                "line": 16968,
                "text": "    {\"VODACOM\", 7, 98811},"
              },
              {
                "line": 16969,
                "text": "    {\"VODA\", 4, 132943},"
              },
              {
                "line": 16970,
                "text": "    {\"VOCW\", 4, 173146},"
              },
              {
                "line": 16971,
                "text": "    {\"VOCT\", 4, 212409},"
              },
              {
                "line": 16972,
                "text": "    {\"VOCS\", 4, 84855},"
              },
              {
                "line": 16973,
                "text": "    {\"VOCOPRO\", 7, 119430},"
              },
              {
                "line": 16974,
                "text": "    {\"VOCODER\", 7, 153702},"
              },
              {
                "line": 16975,
                "text": "    {\"VOCO\", 4, 100538},"
              },
              {
                "line": 16976,
                "text": "    {\"VOCIFEROUSLY\", 12, 199931},"
              },
              {
                "line": 16977,
                "text": "    {\"VOCIFEROUS\", 10, 151910},"
              },
              {
                "line": 16978,
                "text": "    {\"VOCI\", 4, 209014},"
              },
              {
                "line": 16979,
                "text": "    {\"VOCH\", 4, 180874},"
              },
              {
                "line": 16980,
                "text": "    {\"VOCES\", 5, 183965},"
              }
            ]
          }
        },
        {
          "line": 16994,
          "matches": [
            "list"
          ],
          "snippet": {
            "start_line": 16988,
            "end_line": 17000,
            "lines": [
              {
                "line": 16988,
                "text": "    {\"VOCALS\", 6, 32620},"
              },
              {
                "line": 16989,
                "text": "    {\"VOCALLY\", 7, 129889},"
              },
              {
                "line": 16990,
                "text": "    {\"VOCALIZING\", 10, 253385},"
              },
              {
                "line": 16991,
                "text": "    {\"VOCALIZE\", 8, 235123},"
              },
              {
                "line": 16992,
                "text": "    {\"VOCALIZATIONS\", 13, 153203},"
              },
              {
                "line": 16993,
                "text": "    {\"VOCALIZATION\", 12, 169961},"
              },
              {
                "line": 16994,
                "text": "    {\"VOCALISTS\", 9, 74043},"
              },
              {
                "line": 16995,
                "text": "    {\"VOCALIST\", 8, 54952},"
              },
              {
                "line": 16996,
                "text": "    {\"VOCALISE\", 8, 230150},"
              },
              {
                "line": 16997,
                "text": "    {\"VOCALIC\", 7, 231299},"
              },
              {
                "line": 16998,
                "text": "    {\"VOCALE\", 6, 255077},"
              },
              {
                "line": 16999,
                "text": "    {\"VOCAL\", 5, 34063},"
              },
              {
                "line": 17000,
                "text": "    {\"VOCABULARY\", 10, 33411},"
              }
            ]
          }
        },
        {
          "line": 17104,
          "matches": [
            "list"
          ],
          "snippet": {
            "start_line": 17098,
            "end_line": 17110,
            "lines": [
              {
                "line": 17098,
                "text": "    {\"VLOER\", 5, 188207},"
              },
              {
                "line": 17099,
                "text": "    {\"VLOCK\", 5, 254807},"
              },
              {
                "line": 17100,
                "text": "    {\"VLM\", 3, 167766},"
              },
              {
                "line": 17101,
                "text": "    {\"VLJ\", 3, 51042},"
              },
              {
                "line": 17102,
                "text": "    {\"VLIW\", 4, 176611},"
              },
              {
                "line": 17103,
                "text": "    {\"VLIV\", 4, 231829},"
              },
              {
                "line": 17104,
                "text": "    {\"VLIST\", 5, 189773},"
              },
              {
                "line": 17105,
                "text": "    {\"VLISSINGEN\", 10, 253975},"
              },
              {
                "line": 17106,
                "text": "    {\"VLIS\", 4, 200912},"
              },
              {
                "line": 17107,
                "text": "    {\"VLIPART\", 7, 235880},"
              },
              {
                "line": 17108,
                "text": "    {\"VLINK\", 5, 252048},"
              },
              {
                "line": 17109,
                "text": "    {\"VLIN\", 4, 88553},"
              },
              {
                "line": 17110,
                "text": "    {\"VLIK\", 4, 114645},"
              }
            ]
          }
        }
      ]
    },
    {
      "path": "JS8_Include/commons.h",
      "exists": true,
      "bytes": 3525,
      "sha256": "d7abc3090fcf5516b64435f78dfbd08dff9b01a56905afbe4d69fa4eb9c16048",
      "line_count": 106,
      "phase_hits": {
        "timing_submode": 3,
        "symbol_to_soft_bits": 6,
        "bit_order_interleaver": 0,
        "whitening_erasure": 0,
        "ldpc_decode": 0,
        "message91_crc_text": 0
      },
      "function_blocks": [],
      "keyword_snippets": [
        {
          "line": 11,
          "matches": [
            "JS8_NSPS"
          ],
          "snippet": {
            "start_line": 5,
            "end_line": 17,
            "lines": [
              {
                "line": 5,
                "text": "#include <mutex>"
              },
              {
                "line": 6,
                "text": ""
              },
              {
                "line": 7,
                "text": "// NSPS, the number of samples per second (at a sample rate of 12000"
              },
              {
                "line": 8,
                "text": "// samples per second) is a constant, chosen so as to be a number"
              },
              {
                "line": 9,
                "text": "// with no prime factor greater than 7."
              },
              {
                "line": 10,
                "text": ""
              },
              {
                "line": 11,
                "text": "#define JS8_NSPS           6192"
              },
              {
                "line": 12,
                "text": "#define JS8_NSMAX          6827"
              },
              {
                "line": 13,
                "text": "#define JS8_NTMAX          60"
              },
              {
                "line": 14,
                "text": "#define JS8_RX_SAMPLE_RATE 12000"
              },
              {
                "line": 15,
                "text": "#define JS8_RX_SAMPLE_SIZE (JS8_NTMAX * JS8_RX_SAMPLE_RATE)"
              },
              {
                "line": 16,
                "text": ""
              },
              {
                "line": 17,
                "text": "#define JS8_RING_BUFFER    1       // use a ring buffer instead of clearing the decode frames"
              }
            ]
          }
        }
      ]
    }
  ],
  "source_derived_next_patch_plan": [
    {
      "step": 1,
      "name": "Implement exact Costas/submode/timing constants from JS8Submode/commons",
      "why": "Step51 confirmed JS8_NSPS=6192 but still prefers tone-spacing offset -0.03; source snippets must show whether additional submode correction is applied."
    },
    {
      "step": 2,
      "name": "Replace lab FT8-style symbol-to-bit hypothesis with source-derived soft/LLR bitpath",
      "why": "Syndrome remains 22; exact pre-LDPC bit ordering is more likely than wider timing now."
    },
    {
      "step": 3,
      "name": "Apply source whitening/erasure/mask path before LDPC/message91 validation",
      "why": "CRC validation and guided repair do not validate current Message91 candidates."
    },
    {
      "step": 4,
      "name": "Only after source bitpath patch: rerun a bounded LDPC/CRC probe",
      "why": "Avoid another expensive blind repair run before the source path is reflected in JS8Lab."
    }
  ],
  "recommended_next_step": "Step55 should implement the first source-derived bitpath patch in JS8Lab, using these extracted snippets as evidence; do not start JS8Call GUI."
}
