///|
pub fn version() -> String {
  "0.1.0"
}

///|
pub fn default_dcp_identify_timeout_ms() -> Int {
  400
}

///|
pub fn default_dcp_set_get_timeout_ms() -> Int {
  1000
}

///|
pub fn default_dcp_set_get_max_retry_limit() -> Int {
  2
}

///|
pub fn mandatory_set_usage_time_ms() -> Int {
  400
}

///|
pub fn ip_address_change_bumpless() -> Bool {
  false
}

///|
pub fn station_name_change_bumpless() -> Bool {
  false
}

///|
pub fn recommended_ip_startup_time_ms() -> Int {
  30000
}

///|
pub fn mandatory_ip_startup_time_ms() -> Int {
  300000
}

///|
pub fn recommended_reset_to_factory_time_ms() -> Int {
  30000
}

///|
pub fn mandatory_reset_to_factory_time_ms() -> Int {
  300000
}

///|
pub fn recommended_ar_resource_release_timeout_ms() -> Int {
  100
}

///|
pub fn mandatory_ar_resource_release_timeout_ms() -> Int {
  1000
}

///|
pub fn recommended_autonegotiation_timeout_ms() -> Int {
  3000
}

///|
pub fn mandatory_autonegotiation_timeout_ms() -> Int {
  30000
}

///|
pub fn minimum_operational_link_speed_mbps() -> Int {
  100
}

///|
pub fn required_operational_duplex_mode() -> String {
  "full"
}

///|
pub fn diagnosis_link_state_mismatch_code() -> String {
  "0x8000"
}

///|
pub fn diagnosis_mau_type_mismatch_code() -> String {
  "0x8001"
}

///|
pub fn diagnosis_line_delay_mismatch_code() -> String {
  "0x8002"
}

///|
pub fn autonegotiation_fault_requires_link_restart() -> Bool {
  true
}

///|
pub fn pd_port_data_real_extended_record_index() -> String {
  "0x8027"
}

///|
pub fn pd_port_data_real_record_index() -> String {
  "0x802A"
}

///|
pub fn pd_port_data_check_record_index() -> String {
  "0x802B"
}

///|
pub fn pd_port_statistic_record_index() -> String {
  "0x8072"
}

///|
pub fn pd_interface_mrp_data_real_record_index() -> String {
  "0x8050"
}

///|
pub fn pd_port_mrp_data_real_record_index() -> String {
  "0x8054"
}

///|
pub fn pd_port_mrplc_data_real_record_index() -> String {
  "0x8057"
}

///|
pub fn pd_interface_data_real_record_index() -> String {
  "0x8080"
}

///|
pub fn pdev_data_record_index() -> String {
  "0xF831"
}

///|
pub fn pd_real_data_record_index() -> String {
  "0xF841"
}

///|
pub fn pd_port_data_check_supported_blocks() -> String {
  "CheckPeers,CheckLineDelay,CheckMAUType,CheckLinkState,CheckSyncDifference,CheckMAUTypeDifference"
}

///|
pub fn maximum_diagnosis_data_per_submodule_octets_exclusive_upper_bound() -> Int {
  65536
}

///|
pub fn mandatory_set_storage_time_ms() -> Int {
  30000
}

///|
pub fn minimum_logbook_entries() -> Int {
  16
}

///|
pub fn lldp_msg_tx_hold() -> Int {
  4
}

///|
pub fn lldp_msg_tx_interval_ms() -> Int {
  5000
}

///|
pub fn lldp_msg_tx_interval_positive_jitter_ms() -> Int {
  1000
}

///|
pub fn lldp_tx_ttl_ms() -> Int {
  21000
}

///|
pub fn lldp_tx_ttl_positive_jitter_ms() -> Int {
  2000
}

///|
pub fn lldp_tx_now_on_change() -> Bool {
  true
}

///|
pub fn lldp_minimum_neighbor_capacity() -> Int {
  1
}

///|
pub fn lldp_recommended_neighbor_capacity() -> Int {
  4
}

///|
pub fn pruning_mac_destination_support_recommended() -> Bool {
  true
}

///|
pub fn lldp_system_capabilities_station_only_required() -> Bool {
  true
}

///|
pub fn minimum_arp_cache_size() -> Int {
  32
}

///|
pub fn arp_cache_timeout_ms() -> Int {
  60000
}

///|
pub fn arp_response_timeout_ms() -> Int {
  2000
}

///|
pub fn dns_request_timeout_ms() -> Int {
  16000
}

///|
pub fn reject_dcp_set_requests_support() -> String {
  "optional"
}

///|
pub fn snmp_service_optional() -> Bool {
  true
}

///|
pub fn snmp_default_access_disabled() -> Bool {
  true
}

///|
pub fn dhcp_service_optional() -> Bool {
  true
}

///|
pub fn dhcp_subnet_mask_option_required() -> Bool {
  true
}

///|
pub fn dhcp_gateway_option_required() -> Bool {
  true
}

///|
pub fn dhcp_parameter_data_required_value() -> Int {
  2
}

///|
pub fn dhcp_other_options_optional() -> Bool {
  true
}

///|
pub fn snmp_explicit_enable_required() -> Bool {
  true
}

///|
pub fn snmp_disabled_after_ar_abort() -> Bool {
  true
}

///|
pub fn snmp_cim_interface_overrides_ar() -> Bool {
  true
}

///|
pub fn snmp_community_public_access() -> String {
  "read_only"
}

///|
pub fn snmp_community_private_access() -> String {
  "read_write"
}

///|
pub fn recommended_snmp_set_timeout_ms() -> Int {
  3000
}

///|
pub fn mandatory_snmp_set_timeout_ms() -> Int {
  10000
}

///|
pub fn recommended_snmp_get_timeout_ms() -> Int {
  3000
}

///|
pub fn mandatory_snmp_get_timeout_ms() -> Int {
  10000
}

///|
pub fn recommended_snmp_get_next_timeout_ms() -> Int {
  3000
}

///|
pub fn mandatory_snmp_get_next_timeout_ms() -> Int {
  10000
}

///|
pub fn recommended_snmp_mib_update_time_ms() -> Int {
  500
}

///|
pub fn mandatory_snmp_mib_update_time_ms() -> Int {
  3000
}

///|
pub fn snmp_feature_mib2_required() -> Bool {
  true
}

///|
pub fn snmp_feature_lldp_mib_required() -> Bool {
  true
}

///|
pub fn snmp_feature_ieee_8021as_mib_optional() -> Bool {
  true
}

///|
pub fn snmp_feature_bridge_mib_optional() -> Bool {
  true
}

///|
pub fn snmp_feature_pno_mib_optional() -> Bool {
  true
}

///|
pub fn set_usage_time_probeability() -> String {
  "active_dcp_poll"
}

///|
pub fn set_usage_time_probeability_class() -> String {
  "automatic_now"
}

///|
pub fn ip_startup_time_probeability() -> String {
  "active_dcp_poll"
}

///|
pub fn ip_startup_time_probeability_class() -> String {
  "automatic_now"
}

///|
pub fn reset_to_factory_time_probeability() -> String {
  "active_reset_poll"
}

///|
pub fn reset_to_factory_time_probeability_class() -> String {
  "requires_reset_workflow"
}

///|
pub fn ar_resource_release_time_probeability() -> String {
  "ar_session_trace"
}

///|
pub fn ar_resource_release_time_probeability_class() -> String {
  "requires_protocol_extension"
}

///|
pub fn autonegotiation_time_probeability() -> String {
  "link_state_trace"
}

///|
pub fn autonegotiation_time_probeability_class() -> String {
  "requires_link_state_capture"
}

///|
pub fn pd_port_data_real_probeability() -> String {
  "record_read_pdportdatareal"
}

///|
pub fn pd_port_data_real_probeability_class() -> String {
  "requires_protocol_extension"
}

///|
pub fn pd_interface_data_real_probeability() -> String {
  "record_read_pdinterfacedatareal"
}

///|
pub fn pd_interface_data_real_probeability_class() -> String {
  "requires_protocol_extension"
}

///|
pub fn pd_interface_mrp_data_real_probeability() -> String {
  "record_read_pdinterfacemrpdatareal"
}

///|
pub fn pd_interface_mrp_data_real_probeability_class() -> String {
  "requires_protocol_extension"
}

///|
pub fn pd_port_mrp_data_real_probeability() -> String {
  "record_read_pdportmrpdatareal"
}

///|
pub fn pd_port_mrp_data_real_probeability_class() -> String {
  "requires_protocol_extension"
}

///|
pub fn pd_port_mrplc_data_real_probeability() -> String {
  "record_read_pdportmrplcdatareal"
}

///|
pub fn pd_port_mrplc_data_real_probeability_class() -> String {
  "requires_protocol_extension"
}

///|
pub fn pdev_data_probeability() -> String {
  "record_read_pdevdata"
}

///|
pub fn pdev_data_probeability_class() -> String {
  "requires_protocol_extension"
}

///|
pub fn pd_real_data_probeability() -> String {
  "record_read_pdrealdata"
}

///|
pub fn pd_real_data_probeability_class() -> String {
  "requires_protocol_extension"
}

///|
pub fn pd_port_statistic_probeability() -> String {
  "record_read_pdportstatistic"
}

///|
pub fn pd_port_statistic_probeability_class() -> String {
  "requires_protocol_extension"
}

///|
pub fn lldp_neighbor_probeability() -> String {
  "passive_lldp_capture"
}

///|
pub fn lldp_neighbor_probeability_class() -> String {
  "requires_packet_capture"
}

///|
pub fn logbook_data_probeability() -> String {
  "record_read_logbookdata"
}

///|
pub fn logbook_data_probeability_class() -> String {
  "requires_protocol_extension"
}

///|
pub fn snmp_default_state_probeability() -> String {
  "record_read_cimsnmpreal"
}

///|
pub fn snmp_default_state_probeability_class() -> String {
  "requires_protocol_extension"
}

///|
pub fn snmp_timeout_probeability() -> String {
  "active_snmp_roundtrip"
}

///|
pub fn snmp_timeout_probeability_class() -> String {
  "requires_protocol_extension"
}

///|
pub fn snmp_mib_update_probeability() -> String {
  "active_snmp_polling"
}

///|
pub fn snmp_mib_update_probeability_class() -> String {
  "requires_protocol_extension"
}

///|
pub fn dhcp_option_support_probeability() -> String {
  "startup_trace_or_vendor_record"
}

///|
pub fn dhcp_option_support_probeability_class() -> String {
  "indirect_or_vendor_specific"
}

///|
pub fn dhcp_runtime_state_probeability() -> String {
  "indirect_ip_observation"
}

///|
pub fn dhcp_runtime_state_probeability_class() -> String {
  "indirect_only"
}

///|
pub fn encode_dcp_identify_request(
  source_mac : StringView,
  destination_mac? : StringView = "01:0E:CF:00:00:00",
  xid? : Int = 16909060,
) -> Bytes raise @frame.FrameError {
  let request = @dcp.IdentifyRequest::{
    destination: @frame.MacAddress::from_hex(destination_mac),
    source: @frame.MacAddress::from_hex(source_mac),
    xid,
  }
  @dcp.encode_identify_request(request)
}

///|
pub fn encode_dcp_identify_request_hex(
  source_mac : StringView,
  destination_mac? : StringView = "01:0E:CF:00:00:00",
  xid? : Int = 16909060,
) -> String raise @frame.FrameError {
  @frame.bytes_to_hex(
    encode_dcp_identify_request(source_mac, destination_mac~, xid~),
  )
}

///|
pub fn encode_dcp_get_request(
  source_mac : StringView,
  destination_mac : StringView,
  selectors? : StringView = "all",
  xid? : Int = 16909060,
) -> Bytes raise @frame.FrameError {
  @dcp.encode_get_request(@dcp.GetRequest::{
    destination: @frame.MacAddress::from_hex(destination_mac),
    source: @frame.MacAddress::from_hex(source_mac),
    xid,
    blocks: @dcp.parse_get_request_blocks(selectors),
  })
}

///|
pub fn encode_dcp_get_request_hex(
  source_mac : StringView,
  destination_mac : StringView,
  selectors? : StringView = "all",
  xid? : Int = 16909060,
) -> String raise @frame.FrameError {
  @frame.bytes_to_hex(
    encode_dcp_get_request(source_mac, destination_mac, selectors~, xid~),
  )
}

///|
pub fn encode_dcp_set_name_request(
  source_mac : StringView,
  destination_mac : StringView,
  station_name : String,
  xid? : Int = 16909060,
  is_persistent? : Bool = false,
) -> Bytes raise @frame.FrameError {
  @dcp.encode_set_name_request(
    @frame.MacAddress::from_hex(destination_mac),
    @frame.MacAddress::from_hex(source_mac),
    xid,
    station_name,
    is_persistent~,
  )
}

///|
pub fn encode_dcp_set_name_request_hex(
  source_mac : StringView,
  destination_mac : StringView,
  station_name : String,
  xid? : Int = 16909060,
  is_persistent? : Bool = false,
) -> String raise @frame.FrameError {
  @frame.bytes_to_hex(
    encode_dcp_set_name_request(
      source_mac,
      destination_mac,
      station_name,
      xid~,
      is_persistent~,
    ),
  )
}

///|
pub fn encode_dcp_set_ip_request(
  source_mac : StringView,
  destination_mac : StringView,
  address : StringView,
  mask : StringView,
  gateway : StringView,
  xid? : Int = 16909060,
  is_persistent? : Bool = false,
) -> Bytes raise @frame.FrameError {
  @dcp.encode_set_ip_request(
    @frame.MacAddress::from_hex(destination_mac),
    @frame.MacAddress::from_hex(source_mac),
    xid,
    @frame.IPv4Address::from_text(address),
    @frame.IPv4Address::from_text(mask),
    @frame.IPv4Address::from_text(gateway),
    is_persistent~,
  )
}

///|
pub fn encode_dcp_set_ip_request_hex(
  source_mac : StringView,
  destination_mac : StringView,
  address : StringView,
  mask : StringView,
  gateway : StringView,
  xid? : Int = 16909060,
  is_persistent? : Bool = false,
) -> String raise @frame.FrameError {
  @frame.bytes_to_hex(
    encode_dcp_set_ip_request(
      source_mac,
      destination_mac,
      address,
      mask,
      gateway,
      xid~,
      is_persistent~,
    ),
  )
}

///|
pub fn summarize_dcp_response_hex(packet_hex : StringView) -> String raise {
  format_device_summary(
    @dcp.summarize_response(
      @dcp.parse_response(@frame.bytes_from_hex(packet_hex)),
    ),
  )
}

///|
fn[T] fixture_merge_optional(left : T?, right : T?) -> T? {
  match right {
    Some(_) => right
    None => left
  }
}

///|
fn fixture_merge_device_summary(
  current : @dcp.DeviceSummary,
  incoming : @dcp.DeviceSummary,
) -> @dcp.DeviceSummary {
  let options = current.options.copy()
  for pair in incoming.options {
    if !options.any(existing => existing == pair) {
      options.push(pair)
    }
  }
  @dcp.DeviceSummary::{
    source: current.source,
    station_name: fixture_merge_optional(
      current.station_name,
      incoming.station_name,
    ),
    vendor_name: fixture_merge_optional(
      current.vendor_name,
      incoming.vendor_name,
    ),
    alias_name: fixture_merge_optional(current.alias_name, incoming.alias_name),
    vendor_id: fixture_merge_optional(current.vendor_id, incoming.vendor_id),
    device_id: fixture_merge_optional(current.device_id, incoming.device_id),
    device_instance: fixture_merge_optional(
      current.device_instance,
      incoming.device_instance,
    ),
    oem_vendor_id: fixture_merge_optional(
      current.oem_vendor_id,
      incoming.oem_vendor_id,
    ),
    oem_device_id: fixture_merge_optional(
      current.oem_device_id,
      incoming.oem_device_id,
    ),
    ip_address: fixture_merge_optional(current.ip_address, incoming.ip_address),
    subnet_mask: fixture_merge_optional(
      current.subnet_mask,
      incoming.subnet_mask,
    ),
    gateway: fixture_merge_optional(current.gateway, incoming.gateway),
    is_device: current.is_device || incoming.is_device,
    is_controller: current.is_controller || incoming.is_controller,
    is_multidevice: current.is_multidevice || incoming.is_multidevice,
    is_supervisor: current.is_supervisor || incoming.is_supervisor,
    options,
    device_initiative: fixture_merge_optional(
      current.device_initiative,
      incoming.device_initiative,
    ),
    control_response: fixture_merge_optional(
      current.control_response,
      incoming.control_response,
    ),
  }
}

///|
fn fixture_upsert_device_summary(
  summaries : Array[@dcp.DeviceSummary],
  summary : @dcp.DeviceSummary,
) -> Unit {
  let existing_index = summaries.search_by(item => item.source == summary.source)
  match existing_index {
    Some(index) =>
      summaries[index] = fixture_merge_device_summary(summaries[index], summary)
    None => summaries.push(summary)
  }
}

///|
pub fn summarize_dcp_response_hexes(
  packet_hexes : Array[String],
) -> String raise {
  let summaries : Array[@dcp.DeviceSummary] = []
  for packet_hex in packet_hexes {
    fixture_upsert_device_summary(
      summaries,
      @dcp.summarize_response(
        @dcp.parse_response(@frame.bytes_from_hex(packet_hex[:])),
      ),
    )
  }
  if summaries.is_empty() {
    "No devices discovered."
  } else {
    summaries.map(summary => format_device_summary(summary)).join("\n\n")
  }
}

///|
pub fn format_dcp_response_overview(response : @dcp.DcpResponse) -> String {
  let lines : Array[String] = []
  let summary = @dcp.summarize_response(response)
  let nonzero_blocks = response.blocks.filter(block => {
    @dcp.response_block_info(block) != 0
  })
  lines.push("frame_id=" + response.frame_id.to_string())
  lines.push("service_id=" + response.service_id.to_int().to_string())
  lines.push("service_type=" + response.service_type.to_int().to_string())
  lines.push(
    "service_type_label=" +
    @dcp.response_service_type_label(response.service_type),
  )
  lines.push("xid=" + response.xid.to_string())
  lines.push("source=" + response.source.to_hex())
  lines.push("block_count=" + response.blocks.length().to_string())
  lines.push(
    "blocks=" +
    response.blocks.map(block => @dcp.response_block_name(block)).join(","),
  )
  lines.push("nonzero_block_count=" + nonzero_blocks.length().to_string())
  if nonzero_blocks.length() > 0 {
    lines.push(
      "nonzero_blocks=" +
      nonzero_blocks
      .map(block => {
        @dcp.response_block_name(block) +
        ":" +
        @dcp.response_block_info(block).to_string() +
        ":" +
        @dcp.response_block_info_label(@dcp.response_block_info(block))
      })
      .join(","),
    )
  }
  match summary.station_name {
    Some(name) => lines.push("station_name=" + name)
    None => ()
  }
  match summary.vendor_name {
    Some(name) => lines.push("vendor_name=" + name)
    None => ()
  }
  match summary.alias_name {
    Some(name) => lines.push("alias_name=" + name)
    None => ()
  }
  match summary.vendor_id {
    Some(value) => lines.push("vendor_id=" + value.to_string())
    None => ()
  }
  match summary.device_id {
    Some(value) => lines.push("device_id=" + value.to_string())
    None => ()
  }
  match summary.device_instance {
    Some(value) => lines.push("device_instance=" + value.to_string())
    None => ()
  }
  match summary.oem_vendor_id {
    Some(value) => lines.push("oem_vendor_id=" + value.to_string())
    None => ()
  }
  match summary.oem_device_id {
    Some(value) => lines.push("oem_device_id=" + value.to_string())
    None => ()
  }
  match summary.device_initiative {
    Some(value) => lines.push("device_initiative=" + value.to_string())
    None => ()
  }
  match summary.control_response {
    Some(data) => {
      lines.push(
        "control_failed_option=" + data.failed_option.to_int().to_string(),
      )
      lines.push(
        "control_failed_suboption=" + data.failed_suboption.to_int().to_string(),
      )
      lines.push("control_block_error=" + data.block_error.to_int().to_string())
      lines.push(
        "control_block_error_label=" +
        @dcp.control_response_error_label(data.block_error),
      )
    }
    None => ()
  }
  if summary.options.length() > 0 {
    lines.push(
      "device_options=" +
      summary.options
      .map(pair => {
        pair.option.to_int().to_string() +
        ":" +
        pair.suboption.to_int().to_string()
      })
      .join(","),
    )
  }
  lines.push("is_device=" + summary.is_device.to_string())
  lines.push("is_controller=" + summary.is_controller.to_string())
  lines.push("is_multidevice=" + summary.is_multidevice.to_string())
  lines.push("is_supervisor=" + summary.is_supervisor.to_string())
  lines.join("\n")
}

///|
pub fn describe_dcp_response_hex(packet_hex : StringView) -> String raise {
  format_dcp_response_overview(
    @dcp.parse_response(@frame.bytes_from_hex(packet_hex)),
  )
}

///|
pub fn format_device_summary(summary : @dcp.DeviceSummary) -> String {
  let lines : Array[String] = []
  let vendor_id = match summary.vendor_id {
    Some(id) => id.to_string()
    None => ""
  }
  let device_id = match summary.device_id {
    Some(id) => id.to_string()
    None => ""
  }
  let device_instance = match summary.device_instance {
    Some(value) => value.to_string()
    None => ""
  }
  let oem_vendor_id = match summary.oem_vendor_id {
    Some(value) => value.to_string()
    None => ""
  }
  let oem_device_id = match summary.oem_device_id {
    Some(value) => value.to_string()
    None => ""
  }
  let ip_address = match summary.ip_address {
    Some(ip) => ip.to_text()
    None => ""
  }
  let subnet_mask = match summary.subnet_mask {
    Some(ip) => ip.to_text()
    None => ""
  }
  let gateway = match summary.gateway {
    Some(ip) => ip.to_text()
    None => ""
  }
  let device_initiative = match summary.device_initiative {
    Some(value) => value.to_string()
    None => ""
  }
  let control_block_error_label = match summary.control_response {
    Some(data) => @dcp.control_response_error_label(data.block_error)
    None => ""
  }
  lines.push("source=" + summary.source.to_hex())
  lines.push("station_name=" + summary.station_name.unwrap_or(""))
  lines.push("vendor_name=" + summary.vendor_name.unwrap_or(""))
  lines.push("alias_name=" + summary.alias_name.unwrap_or(""))
  lines.push("vendor_id=" + vendor_id)
  lines.push("device_id=" + device_id)
  lines.push("device_instance=" + device_instance)
  lines.push("oem_vendor_id=" + oem_vendor_id)
  lines.push("oem_device_id=" + oem_device_id)
  lines.push("ip_address=" + ip_address)
  lines.push("subnet_mask=" + subnet_mask)
  lines.push("gateway=" + gateway)
  lines.push("is_device=" + summary.is_device.to_string())
  lines.push("is_controller=" + summary.is_controller.to_string())
  lines.push("is_multidevice=" + summary.is_multidevice.to_string())
  lines.push("is_supervisor=" + summary.is_supervisor.to_string())
  lines.push(
    "device_options=" +
    summary.options
    .map(pair => {
      pair.option.to_int().to_string() +
      ":" +
      pair.suboption.to_int().to_string()
    })
    .join(","),
  )
  lines.push("device_initiative=" + device_initiative)
  lines.push("control_block_error_label=" + control_block_error_label)
  lines.join("\n")
}

///|
fn format_gsd_summary(summary : @gsd.GsdSummary) -> String {
  [
    "vendor_id=" + summary.vendor_id,
    "device_id=" + summary.device_id,
    "vendor_name=" + summary.vendor_name,
    "main_family=" + summary.main_family,
    "product_family=" + summary.product_family,
    "order_number=" + summary.order_number,
    "device_access_point_id=" + summary.device_access_point_id,
    "dns_compatible_name=" + summary.dns_compatible_name,
  ].join("\n")
}

///|
fn normalize_fixture_bool_text(text : String) -> String {
  let trimmed = text.trim().to_owned()
  if trimmed == "true" ||
    trimmed == "TRUE" ||
    trimmed == "Enabled" ||
    trimmed == "enabled" ||
    trimmed == "yes" ||
    trimmed == "YES" {
    "true"
  } else if trimmed == "false" ||
    trimmed == "FALSE" ||
    trimmed == "Disabled" ||
    trimmed == "disabled" ||
    trimmed == "no" ||
    trimmed == "NO" {
    "false"
  } else {
    trimmed
  }
}

///|
fn normalize_mrp_role_text(text : String) -> String {
  let trimmed = text.trim().to_owned()
  if trimmed == "disabled" ||
    trimmed == "Disabled" ||
    trimmed == "Media Redundancy disabled" ||
    trimmed == "mrp_disabled" {
    "disabled"
  } else if trimmed == "client" ||
    trimmed == "Client" ||
    trimmed == "Media Redundancy Client" ||
    trimmed == "mrp_client" {
    "client"
  } else if trimmed == "manager" ||
    trimmed == "Manager" ||
    trimmed == "Media Redundancy Manager" ||
    trimmed == "mrp_manager" {
    "manager"
  } else if trimmed == "auto_manager" ||
    trimmed == "manager_auto" ||
    trimmed == "Media Redundancy Manager (Auto manager negotiation)" {
    "auto_manager"
  } else if trimmed == "" {
    "unknown"
  } else {
    trimmed
  }
}

///|
fn normalize_mrp_ring_state_text(text : String) -> String {
  let trimmed = text.trim().to_owned()
  if trimmed == "closed" ||
    trimmed == "Closed" ||
    trimmed == "ring_closed" ||
    trimmed == "Ring Closed" {
    "ring_closed"
  } else if trimmed == "open" ||
    trimmed == "Open" ||
    trimmed == "ring_open" ||
    trimmed == "Ring Open" {
    "ring_open"
  } else if trimmed == "" {
    "unknown"
  } else {
    trimmed
  }
}

///|
fn fixture_number_is_zero_like(text : String) -> Bool {
  let trimmed = text.trim().to_owned()
  trimmed == "0" ||
  trimmed == "00" ||
  trimmed == "0x0" ||
  trimmed == "0x00" ||
  trimmed == "0x0000"
}

///|
fn normalize_mrpic_role_text(text : String) -> String {
  let trimmed = text.trim().to_owned()
  if trimmed == "0" ||
    trimmed == "0x00" ||
    trimmed == "unassigned" ||
    trimmed == "none" ||
    trimmed == "No role assigned" {
    "unassigned"
  } else if trimmed == "1" ||
    trimmed == "0x01" ||
    trimmed == "MIC" ||
    trimmed == "mic" ||
    trimmed == "MRP Interconnection Client (MIC)" {
    "mic"
  } else if trimmed == "2" ||
    trimmed == "0x02" ||
    trimmed == "MIM" ||
    trimmed == "mim" ||
    trimmed == "MRP Interconnection Manager (MIM)" {
    "mim"
  } else if trimmed == "" {
    "unknown"
  } else {
    trimmed
  }
}

///|
fn normalize_mrpic_state_text(text : String) -> String {
  let trimmed = text.trim().to_owned()
  if trimmed == "0" ||
    trimmed == "0x00" ||
    trimmed == "open" ||
    trimmed == "Open" ||
    trimmed == "MRP Interconnection open" ||
    trimmed == "interconnection_open" {
    "interconnection_open"
  } else if trimmed == "1" ||
    trimmed == "0x01" ||
    trimmed == "closed" ||
    trimmed == "Closed" ||
    trimmed == "MRP Interconnection closed" ||
    trimmed == "interconnection_closed" {
    "interconnection_closed"
  } else if trimmed == "" {
    "unknown"
  } else {
    trimmed
  }
}

///|
fn fixture_lines(text : String) -> Array[String] {
  text.split("\n").to_array().map(raw => raw.trim().to_owned())
}

///|
pub fn trace_link_state_autonegotiation(trace_text : String) -> String {
  let mut local_port_id = ""
  let mut autonegotiation_state = "unknown"
  let mut link_state = "unknown"
  let mut negotiated_mau_type = ""
  let mut speed_mbps = "0"
  let mut duplex_mode = "unknown"
  let mut observed_autonegotiation_ms = "0"
  let mut capture_source = ""
  let mut restart_detected = "false"
  let mut stable_after_link_up = "false"
  for line in fixture_lines(trace_text) {
    if line == "" || line[:].has_prefix("#") {
      continue
    }
    let parts = line.split("=").to_array()
    if parts.length() < 2 {
      continue
    }
    let key = parts[0].trim().to_owned()
    let value = parts[1].trim().to_owned()
    match key {
      "local_port_id" => local_port_id = value
      "autonegotiation_state" => autonegotiation_state = value
      "link_state" => link_state = value
      "negotiated_mau_type" => negotiated_mau_type = value
      "speed_mbps" => speed_mbps = value
      "duplex_mode" => duplex_mode = value
      "observed_autonegotiation_ms" => observed_autonegotiation_ms = value
      "capture_source" => capture_source = value
      "restart_detected" =>
        restart_detected = normalize_fixture_bool_text(value)
      "stable_after_link_up" =>
        stable_after_link_up = normalize_fixture_bool_text(value)
      _ => ()
    }
  }
  let observed_value = @string.parse_int(observed_autonegotiation_ms[:]) catch {
    _ => 0
  }
  let speed_value = @string.parse_int(speed_mbps[:]) catch { _ => 0 }
  let recommended_timeout_ms = recommended_autonegotiation_timeout_ms()
  let mandatory_timeout_ms = mandatory_autonegotiation_timeout_ms()
  let link_ready = (link_state == "up" || link_state == "UP") &&
    speed_value >= minimum_operational_link_speed_mbps() &&
    (duplex_mode == required_operational_duplex_mode() || duplex_mode == "FULL")
  let physical_contract = if link_ready {
    "meets_minimum"
  } else {
    "below_minimum"
  }
  let compliance = if stable_after_link_up != "true" {
    "not_stable"
  } else if observed_value <= recommended_timeout_ms {
    "recommended"
  } else if observed_value <= mandatory_timeout_ms {
    "mandatory_only"
  } else {
    "out_of_spec"
  }
  [
    "trace_method=link_state_trace",
    "local_port_id=" + local_port_id,
    "autonegotiation_state=" + autonegotiation_state,
    "link_state=" + link_state,
    "negotiated_mau_type=" + negotiated_mau_type,
    "speed_mbps=" + speed_mbps,
    "duplex_mode=" + duplex_mode,
    "observed_autonegotiation_ms=" + observed_autonegotiation_ms,
    "capture_source=" + capture_source,
    "restart_detected=" + restart_detected,
    "stable_after_link_up=" + stable_after_link_up,
    "recommended_timeout_ms=" + recommended_timeout_ms.to_string(),
    "mandatory_timeout_ms=" + mandatory_timeout_ms.to_string(),
    "minimum_speed_mbps=" + minimum_operational_link_speed_mbps().to_string(),
    "required_duplex_mode=" + required_operational_duplex_mode(),
    "fault_requires_link_restart=" +
    autonegotiation_fault_requires_link_restart().to_string(),
    "link_ready=" + link_ready.to_string(),
    "physical_contract=" + physical_contract,
    "compliance=" + compliance,
  ].join("\n")
}

///|
pub fn trace_link_state_port_diagnosis(trace_text : String) -> String {
  let mut local_port_id = ""
  let mut expected_mau_type = ""
  let mut observed_mau_type = ""
  let mut expected_link_state = "up"
  let mut observed_link_state = "unknown"
  let mut expected_line_delay_ns = ""
  let mut observed_line_delay_ns = ""
  let mut speed_mbps = "0"
  let mut duplex_mode = "unknown"
  for line in fixture_lines(trace_text) {
    if line == "" || line[:].has_prefix("#") {
      continue
    }
    let parts = line.split("=").to_array()
    if parts.length() < 2 {
      continue
    }
    let key = parts[0].trim().to_owned()
    let value = parts[1].trim().to_owned()
    match key {
      "local_port_id" => local_port_id = value
      "expected_mau_type" => expected_mau_type = value
      "observed_mau_type" => observed_mau_type = value
      "expected_link_state" => expected_link_state = value
      "observed_link_state" => observed_link_state = value
      "expected_line_delay_ns" => expected_line_delay_ns = value
      "observed_line_delay_ns" => observed_line_delay_ns = value
      "speed_mbps" => speed_mbps = value
      "duplex_mode" => duplex_mode = value
      _ => ()
    }
  }
  let speed_value = @string.parse_int(speed_mbps[:]) catch { _ => 0 }
  let expected_delay = @string.parse_int(expected_line_delay_ns[:]) catch {
    _ => 0
  }
  let observed_delay = @string.parse_int(observed_line_delay_ns[:]) catch {
    _ => 0
  }
  let observed_link_up = observed_link_state == "up" ||
    observed_link_state == "UP"
  let expected_link_up = expected_link_state == "up" ||
    expected_link_state == "UP"
  let link_mismatch = expected_link_up && !observed_link_up
  let mau_mismatch = expected_mau_type != "" &&
    observed_mau_type != "" &&
    expected_mau_type != observed_mau_type
  let line_delay_mismatch = expected_delay > 0 &&
    observed_delay > expected_delay
  let physical_ready = observed_link_up &&
    speed_value >= minimum_operational_link_speed_mbps() &&
    (duplex_mode == required_operational_duplex_mode() || duplex_mode == "FULL")
  let diagnosis_code = if link_mismatch {
    diagnosis_link_state_mismatch_code()
  } else if mau_mismatch || !physical_ready {
    diagnosis_mau_type_mismatch_code()
  } else if line_delay_mismatch {
    diagnosis_line_delay_mismatch_code()
  } else {
    "none"
  }
  let diagnosis_label = match diagnosis_code {
    "0x8000" => "link_state_mismatch"
    "0x8001" => "mau_type_mismatch"
    "0x8002" => "line_delay_mismatch"
    _ => "no_fault"
  }
  [
    "trace_method=link_state_trace",
    "local_port_id=" + local_port_id,
    "expected_mau_type=" + expected_mau_type,
    "observed_mau_type=" + observed_mau_type,
    "expected_link_state=" + expected_link_state,
    "observed_link_state=" + observed_link_state,
    "expected_line_delay_ns=" + expected_line_delay_ns,
    "observed_line_delay_ns=" + observed_line_delay_ns,
    "speed_mbps=" + speed_mbps,
    "duplex_mode=" + duplex_mode,
    "minimum_speed_mbps=" + minimum_operational_link_speed_mbps().to_string(),
    "required_duplex_mode=" + required_operational_duplex_mode(),
    "link_state_mismatch_code=" + diagnosis_link_state_mismatch_code(),
    "mau_type_mismatch_code=" + diagnosis_mau_type_mismatch_code(),
    "line_delay_mismatch_code=" + diagnosis_line_delay_mismatch_code(),
    "physical_ready=" + physical_ready.to_string(),
    "diagnosis_code=" + diagnosis_code,
    "diagnosis_label=" + diagnosis_label,
  ].join("\n")
}

///|
pub fn read_pd_port_data_real(record_text : String) -> String {
  let mut local_port_id = ""
  let mut port_state = "unknown"
  let mut boundary_state = "unknown"
  let mut link_state = "unknown"
  let mut mau_type = ""
  let mut speed_mbps = "0"
  let mut duplex_mode = "unknown"
  let mut line_delay_ns = "0"
  let mut peer_count = "0"
  let mut check_peers = "false"
  let mut check_line_delay = "false"
  let mut check_mau_type = "false"
  let mut check_link_state = "false"
  let mut check_sync_difference = "false"
  let mut check_mau_type_difference = "false"
  for line in fixture_lines(record_text) {
    if line == "" || line[:].has_prefix("#") {
      continue
    }
    let parts = line.split("=").to_array()
    if parts.length() < 2 {
      continue
    }
    let key = parts[0].trim().to_owned()
    let value = parts[1].trim().to_owned()
    match key {
      "local_port_id" => local_port_id = value
      "port_state" => port_state = value
      "boundary_state" => boundary_state = value
      "link_state" => link_state = value
      "mau_type" => mau_type = value
      "speed_mbps" => speed_mbps = value
      "duplex_mode" => duplex_mode = value
      "line_delay_ns" => line_delay_ns = value
      "peer_count" => peer_count = value
      "check_peers" => check_peers = normalize_fixture_bool_text(value)
      "check_line_delay" =>
        check_line_delay = normalize_fixture_bool_text(value)
      "check_mau_type" => check_mau_type = normalize_fixture_bool_text(value)
      "check_link_state" =>
        check_link_state = normalize_fixture_bool_text(value)
      "check_sync_difference" =>
        check_sync_difference = normalize_fixture_bool_text(value)
      "check_mau_type_difference" =>
        check_mau_type_difference = normalize_fixture_bool_text(value)
      _ => ()
    }
  }
  let speed_value = @string.parse_int(speed_mbps[:]) catch { _ => 0 }
  let peer_value = @string.parse_int(peer_count[:]) catch { _ => 0 }
  let link_up = link_state == "up" || link_state == "UP"
  let physical_ready = link_up &&
    speed_value >= minimum_operational_link_speed_mbps() &&
    (duplex_mode == required_operational_duplex_mode() || duplex_mode == "FULL")
  let active_check_blocks : Array[String] = []
  if check_peers == "true" {
    active_check_blocks.push("CheckPeers")
  }
  if check_line_delay == "true" {
    active_check_blocks.push("CheckLineDelay")
  }
  if check_mau_type == "true" {
    active_check_blocks.push("CheckMAUType")
  }
  if check_link_state == "true" {
    active_check_blocks.push("CheckLinkState")
  }
  if check_sync_difference == "true" {
    active_check_blocks.push("CheckSyncDifference")
  }
  if check_mau_type_difference == "true" {
    active_check_blocks.push("CheckMAUTypeDifference")
  }
  let topology_status = if peer_value > 0 {
    "peer_present"
  } else {
    "peer_missing"
  }
  [
    "record_method=record_read_pdportdatareal",
    "local_port_id=" + local_port_id,
    "record_index_real_extended=" + pd_port_data_real_extended_record_index(),
    "record_index_real=" + pd_port_data_real_record_index(),
    "record_index_check=" + pd_port_data_check_record_index(),
    "supported_check_blocks=" + pd_port_data_check_supported_blocks(),
    "port_state=" + port_state,
    "boundary_state=" + boundary_state,
    "link_state=" + link_state,
    "mau_type=" + mau_type,
    "speed_mbps=" + speed_mbps,
    "duplex_mode=" + duplex_mode,
    "line_delay_ns=" + line_delay_ns,
    "peer_count=" + peer_count,
    "minimum_speed_mbps=" + minimum_operational_link_speed_mbps().to_string(),
    "required_duplex_mode=" + required_operational_duplex_mode(),
    "physical_ready=" + physical_ready.to_string(),
    "topology_status=" + topology_status,
    "check_peers=" + check_peers,
    "check_line_delay=" + check_line_delay,
    "check_mau_type=" + check_mau_type,
    "check_link_state=" + check_link_state,
    "check_sync_difference=" + check_sync_difference,
    "check_mau_type_difference=" + check_mau_type_difference,
    "active_check_blocks=" + active_check_blocks.join(","),
  ].join("\n")
}

///|
pub fn read_pd_port_statistic(record_text : String) -> String {
  let mut slot_number = ""
  let mut subslot_number = ""
  let mut local_port_id = ""
  let mut counter_status = "0"
  let mut if_in_octets = "0"
  let mut if_out_octets = "0"
  let mut if_in_discards = "0"
  let mut if_out_discards = "0"
  let mut if_in_errors = "0"
  let mut if_out_errors = "0"
  for line in fixture_lines(record_text) {
    if line == "" || line[:].has_prefix("#") {
      continue
    }
    let parts = line.split("=").to_array()
    if parts.length() < 2 {
      continue
    }
    let key = parts[0].trim().to_owned()
    let value = parts[1].trim().to_owned()
    match key {
      "slot_number" => slot_number = value
      "subslot_number" => subslot_number = value
      "local_port_id" => local_port_id = value
      "counter_status" => counter_status = value
      "if_in_octets" => if_in_octets = value
      "if_out_octets" => if_out_octets = value
      "if_in_discards" => if_in_discards = value
      "if_out_discards" => if_out_discards = value
      "if_in_errors" => if_in_errors = value
      "if_out_errors" => if_out_errors = value
      _ => ()
    }
  }
  let counter_status_value = @string.parse_int(counter_status[:]) catch {
    _ => 0
  }
  let invalid_counters : Array[String] = []
  if counter_status_value.land(1) != 0 {
    invalid_counters.push("ifInOctets")
  }
  if counter_status_value.land(2) != 0 {
    invalid_counters.push("ifOutOctets")
  }
  if counter_status_value.land(4) != 0 {
    invalid_counters.push("ifInDiscards")
  }
  if counter_status_value.land(8) != 0 {
    invalid_counters.push("ifOutDiscards")
  }
  if counter_status_value.land(16) != 0 {
    invalid_counters.push("ifInErrors")
  }
  if counter_status_value.land(32) != 0 {
    invalid_counters.push("ifOutErrors")
  }
  let traffic_state = if if_in_octets != "0" || if_out_octets != "0" {
    "active"
  } else {
    "idle"
  }
  [
    "record_method=record_read_pdportstatistic",
    "slot_number=" + slot_number,
    "subslot_number=" + subslot_number,
    "local_port_id=" + local_port_id,
    "record_index=" + pd_port_statistic_record_index(),
    "counter_status=" + counter_status,
    "if_in_octets=" + if_in_octets,
    "if_out_octets=" + if_out_octets,
    "if_in_discards=" + if_in_discards,
    "if_out_discards=" + if_out_discards,
    "if_in_errors=" + if_in_errors,
    "if_out_errors=" + if_out_errors,
    "invalid_counter_count=" + invalid_counters.length().to_string(),
    "invalid_counters=" + invalid_counters.join(","),
    "traffic_state=" + traffic_state,
  ].join("\n")
}

///|
pub fn read_pd_port_mrp_data_real(record_text : String) -> String {
  let mut slot_number = ""
  let mut subslot_number = ""
  let mut local_port_id = ""
  let mut mrp_instance = ""
  let mut mrp_domain_uuid = ""
  for line in fixture_lines(record_text) {
    if line == "" || line[:].has_prefix("#") {
      continue
    }
    let parts = line.split("=").to_array()
    if parts.length() < 2 {
      continue
    }
    let key = parts[0].trim().to_owned()
    let value = parts[1].trim().to_owned()
    match key {
      "slot_number" => slot_number = value
      "subslot_number" => subslot_number = value
      "local_port_id" => local_port_id = value
      "mrp_instance" => mrp_instance = value
      "mrp_domain_uuid" => mrp_domain_uuid = value
      _ => ()
    }
  }
  let domain_uuid_present = mrp_domain_uuid != ""
  let instance_scope = if mrp_instance == "" {
    "default"
  } else {
    "instance_specific"
  }
  let domain_assignment = if domain_uuid_present { "bound" } else { "unbound" }
  let mrp_digest_state = if domain_uuid_present && mrp_instance != "" {
    "instance_bound"
  } else if domain_uuid_present {
    "bound"
  } else if mrp_instance != "" {
    "instance_unbound"
  } else {
    "unbound"
  }
  [
    "record_method=record_read_pdportmrpdatareal",
    "slot_number=" + slot_number,
    "subslot_number=" + subslot_number,
    "local_port_id=" + local_port_id,
    "mrp_instance=" + mrp_instance,
    "record_index=" + pd_port_mrp_data_real_record_index(),
    "mrp_domain_uuid=" + mrp_domain_uuid,
    "domain_uuid_present=" + domain_uuid_present.to_string(),
    "instance_scope=" + instance_scope,
    "domain_assignment=" + domain_assignment,
    "mrp_digest_state=" + mrp_digest_state,
  ].join("\n")
}

///|
pub fn read_pd_port_mrplc_data_real(record_text : String) -> String {
  let mut slot_number = ""
  let mut subslot_number = ""
  let mut local_port_id = ""
  let mut mrpic_domain_id = ""
  let mut mrpic_role = ""
  let mut mrp_version = ""
  let mut mrpic_domain_name = ""
  let mut mrpic_topchg_t = ""
  let mut mrpic_topnr_max = ""
  let mut mrpic_link_status_change_t = ""
  let mut mrpic_link_status_nrmax = ""
  let mut mrpic_lnkdown_t = ""
  let mut mrpic_lnkup_t = ""
  let mut mrpic_lnknr_max = ""
  let mut mrpic_start_delay = ""
  let mut mrpic_mic_position = ""
  let mut mrpic_state = ""
  for line in fixture_lines(record_text) {
    if line == "" || line[:].has_prefix("#") {
      continue
    }
    let parts = line.split("=").to_array()
    if parts.length() < 2 {
      continue
    }
    let key = parts[0].trim().to_owned()
    let value = parts[1].trim().to_owned()
    match key {
      "slot_number" => slot_number = value
      "subslot_number" => subslot_number = value
      "local_port_id" => local_port_id = value
      "mrpic_domain_id" => mrpic_domain_id = value
      "mrpic_role" => mrpic_role = value
      "mrp_version" => mrp_version = value
      "mrpic_domain_name" => mrpic_domain_name = value
      "mrpic_topchg_t" => mrpic_topchg_t = value
      "mrpic_topnr_max" => mrpic_topnr_max = value
      "mrpic_link_status_change_t" => mrpic_link_status_change_t = value
      "mrpic_link_status_nrmax" => mrpic_link_status_nrmax = value
      "mrpic_lnkdown_t" => mrpic_lnkdown_t = value
      "mrpic_lnkup_t" => mrpic_lnkup_t = value
      "mrpic_lnknr_max" => mrpic_lnknr_max = value
      "mrpic_start_delay" => mrpic_start_delay = value
      "mrpic_mic_position" => mrpic_mic_position = value
      "mrpic_state" => mrpic_state = value
      _ => ()
    }
  }
  let normalized_role = normalize_mrpic_role_text(mrpic_role)
  let normalized_state = normalize_mrpic_state_text(mrpic_state)
  let domain_defined = mrpic_domain_id != "" &&
    !fixture_number_is_zero_like(mrpic_domain_id)
  let mim_params_present = mrpic_topchg_t != "" ||
    mrpic_topnr_max != "" ||
    mrpic_link_status_change_t != "" ||
    mrpic_link_status_nrmax != "" ||
    (mrpic_start_delay != "" && normalized_role == "mim")
  let mic_params_present = mrpic_lnkdown_t != "" ||
    mrpic_lnkup_t != "" ||
    mrpic_lnknr_max != "" ||
    mrpic_mic_position != "" ||
    (mrpic_start_delay != "" && normalized_role == "mic")
  let state_present = mrpic_state != ""
  let parameter_set = if mim_params_present && mic_params_present {
    "mim_and_mic"
  } else if mim_params_present {
    "mim"
  } else if mic_params_present {
    "mic"
  } else {
    "none"
  }
  let mrpic_health = if normalized_state == "interconnection_closed" {
    "interconnection_closed"
  } else if normalized_state == "interconnection_open" {
    "interconnection_open"
  } else if !state_present {
    "state_unreported"
  } else {
    "state_other"
  }
  let mrpic_readiness = if normalized_role == "unassigned" {
    "unassigned"
  } else if mrpic_health == "interconnection_closed" {
    "redundant"
  } else if mrpic_health == "interconnection_open" {
    "degraded"
  } else if parameter_set != "none" {
    "configured"
  } else {
    "unknown"
  }
  let mrpic_digest_state = if normalized_role == "unassigned" {
    "unassigned"
  } else if mrpic_health == "interconnection_closed" ||
    mrpic_health == "interconnection_open" {
    normalized_role + "_" + mrpic_health
  } else if parameter_set != "none" {
    normalized_role + "_configured"
  } else {
    normalized_role + "_unknown"
  }
  let mrpic_domain_assignment = if domain_defined {
    "defined"
  } else {
    "undefined"
  }
  [
    "record_method=record_read_pdportmrplcdatareal",
    "slot_number=" + slot_number,
    "subslot_number=" + subslot_number,
    "local_port_id=" + local_port_id,
    "record_index=" + pd_port_mrplc_data_real_record_index(),
    "mrpic_domain_id=" + mrpic_domain_id,
    "mrpic_domain_defined=" + domain_defined.to_string(),
    "mrpic_role=" + mrpic_role,
    "mrpic_role_normalized=" + normalized_role,
    "mrp_version=" + mrp_version,
    "mrpic_domain_name=" + mrpic_domain_name,
    "mrpic_topchg_t=" + mrpic_topchg_t,
    "mrpic_topnr_max=" + mrpic_topnr_max,
    "mrpic_link_status_change_t=" + mrpic_link_status_change_t,
    "mrpic_link_status_nrmax=" + mrpic_link_status_nrmax,
    "mrpic_lnkdown_t=" + mrpic_lnkdown_t,
    "mrpic_lnkup_t=" + mrpic_lnkup_t,
    "mrpic_lnknr_max=" + mrpic_lnknr_max,
    "mrpic_start_delay=" + mrpic_start_delay,
    "mrpic_mic_position=" + mrpic_mic_position,
    "mrpic_state=" + mrpic_state,
    "mim_params_present=" + mim_params_present.to_string(),
    "mic_params_present=" + mic_params_present.to_string(),
    "state_present=" + state_present.to_string(),
    "parameter_set=" + parameter_set,
    "mrpic_domain_assignment=" + mrpic_domain_assignment,
    "mrpic_health=" + mrpic_health,
    "mrpic_readiness=" + mrpic_readiness,
    "mrpic_digest_state=" + mrpic_digest_state,
  ].join("\n")
}

///|
pub fn read_pd_interface_mrp_data_real(record_text : String) -> String {
  let mut slot_number = ""
  let mut subslot_number = ""
  let mut mrp_instance = ""
  let mut mrp_domain_uuid = ""
  let mut mrp_role = ""
  let mut mrp_version = ""
  let mut mrp_domain_name = ""
  let mut mrp_manager_prio = ""
  let mut mrp_topchg_t = ""
  let mut mrp_topnr_max = ""
  let mut mrp_tstshort_t = ""
  let mut mrp_tstdefault_t = ""
  let mut mrp_tstnr_max = ""
  let mut mrp_lnkdown_t = ""
  let mut mrp_lnkup_t = ""
  let mut mrp_lnknr_max = ""
  let mut mrp_ring_state = ""
  for line in fixture_lines(record_text) {
    if line == "" || line[:].has_prefix("#") {
      continue
    }
    let parts = line.split("=").to_array()
    if parts.length() < 2 {
      continue
    }
    let key = parts[0].trim().to_owned()
    let value = parts[1].trim().to_owned()
    match key {
      "slot_number" => slot_number = value
      "subslot_number" => subslot_number = value
      "mrp_instance" => mrp_instance = value
      "mrp_domain_uuid" => mrp_domain_uuid = value
      "mrp_role" => mrp_role = value
      "mrp_version" => mrp_version = value
      "mrp_domain_name" => mrp_domain_name = value
      "mrp_manager_prio" => mrp_manager_prio = value
      "mrp_topchg_t" => mrp_topchg_t = value
      "mrp_topnr_max" => mrp_topnr_max = value
      "mrp_tstshort_t" => mrp_tstshort_t = value
      "mrp_tstdefault_t" => mrp_tstdefault_t = value
      "mrp_tstnr_max" => mrp_tstnr_max = value
      "mrp_lnkdown_t" => mrp_lnkdown_t = value
      "mrp_lnkup_t" => mrp_lnkup_t = value
      "mrp_lnknr_max" => mrp_lnknr_max = value
      "mrp_ring_state" => mrp_ring_state = value
      _ => ()
    }
  }
  let normalized_role = normalize_mrp_role_text(mrp_role)
  let normalized_ring_state = normalize_mrp_ring_state_text(mrp_ring_state)
  let manager_params_present = mrp_manager_prio != "" ||
    mrp_topchg_t != "" ||
    mrp_topnr_max != "" ||
    mrp_tstshort_t != "" ||
    mrp_tstdefault_t != "" ||
    mrp_tstnr_max != ""
  let client_params_present = mrp_lnkdown_t != "" ||
    mrp_lnkup_t != "" ||
    mrp_lnknr_max != ""
  let ring_state_present = mrp_ring_state != ""
  let parameter_set = if manager_params_present && client_params_present {
    "manager_and_client"
  } else if manager_params_present {
    "manager"
  } else if client_params_present {
    "client"
  } else {
    "none"
  }
  let ring_health = if normalized_ring_state == "ring_closed" {
    "ring_closed"
  } else if normalized_ring_state == "ring_open" {
    "ring_open"
  } else if !ring_state_present {
    "ring_state_unreported"
  } else {
    "ring_state_other"
  }
  let mrp_readiness = if normalized_role == "disabled" {
    "disabled"
  } else if ring_health == "ring_closed" {
    "redundant"
  } else if ring_health == "ring_open" {
    "degraded"
  } else if parameter_set != "none" {
    "configured"
  } else {
    "unknown"
  }
  let mrp_digest_state = if normalized_role == "disabled" {
    "disabled"
  } else if ring_health == "ring_closed" || ring_health == "ring_open" {
    normalized_role + "_" + ring_health
  } else if parameter_set != "none" {
    normalized_role + "_configured"
  } else {
    normalized_role + "_unknown"
  }
  [
    "record_method=record_read_pdinterfacemrpdatareal",
    "slot_number=" + slot_number,
    "subslot_number=" + subslot_number,
    "mrp_instance=" + mrp_instance,
    "record_index=" + pd_interface_mrp_data_real_record_index(),
    "mrp_domain_uuid=" + mrp_domain_uuid,
    "mrp_role=" + mrp_role,
    "mrp_role_normalized=" + normalized_role,
    "mrp_version=" + mrp_version,
    "mrp_domain_name=" + mrp_domain_name,
    "mrp_manager_prio=" + mrp_manager_prio,
    "mrp_topchg_t=" + mrp_topchg_t,
    "mrp_topnr_max=" + mrp_topnr_max,
    "mrp_tstshort_t=" + mrp_tstshort_t,
    "mrp_tstdefault_t=" + mrp_tstdefault_t,
    "mrp_tstnr_max=" + mrp_tstnr_max,
    "mrp_lnkdown_t=" + mrp_lnkdown_t,
    "mrp_lnkup_t=" + mrp_lnkup_t,
    "mrp_lnknr_max=" + mrp_lnknr_max,
    "mrp_ring_state=" + mrp_ring_state,
    "manager_params_present=" + manager_params_present.to_string(),
    "client_params_present=" + client_params_present.to_string(),
    "ring_state_present=" + ring_state_present.to_string(),
    "parameter_set=" + parameter_set,
    "mrp_ring_health=" + ring_health,
    "mrp_readiness=" + mrp_readiness,
    "mrp_digest_state=" + mrp_digest_state,
  ].join("\n")
}

///|
pub fn read_pd_interface_data_real(record_text : String) -> String {
  let mut slot_number = ""
  let mut subslot_number = ""
  let mut chassis_id = ""
  let mut mac_address = ""
  let mut ip_parameter_value = ""
  let mut ip_address = ""
  let mut subnet_mask = ""
  let mut standard_gateway = ""
  for line in fixture_lines(record_text) {
    if line == "" || line[:].has_prefix("#") {
      continue
    }
    let parts = line.split("=").to_array()
    if parts.length() < 2 {
      continue
    }
    let key = parts[0].trim().to_owned()
    let value = parts[1].trim().to_owned()
    match key {
      "slot_number" => slot_number = value
      "subslot_number" => subslot_number = value
      "chassis_id" => chassis_id = value
      "mac_address" => mac_address = value
      "ip_parameter_value" => ip_parameter_value = value
      "ip_address" => ip_address = value
      "subnet_mask" => subnet_mask = value
      "standard_gateway" => standard_gateway = value
      _ => ()
    }
  }
  let parameter_assignment = if ip_parameter_value ==
    dhcp_parameter_data_required_value().to_string() {
    "dhcp"
  } else if ip_parameter_value == "" {
    "unknown"
  } else {
    "static_or_vendor_specific"
  }
  let address_complete = ip_address != "" &&
    subnet_mask != "" &&
    standard_gateway != ""
  [
    "record_method=record_read_pdinterfacedatareal",
    "slot_number=" + slot_number,
    "subslot_number=" + subslot_number,
    "record_index=" + pd_interface_data_real_record_index(),
    "chassis_id=" + chassis_id,
    "mac_address=" + mac_address,
    "ip_parameter_value=" + ip_parameter_value,
    "ip_address=" + ip_address,
    "subnet_mask=" + subnet_mask,
    "standard_gateway=" + standard_gateway,
    "parameter_assignment=" + parameter_assignment,
    "address_complete=" + address_complete.to_string(),
  ].join("\n")
}

///|
pub fn read_pdev_data(record_text : String) -> String {
  let mut has_pd_ir_data = "false"
  let mut has_pd_sync_data = "false"
  let mut has_pd_ir_subframe_data = "false"
  let mut has_pd_time_data = "false"
  for line in fixture_lines(record_text) {
    if line == "" || line[:].has_prefix("#") {
      continue
    }
    let parts = line.split("=").to_array()
    if parts.length() < 2 {
      continue
    }
    let key = parts[0].trim().to_owned()
    let value = parts[1].trim().to_owned()
    match key {
      "has_pd_ir_data" => has_pd_ir_data = normalize_fixture_bool_text(value)
      "has_pd_sync_data" =>
        has_pd_sync_data = normalize_fixture_bool_text(value)
      "has_pd_ir_subframe_data" =>
        has_pd_ir_subframe_data = normalize_fixture_bool_text(value)
      "has_pd_time_data" =>
        has_pd_time_data = normalize_fixture_bool_text(value)
      _ => ()
    }
  }
  let present_components : Array[String] = []
  if has_pd_ir_data == "true" {
    present_components.push("PD IR Data")
  }
  if has_pd_sync_data == "true" {
    present_components.push("PD Sync Data")
  }
  if has_pd_ir_subframe_data == "true" {
    present_components.push("PD IR Subframe Data")
  }
  if has_pd_time_data == "true" {
    present_components.push("PD Time Data")
  }
  [
    "record_method=record_read_pdevdata",
    "record_index=" + pdev_data_record_index(),
    "related_pd_real_data_record_index=" + pd_real_data_record_index(),
    "has_pd_ir_data=" + has_pd_ir_data,
    "has_pd_sync_data=" + has_pd_sync_data,
    "has_pd_ir_subframe_data=" + has_pd_ir_subframe_data,
    "has_pd_time_data=" + has_pd_time_data,
    "present_component_count=" + present_components.length().to_string(),
    "present_components=" + present_components.join(","),
  ].join("\n")
}

///|
fn fixture_value(record_text : String, wanted_key : String) -> String {
  for line in fixture_lines(record_text) {
    let parts = line.split("=").to_array()
    if parts.length() < 2 {
      continue
    }
    let key = parts[0].trim().to_owned()
    let value = parts[1].trim().to_owned()
    if key == wanted_key {
      return value
    }
  }
  ""
}

///|
fn pd_real_data_sections(record_text : String) -> Array[String] {
  let sections : Array[String] = []
  let current_lines : Array[String] = []
  for raw_line in record_text.split("\n").to_array() {
    let line = raw_line.trim().to_owned()
    if line == "" {
      if !current_lines.is_empty() {
        sections.push(current_lines.join("\n"))
        current_lines.clear()
      }
      continue
    }
    if line == "[submodule]" || line == "---" {
      if !current_lines.is_empty() {
        sections.push(current_lines.join("\n"))
        current_lines.clear()
      }
      continue
    }
    if line[:].has_prefix("#") {
      continue
    }
    current_lines.push(line)
  }
  if !current_lines.is_empty() {
    sections.push(current_lines.join("\n"))
  }
  sections
}

///|
pub fn read_pd_real_data(record_text : String) -> String {
  let sections = pd_real_data_sections(record_text)
  let mut port_submodule_count = 0
  let mut port_mrp_submodule_count = 0
  let mut port_mrplc_submodule_count = 0
  let mut interface_submodule_count = 0
  let mut interface_mrp_submodule_count = 0
  let mut statistic_submodule_count = 0
  let mut unsupported_submodule_count = 0
  let mut physical_ready_port_count = 0
  let mut bound_port_mrp_count = 0
  let mut closed_port_mrplc_count = 0
  let mut address_complete_interface_count = 0
  let mut ring_closed_interface_mrp_count = 0
  let mut active_statistic_submodule_count = 0
  let submodule_kinds : Array[String] = []
  let submodule_digests : Array[String] = []
  for section in sections {
    let kind = fixture_value(section, "kind")
    let slot_number = fixture_value(section, "slot_number")
    let subslot_number = fixture_value(section, "subslot_number")
    let location = if slot_number != "" || subslot_number != "" {
      slot_number + "/" + subslot_number
    } else {
      fixture_value(section, "local_port_id")
    }
    if kind == "pd_port_data_real" {
      port_submodule_count += 1
      submodule_kinds.push(kind)
      let summary = read_pd_port_data_real(section)
      if fixture_value(summary, "physical_ready") == "true" {
        physical_ready_port_count += 1
      }
      submodule_digests.push(
        location + ":" + kind + ":" + fixture_value(summary, "topology_status"),
      )
    } else if kind == "pd_port_mrp_data_real" {
      port_mrp_submodule_count += 1
      submodule_kinds.push(kind)
      let summary = read_pd_port_mrp_data_real(section)
      if fixture_value(summary, "domain_assignment") == "bound" {
        bound_port_mrp_count += 1
      }
      submodule_digests.push(
        location + ":" + kind + ":" + fixture_value(summary, "mrp_digest_state"),
      )
    } else if kind == "pd_port_mrplc_data_real" {
      port_mrplc_submodule_count += 1
      submodule_kinds.push(kind)
      let summary = read_pd_port_mrplc_data_real(section)
      if fixture_value(summary, "mrpic_health") == "interconnection_closed" {
        closed_port_mrplc_count += 1
      }
      submodule_digests.push(
        location +
        ":" +
        kind +
        ":" +
        fixture_value(summary, "mrpic_digest_state"),
      )
    } else if kind == "pd_interface_mrp_data_real" {
      interface_mrp_submodule_count += 1
      submodule_kinds.push(kind)
      let summary = read_pd_interface_mrp_data_real(section)
      if fixture_value(summary, "mrp_ring_health") == "ring_closed" {
        ring_closed_interface_mrp_count += 1
      }
      submodule_digests.push(
        location + ":" + kind + ":" + fixture_value(summary, "mrp_digest_state"),
      )
    } else if kind == "pd_interface_data_real" {
      interface_submodule_count += 1
      submodule_kinds.push(kind)
      let summary = read_pd_interface_data_real(section)
      if fixture_value(summary, "address_complete") == "true" {
        address_complete_interface_count += 1
      }
      submodule_digests.push(
        location +
        ":" +
        kind +
        ":" +
        fixture_value(summary, "parameter_assignment"),
      )
    } else if kind == "pd_port_statistic" {
      statistic_submodule_count += 1
      submodule_kinds.push(kind)
      let summary = read_pd_port_statistic(section)
      if fixture_value(summary, "traffic_state") == "active" {
        active_statistic_submodule_count += 1
      }
      submodule_digests.push(
        location + ":" + kind + ":" + fixture_value(summary, "traffic_state"),
      )
    } else if kind != "" {
      unsupported_submodule_count += 1
      submodule_kinds.push(kind)
      submodule_digests.push(location + ":" + kind + ":unsupported")
    }
  }
  [
    "record_method=record_read_pdrealdata",
    "record_index=" + pd_real_data_record_index(),
    "submodule_count=" + sections.length().to_string(),
    "port_submodule_count=" + port_submodule_count.to_string(),
    "port_mrp_submodule_count=" + port_mrp_submodule_count.to_string(),
    "port_mrplc_submodule_count=" + port_mrplc_submodule_count.to_string(),
    "interface_submodule_count=" + interface_submodule_count.to_string(),
    "interface_mrp_submodule_count=" + interface_mrp_submodule_count.to_string(),
    "statistic_submodule_count=" + statistic_submodule_count.to_string(),
    "unsupported_submodule_count=" + unsupported_submodule_count.to_string(),
    "physical_ready_port_count=" + physical_ready_port_count.to_string(),
    "bound_port_mrp_count=" + bound_port_mrp_count.to_string(),
    "closed_port_mrplc_count=" + closed_port_mrplc_count.to_string(),
    "address_complete_interface_count=" +
    address_complete_interface_count.to_string(),
    "ring_closed_interface_mrp_count=" +
    ring_closed_interface_mrp_count.to_string(),
    "active_statistic_submodule_count=" +
    active_statistic_submodule_count.to_string(),
    "submodule_kinds=" + submodule_kinds.join(","),
    "submodule_digests=" + submodule_digests.join(","),
  ].join("\n")
}

///|
pub fn trace_ar_resource_release_time(trace_text : String) -> String {
  let mut session_handle = ""
  let mut arep = ""
  let mut release_reason = ""
  let mut trigger_event = ""
  let mut observed_release_ms = "0"
  let mut release_confirmed = "false"
  let mut trace_source = ""
  let mut transition_count = "1"
  for line in fixture_lines(trace_text) {
    if line == "" || line[:].has_prefix("#") {
      continue
    }
    let parts = line.split("=").to_array()
    if parts.length() < 2 {
      continue
    }
    let key = parts[0].trim().to_owned()
    let value = parts[1].trim().to_owned()
    match key {
      "session_handle" => session_handle = value
      "arep" => arep = value
      "release_reason" => release_reason = value
      "trigger_event" => trigger_event = value
      "observed_release_ms" => observed_release_ms = value
      "release_confirmed" =>
        release_confirmed = normalize_fixture_bool_text(value)
      "trace_source" => trace_source = value
      "transition_count" => transition_count = value
      _ => ()
    }
  }
  let observed_value = @string.parse_int(observed_release_ms[:]) catch {
    _ => 0
  }
  let recommended_release_ms = recommended_ar_resource_release_timeout_ms()
  let mandatory_release_ms = mandatory_ar_resource_release_timeout_ms()
  let compliance = if release_confirmed != "true" {
    "not_confirmed"
  } else if observed_value <= recommended_release_ms {
    "recommended"
  } else if observed_value <= mandatory_release_ms {
    "mandatory_only"
  } else {
    "out_of_spec"
  }
  [
    "trace_method=ar_session_trace",
    "session_handle=" + session_handle,
    "arep=" + arep,
    "release_reason=" + release_reason,
    "trigger_event=" + trigger_event,
    "observed_release_ms=" + observed_release_ms,
    "release_confirmed=" + release_confirmed,
    "trace_source=" + trace_source,
    "transition_count=" + transition_count,
    "recommended_release_ms=" + recommended_release_ms.to_string(),
    "mandatory_release_ms=" + mandatory_release_ms.to_string(),
    "compliance=" + compliance,
  ].join("\n")
}

///|
pub fn measure_snmp_roundtrip(sample_text : String) -> String {
  let mut operation = "get"
  let mut target_ip = ""
  let mut community = ""
  let mut oid = ""
  let mut observed_ms = "0"
  let mut retries = "0"
  let mut timeout_budget_ms = ""
  let mut packet_loss = "false"
  for line in fixture_lines(sample_text) {
    if line == "" || line[:].has_prefix("#") {
      continue
    }
    let parts = line.split("=").to_array()
    if parts.length() < 2 {
      continue
    }
    let key = parts[0].trim().to_owned()
    let value = parts[1].trim().to_owned()
    match key {
      "operation" => operation = value
      "target_ip" => target_ip = value
      "community" => community = value
      "oid" => oid = value
      "observed_ms" => observed_ms = value
      "retries" => retries = value
      "timeout_budget_ms" => timeout_budget_ms = value
      "packet_loss" => packet_loss = normalize_fixture_bool_text(value)
      _ => ()
    }
  }
  let observed_value = @string.parse_int(observed_ms[:]) catch { _ => 0 }
  let recommended_timeout_ms = match operation {
    "set" => recommended_snmp_set_timeout_ms()
    "get_next" => recommended_snmp_get_next_timeout_ms()
    _ => recommended_snmp_get_timeout_ms()
  }
  let mandatory_timeout_ms = match operation {
    "set" => mandatory_snmp_set_timeout_ms()
    "get_next" => mandatory_snmp_get_next_timeout_ms()
    _ => mandatory_snmp_get_timeout_ms()
  }
  let compliance = if observed_value <= recommended_timeout_ms {
    "recommended"
  } else if observed_value <= mandatory_timeout_ms {
    "mandatory_only"
  } else {
    "out_of_spec"
  }
  [
    "measurement_method=active_snmp_roundtrip",
    "operation=" + operation,
    "target_ip=" + target_ip,
    "community=" + community,
    "oid=" + oid,
    "observed_ms=" + observed_ms,
    "retries=" + retries,
    "timeout_budget_ms=" + timeout_budget_ms,
    "packet_loss=" + packet_loss,
    "recommended_timeout_ms=" + recommended_timeout_ms.to_string(),
    "mandatory_timeout_ms=" + mandatory_timeout_ms.to_string(),
    "compliance=" + compliance,
  ].join("\n")
}

///|
pub fn measure_snmp_mib_update(sample_text : String) -> String {
  let mut target_ip = ""
  let mut community = ""
  let mut oid = ""
  let mut poll_interval_ms = ""
  let mut observed_update_ms = "0"
  let mut timeout_budget_ms = ""
  let mut update_detected = "false"
  let mut sample_count = "1"
  for line in fixture_lines(sample_text) {
    if line == "" || line[:].has_prefix("#") {
      continue
    }
    let parts = line.split("=").to_array()
    if parts.length() < 2 {
      continue
    }
    let key = parts[0].trim().to_owned()
    let value = parts[1].trim().to_owned()
    match key {
      "target_ip" => target_ip = value
      "community" => community = value
      "oid" => oid = value
      "poll_interval_ms" => poll_interval_ms = value
      "observed_update_ms" => observed_update_ms = value
      "timeout_budget_ms" => timeout_budget_ms = value
      "update_detected" => update_detected = normalize_fixture_bool_text(value)
      "sample_count" => sample_count = value
      _ => ()
    }
  }
  let observed_value = @string.parse_int(observed_update_ms[:]) catch { _ => 0 }
  let recommended_update_ms = recommended_snmp_mib_update_time_ms()
  let mandatory_update_ms = mandatory_snmp_mib_update_time_ms()
  let compliance = if update_detected != "true" {
    "not_detected"
  } else if observed_value <= recommended_update_ms {
    "recommended"
  } else if observed_value <= mandatory_update_ms {
    "mandatory_only"
  } else {
    "out_of_spec"
  }
  [
    "measurement_method=active_snmp_polling",
    "target_ip=" + target_ip,
    "community=" + community,
    "oid=" + oid,
    "poll_interval_ms=" + poll_interval_ms,
    "observed_update_ms=" + observed_update_ms,
    "timeout_budget_ms=" + timeout_budget_ms,
    "update_detected=" + update_detected,
    "sample_count=" + sample_count,
    "recommended_update_ms=" + recommended_update_ms.to_string(),
    "mandatory_update_ms=" + mandatory_update_ms.to_string(),
    "compliance=" + compliance,
  ].join("\n")
}

///|
pub fn observe_dhcp_runtime_state(observation_text : String) -> String {
  let mut source = ""
  let mut station_name = ""
  let mut current_ip = ""
  let mut previous_ip = ""
  let mut subnet_mask = ""
  let mut gateway = ""
  let mut lease_source = "unknown"
  let mut renewed = "false"
  let mut changed_by_dcp = "false"
  let mut observed_reboot = "false"
  let mut ip_conflict = "false"
  let mut address_observed_count = "1"
  for line in fixture_lines(observation_text) {
    if line == "" || line[:].has_prefix("#") {
      continue
    }
    let parts = line.split("=").to_array()
    if parts.length() < 2 {
      continue
    }
    let key = parts[0].trim().to_owned()
    let value = parts[1].trim().to_owned()
    match key {
      "source" => source = value
      "station_name" => station_name = value
      "current_ip" => current_ip = value
      "previous_ip" => previous_ip = value
      "subnet_mask" => subnet_mask = value
      "gateway" => gateway = value
      "lease_source" => lease_source = value
      "renewed" => renewed = normalize_fixture_bool_text(value)
      "changed_by_dcp" => changed_by_dcp = normalize_fixture_bool_text(value)
      "observed_reboot" => observed_reboot = normalize_fixture_bool_text(value)
      "ip_conflict" => ip_conflict = normalize_fixture_bool_text(value)
      "address_observed_count" => address_observed_count = value
      _ => ()
    }
  }
  let runtime_state = if lease_source == "dhcp" || renewed == "true" {
    "dhcp_active"
  } else if changed_by_dcp == "true" {
    "dcp_override_observed"
  } else if lease_source == "static" {
    "static_observed"
  } else {
    "unknown"
  }
  [
    "observation_method=indirect_ip_observation",
    "source=" + source,
    "station_name=" + station_name,
    "current_ip=" + current_ip,
    "previous_ip=" + previous_ip,
    "subnet_mask=" + subnet_mask,
    "gateway=" + gateway,
    "lease_source=" + lease_source,
    "renewed=" + renewed,
    "changed_by_dcp=" + changed_by_dcp,
    "observed_reboot=" + observed_reboot,
    "ip_conflict=" + ip_conflict,
    "address_observed_count=" + address_observed_count,
    "required_parameter_data_value=" +
    dhcp_parameter_data_required_value().to_string(),
    "required_subnet_mask_option=" +
    dhcp_subnet_mask_option_required().to_string(),
    "required_gateway_option=" + dhcp_gateway_option_required().to_string(),
    "other_options_optional=" + dhcp_other_options_optional().to_string(),
    "runtime_state=" + runtime_state,
  ].join("\n")
}

///|
pub fn read_logbook_data(record_text : String) -> String {
  let entries : Array[String] = []
  let mut source = ""
  let mut slot = ""
  let mut subslot = ""
  let mut block_version_low = "0"
  let mut actual_local_timestamp = ""
  let mut time_timestamp = ""
  let mut entry_local_timestamp = ""
  let mut entry_aruuid = ""
  let mut entry_pniostatus = ""
  let mut entry_detail = ""
  fn flush_logbook_entry(
    entries : Array[String],
    entry_local_timestamp : String,
    entry_aruuid : String,
    entry_pniostatus : String,
    entry_detail : String,
  ) -> Unit {
    if entry_local_timestamp == "" &&
      entry_aruuid == "" &&
      entry_pniostatus == "" &&
      entry_detail == "" {
      return
    }
    entries.push(
      "local_timestamp=" +
      entry_local_timestamp +
      "|aruuid=" +
      entry_aruuid +
      "|pniostatus=" +
      entry_pniostatus +
      "|entry_detail=" +
      entry_detail,
    )
  }
  for line in fixture_lines(record_text) {
    if line == "" || line == "---" {
      flush_logbook_entry(
        entries, entry_local_timestamp, entry_aruuid, entry_pniostatus, entry_detail,
      )
      entry_local_timestamp = ""
      entry_aruuid = ""
      entry_pniostatus = ""
      entry_detail = ""
      continue
    }
    if line[:].has_prefix("#") {
      continue
    }
    let parts = line.split("=").to_array()
    if parts.length() < 2 {
      continue
    }
    let key = parts[0].trim().to_owned()
    let value = parts[1].trim().to_owned()
    match key {
      "source" => source = value
      "slot" => slot = value
      "subslot" => subslot = value
      "block_version_low" => block_version_low = value
      "actual_local_timestamp" => actual_local_timestamp = value
      "time_timestamp" => time_timestamp = value
      "entry_local_timestamp" => entry_local_timestamp = value
      "entry_aruuid" => entry_aruuid = value
      "entry_pniostatus" => entry_pniostatus = value
      "entry_detail" => entry_detail = value
      _ => ()
    }
  }
  flush_logbook_entry(
    entries, entry_local_timestamp, entry_aruuid, entry_pniostatus, entry_detail,
  )
  let lines : Array[String] = []
  lines.push("record_index=0xF830")
  lines.push("scope=device")
  lines.push("source=" + source)
  lines.push("slot=" + slot)
  lines.push("subslot=" + subslot)
  lines.push("block_version_low=" + block_version_low)
  lines.push("minimum_entry_capacity=" + minimum_logbook_entries().to_string())
  lines.push("ring_buffer=true")
  lines.push("whole_buffer_read=true")
  if block_version_low == "0" {
    lines.push("actual_local_timestamp=" + actual_local_timestamp)
  } else {
    lines.push("time_timestamp=" + time_timestamp)
  }
  lines.push("entry_count=" + entries.length().to_string())
  for index, entry in entries {
    lines.push("entry_" + (index + 1).to_string() + "=" + entry)
  }
  lines.join("\n")
}

///|
pub fn read_cimsnmp_real(record_text : String) -> String {
  let mut source = ""
  let mut slot = ""
  let mut subslot = ""
  let mut snmp_disabled = snmp_default_access_disabled().to_string()
  let mut public_community_access = snmp_community_public_access()
  let mut private_community_access = snmp_community_private_access()
  let mut configuration_owner = "cim"
  let mut supported_mib2 = snmp_feature_mib2_required().to_string()
  let mut supported_lldp = snmp_feature_lldp_mib_required().to_string()
  let mut supported_ieee_8021as = snmp_feature_ieee_8021as_mib_optional().to_string()
  let mut supported_bridge = snmp_feature_bridge_mib_optional().to_string()
  let mut supported_pno = snmp_feature_pno_mib_optional().to_string()
  for line in fixture_lines(record_text) {
    if line == "" || line[:].has_prefix("#") {
      continue
    }
    let parts = line.split("=").to_array()
    if parts.length() < 2 {
      continue
    }
    let key = parts[0].trim().to_owned()
    let value = parts[1].trim().to_owned()
    match key {
      "source" => source = value
      "slot" => slot = value
      "subslot" => subslot = value
      "snmp_disabled" => snmp_disabled = normalize_fixture_bool_text(value)
      "public_community_access" => public_community_access = value
      "private_community_access" => private_community_access = value
      "configuration_owner" => configuration_owner = value
      "supported_mib2" => supported_mib2 = normalize_fixture_bool_text(value)
      "supported_lldp" => supported_lldp = normalize_fixture_bool_text(value)
      "supported_ieee_8021as" =>
        supported_ieee_8021as = normalize_fixture_bool_text(value)
      "supported_bridge" =>
        supported_bridge = normalize_fixture_bool_text(value)
      "supported_pno" => supported_pno = normalize_fixture_bool_text(value)
      _ => ()
    }
  }
  [
    "record_index=0x8201",
    "source=" + source,
    "slot=" + slot,
    "subslot=" + subslot,
    "snmp_disabled=" + snmp_disabled,
    "public_community_access=" + public_community_access,
    "private_community_access=" + private_community_access,
    "configuration_owner=" + configuration_owner,
    "explicit_enable_required=" + snmp_explicit_enable_required().to_string(),
    "reverts_after_ar_abort=" + snmp_disabled_after_ar_abort().to_string(),
    "cim_interface_overrides_ar=" +
    snmp_cim_interface_overrides_ar().to_string(),
    "supported_mib2=" + supported_mib2,
    "supported_lldp=" + supported_lldp,
    "supported_ieee_8021as=" + supported_ieee_8021as,
    "supported_bridge=" + supported_bridge,
    "supported_pno=" + supported_pno,
  ].join("\n")
}

///|
pub fn capture_lldp_neighbors(capture_text : String) -> String {
  let entries : Array[String] = []
  let local_ports : Array[String] = []
  let mut local_port = ""
  let mut chassis_id = ""
  let mut port_id = ""
  let mut source_mac = ""
  let mut system_name = ""
  let mut management_address = ""
  fn flush_entry(
    entries : Array[String],
    local_ports : Array[String],
    local_port : String,
    chassis_id : String,
    port_id : String,
    source_mac : String,
    system_name : String,
    management_address : String,
  ) -> Unit {
    if local_port == "" &&
      chassis_id == "" &&
      port_id == "" &&
      source_mac == "" &&
      system_name == "" &&
      management_address == "" {
      return
    }
    if local_port != "" {
      local_ports.push(local_port)
    }
    entries.push(
      "local_port=" +
      local_port +
      "|chassis_id=" +
      chassis_id +
      "|port_id=" +
      port_id +
      "|source_mac=" +
      source_mac +
      "|system_name=" +
      system_name +
      "|management_address=" +
      management_address,
    )
  }
  for line in fixture_lines(capture_text) {
    if line == "" || line == "---" {
      flush_entry(
        entries, local_ports, local_port, chassis_id, port_id, source_mac, system_name,
        management_address,
      )
      local_port = ""
      chassis_id = ""
      port_id = ""
      source_mac = ""
      system_name = ""
      management_address = ""
      continue
    }
    if line[:].has_prefix("#") {
      continue
    }
    let parts = line.split("=").to_array()
    if parts.length() < 2 {
      continue
    }
    let key = parts[0].trim().to_owned()
    let value = parts[1].trim().to_owned()
    match key {
      "local_port" => local_port = value
      "chassis_id" => chassis_id = value
      "port_id" => port_id = value
      "source_mac" => source_mac = value
      "system_name" => system_name = value
      "management_address" => management_address = value
      _ => ()
    }
  }
  flush_entry(
    entries, local_ports, local_port, chassis_id, port_id, source_mac, system_name,
    management_address,
  )
  let lines : Array[String] = []
  lines.push("neighbor_count=" + entries.length().to_string())
  lines.push(
    "minimum_neighbor_capacity=" + lldp_minimum_neighbor_capacity().to_string(),
  )
  lines.push(
    "recommended_neighbor_capacity=" +
    lldp_recommended_neighbor_capacity().to_string(),
  )
  lines.push("local_ports=" + local_ports.join(","))
  for index, entry in entries {
    lines.push("neighbor_" + (index + 1).to_string() + "=" + entry)
  }
  lines.join("\n")
}

///|
pub fn standard_baseline_report() -> String {
  [
    "default_dcp_identify_timeout_ms=" +
    default_dcp_identify_timeout_ms().to_string(),
    "default_dcp_set_get_timeout_ms=" +
    default_dcp_set_get_timeout_ms().to_string(),
    "default_dcp_set_get_max_retry_limit=" +
    default_dcp_set_get_max_retry_limit().to_string(),
    "ip_address_change_bumpless=" + ip_address_change_bumpless().to_string(),
    "station_name_change_bumpless=" + station_name_change_bumpless().to_string(),
    "mandatory_set_usage_time_ms=" + mandatory_set_usage_time_ms().to_string(),
    "recommended_ip_startup_time_ms=" +
    recommended_ip_startup_time_ms().to_string(),
    "mandatory_ip_startup_time_ms=" + mandatory_ip_startup_time_ms().to_string(),
    "recommended_reset_to_factory_time_ms=" +
    recommended_reset_to_factory_time_ms().to_string(),
    "mandatory_reset_to_factory_time_ms=" +
    mandatory_reset_to_factory_time_ms().to_string(),
    "recommended_ar_resource_release_timeout_ms=" +
    recommended_ar_resource_release_timeout_ms().to_string(),
    "mandatory_ar_resource_release_timeout_ms=" +
    mandatory_ar_resource_release_timeout_ms().to_string(),
    "recommended_autonegotiation_timeout_ms=" +
    recommended_autonegotiation_timeout_ms().to_string(),
    "mandatory_autonegotiation_timeout_ms=" +
    mandatory_autonegotiation_timeout_ms().to_string(),
    "minimum_operational_link_speed_mbps=" +
    minimum_operational_link_speed_mbps().to_string(),
    "required_operational_duplex_mode=" + required_operational_duplex_mode(),
    "autonegotiation_fault_requires_link_restart=" +
    autonegotiation_fault_requires_link_restart().to_string(),
    "pd_port_statistic_record_index=" + pd_port_statistic_record_index(),
    "pd_port_mrp_data_real_record_index=" + pd_port_mrp_data_real_record_index(),
    "pd_port_mrplc_data_real_record_index=" +
    pd_port_mrplc_data_real_record_index(),
    "pd_interface_mrp_data_real_record_index=" +
    pd_interface_mrp_data_real_record_index(),
    "pd_interface_data_real_record_index=" +
    pd_interface_data_real_record_index(),
    "pdev_data_record_index=" + pdev_data_record_index(),
    "pd_real_data_record_index=" + pd_real_data_record_index(),
    "pd_port_data_real_extended_record_index=" +
    pd_port_data_real_extended_record_index(),
    "pd_port_data_real_record_index=" + pd_port_data_real_record_index(),
    "pd_port_data_check_record_index=" + pd_port_data_check_record_index(),
    "pd_port_data_check_supported_blocks=" +
    pd_port_data_check_supported_blocks(),
    "mandatory_set_storage_time_ms=" +
    mandatory_set_storage_time_ms().to_string(),
    "maximum_diagnosis_data_per_submodule_octets_exclusive_upper_bound=" +
    maximum_diagnosis_data_per_submodule_octets_exclusive_upper_bound().to_string(),
    "diagnosis_link_state_mismatch_code=" + diagnosis_link_state_mismatch_code(),
    "diagnosis_mau_type_mismatch_code=" + diagnosis_mau_type_mismatch_code(),
    "diagnosis_line_delay_mismatch_code=" + diagnosis_line_delay_mismatch_code(),
    "minimum_logbook_entries=" + minimum_logbook_entries().to_string(),
    "pruning_mac_destination_support_recommended=" +
    pruning_mac_destination_support_recommended().to_string(),
    "lldp_system_capabilities_station_only_required=" +
    lldp_system_capabilities_station_only_required().to_string(),
    "lldp_msg_tx_hold=" + lldp_msg_tx_hold().to_string(),
    "lldp_msg_tx_interval_ms=" + lldp_msg_tx_interval_ms().to_string(),
    "lldp_msg_tx_interval_positive_jitter_ms=" +
    lldp_msg_tx_interval_positive_jitter_ms().to_string(),
    "lldp_tx_ttl_ms=" + lldp_tx_ttl_ms().to_string(),
    "lldp_tx_ttl_positive_jitter_ms=" +
    lldp_tx_ttl_positive_jitter_ms().to_string(),
    "lldp_tx_now_on_change=" + lldp_tx_now_on_change().to_string(),
    "lldp_minimum_neighbor_capacity=" +
    lldp_minimum_neighbor_capacity().to_string(),
    "lldp_recommended_neighbor_capacity=" +
    lldp_recommended_neighbor_capacity().to_string(),
    "minimum_arp_cache_size=" + minimum_arp_cache_size().to_string(),
    "arp_cache_timeout_ms=" + arp_cache_timeout_ms().to_string(),
    "arp_response_timeout_ms=" + arp_response_timeout_ms().to_string(),
    "dns_request_timeout_ms=" + dns_request_timeout_ms().to_string(),
    "reject_dcp_set_requests_support=" + reject_dcp_set_requests_support(),
    "snmp_service_optional=" + snmp_service_optional().to_string(),
    "snmp_default_access_disabled=" + snmp_default_access_disabled().to_string(),
    "snmp_explicit_enable_required=" +
    snmp_explicit_enable_required().to_string(),
    "snmp_disabled_after_ar_abort=" + snmp_disabled_after_ar_abort().to_string(),
    "snmp_cim_interface_overrides_ar=" +
    snmp_cim_interface_overrides_ar().to_string(),
    "snmp_community_public_access=" + snmp_community_public_access(),
    "snmp_community_private_access=" + snmp_community_private_access(),
    "recommended_snmp_set_timeout_ms=" +
    recommended_snmp_set_timeout_ms().to_string(),
    "mandatory_snmp_set_timeout_ms=" +
    mandatory_snmp_set_timeout_ms().to_string(),
    "recommended_snmp_get_timeout_ms=" +
    recommended_snmp_get_timeout_ms().to_string(),
    "mandatory_snmp_get_timeout_ms=" +
    mandatory_snmp_get_timeout_ms().to_string(),
    "recommended_snmp_get_next_timeout_ms=" +
    recommended_snmp_get_next_timeout_ms().to_string(),
    "mandatory_snmp_get_next_timeout_ms=" +
    mandatory_snmp_get_next_timeout_ms().to_string(),
    "recommended_snmp_mib_update_time_ms=" +
    recommended_snmp_mib_update_time_ms().to_string(),
    "mandatory_snmp_mib_update_time_ms=" +
    mandatory_snmp_mib_update_time_ms().to_string(),
    "snmp_feature_mib2_required=" + snmp_feature_mib2_required().to_string(),
    "snmp_feature_lldp_mib_required=" +
    snmp_feature_lldp_mib_required().to_string(),
    "snmp_feature_ieee_8021as_mib_optional=" +
    snmp_feature_ieee_8021as_mib_optional().to_string(),
    "snmp_feature_bridge_mib_optional=" +
    snmp_feature_bridge_mib_optional().to_string(),
    "snmp_feature_pno_mib_optional=" +
    snmp_feature_pno_mib_optional().to_string(),
    "dhcp_service_optional=" + dhcp_service_optional().to_string(),
    "dhcp_subnet_mask_option_required=" +
    dhcp_subnet_mask_option_required().to_string(),
    "dhcp_gateway_option_required=" + dhcp_gateway_option_required().to_string(),
    "dhcp_parameter_data_required_value=" +
    dhcp_parameter_data_required_value().to_string(),
    "dhcp_other_options_optional=" + dhcp_other_options_optional().to_string(),
  ].join("\n")
}

///|
pub fn standard_baseline_grouped_report() -> String {
  [
    [
      "[dcp_defaults]",
      "default_dcp_identify_timeout_ms=" +
      default_dcp_identify_timeout_ms().to_string(),
      "default_dcp_set_get_timeout_ms=" +
      default_dcp_set_get_timeout_ms().to_string(),
      "default_dcp_set_get_max_retry_limit=" +
      default_dcp_set_get_max_retry_limit().to_string(),
    ].join("\n"),
    [
      "[behavior]",
      "ip_address_change_bumpless=" + ip_address_change_bumpless().to_string(),
      "station_name_change_bumpless=" +
      station_name_change_bumpless().to_string(),
      "mandatory_set_usage_time_ms=" + mandatory_set_usage_time_ms().to_string(),
      "recommended_ip_startup_time_ms=" +
      recommended_ip_startup_time_ms().to_string(),
      "mandatory_ip_startup_time_ms=" +
      mandatory_ip_startup_time_ms().to_string(),
      "recommended_reset_to_factory_time_ms=" +
      recommended_reset_to_factory_time_ms().to_string(),
      "mandatory_reset_to_factory_time_ms=" +
      mandatory_reset_to_factory_time_ms().to_string(),
      "recommended_ar_resource_release_timeout_ms=" +
      recommended_ar_resource_release_timeout_ms().to_string(),
      "mandatory_ar_resource_release_timeout_ms=" +
      mandatory_ar_resource_release_timeout_ms().to_string(),
      "recommended_autonegotiation_timeout_ms=" +
      recommended_autonegotiation_timeout_ms().to_string(),
      "mandatory_autonegotiation_timeout_ms=" +
      mandatory_autonegotiation_timeout_ms().to_string(),
      "minimum_operational_link_speed_mbps=" +
      minimum_operational_link_speed_mbps().to_string(),
      "required_operational_duplex_mode=" + required_operational_duplex_mode(),
      "autonegotiation_fault_requires_link_restart=" +
      autonegotiation_fault_requires_link_restart().to_string(),
      "pd_port_statistic_record_index=" + pd_port_statistic_record_index(),
      "pd_port_mrp_data_real_record_index=" +
      pd_port_mrp_data_real_record_index(),
      "pd_port_mrplc_data_real_record_index=" +
      pd_port_mrplc_data_real_record_index(),
      "pd_interface_mrp_data_real_record_index=" +
      pd_interface_mrp_data_real_record_index(),
      "pd_interface_data_real_record_index=" +
      pd_interface_data_real_record_index(),
      "pdev_data_record_index=" + pdev_data_record_index(),
      "pd_real_data_record_index=" + pd_real_data_record_index(),
      "pd_port_data_real_extended_record_index=" +
      pd_port_data_real_extended_record_index(),
      "pd_port_data_real_record_index=" + pd_port_data_real_record_index(),
      "pd_port_data_check_record_index=" + pd_port_data_check_record_index(),
      "pd_port_data_check_supported_blocks=" +
      pd_port_data_check_supported_blocks(),
      "mandatory_set_storage_time_ms=" +
      mandatory_set_storage_time_ms().to_string(),
    ].join("\n"),
    [
      "[diagnosis_and_lldp]",
      "maximum_diagnosis_data_per_submodule_octets_exclusive_upper_bound=" +
      maximum_diagnosis_data_per_submodule_octets_exclusive_upper_bound().to_string(),
      "diagnosis_link_state_mismatch_code=" +
      diagnosis_link_state_mismatch_code(),
      "diagnosis_mau_type_mismatch_code=" + diagnosis_mau_type_mismatch_code(),
      "diagnosis_line_delay_mismatch_code=" +
      diagnosis_line_delay_mismatch_code(),
      "minimum_logbook_entries=" + minimum_logbook_entries().to_string(),
      "pruning_mac_destination_support_recommended=" +
      pruning_mac_destination_support_recommended().to_string(),
      "lldp_system_capabilities_station_only_required=" +
      lldp_system_capabilities_station_only_required().to_string(),
      "lldp_msg_tx_hold=" + lldp_msg_tx_hold().to_string(),
      "lldp_msg_tx_interval_ms=" + lldp_msg_tx_interval_ms().to_string(),
      "lldp_msg_tx_interval_positive_jitter_ms=" +
      lldp_msg_tx_interval_positive_jitter_ms().to_string(),
      "lldp_tx_ttl_ms=" + lldp_tx_ttl_ms().to_string(),
      "lldp_tx_ttl_positive_jitter_ms=" +
      lldp_tx_ttl_positive_jitter_ms().to_string(),
      "lldp_tx_now_on_change=" + lldp_tx_now_on_change().to_string(),
      "lldp_minimum_neighbor_capacity=" +
      lldp_minimum_neighbor_capacity().to_string(),
      "lldp_recommended_neighbor_capacity=" +
      lldp_recommended_neighbor_capacity().to_string(),
    ].join("\n"),
    [
      "[network]",
      "minimum_arp_cache_size=" + minimum_arp_cache_size().to_string(),
      "arp_cache_timeout_ms=" + arp_cache_timeout_ms().to_string(),
      "arp_response_timeout_ms=" + arp_response_timeout_ms().to_string(),
      "dns_request_timeout_ms=" + dns_request_timeout_ms().to_string(),
      "reject_dcp_set_requests_support=" + reject_dcp_set_requests_support(),
    ].join("\n"),
    [
      "[snmp]",
      "snmp_service_optional=" + snmp_service_optional().to_string(),
      "snmp_default_access_disabled=" +
      snmp_default_access_disabled().to_string(),
      "snmp_explicit_enable_required=" +
      snmp_explicit_enable_required().to_string(),
      "snmp_disabled_after_ar_abort=" +
      snmp_disabled_after_ar_abort().to_string(),
      "snmp_cim_interface_overrides_ar=" +
      snmp_cim_interface_overrides_ar().to_string(),
      "snmp_community_public_access=" + snmp_community_public_access(),
      "snmp_community_private_access=" + snmp_community_private_access(),
      "recommended_snmp_set_timeout_ms=" +
      recommended_snmp_set_timeout_ms().to_string(),
      "mandatory_snmp_set_timeout_ms=" +
      mandatory_snmp_set_timeout_ms().to_string(),
      "recommended_snmp_get_timeout_ms=" +
      recommended_snmp_get_timeout_ms().to_string(),
      "mandatory_snmp_get_timeout_ms=" +
      mandatory_snmp_get_timeout_ms().to_string(),
      "recommended_snmp_get_next_timeout_ms=" +
      recommended_snmp_get_next_timeout_ms().to_string(),
      "mandatory_snmp_get_next_timeout_ms=" +
      mandatory_snmp_get_next_timeout_ms().to_string(),
      "recommended_snmp_mib_update_time_ms=" +
      recommended_snmp_mib_update_time_ms().to_string(),
      "mandatory_snmp_mib_update_time_ms=" +
      mandatory_snmp_mib_update_time_ms().to_string(),
      "snmp_feature_mib2_required=" + snmp_feature_mib2_required().to_string(),
      "snmp_feature_lldp_mib_required=" +
      snmp_feature_lldp_mib_required().to_string(),
      "snmp_feature_ieee_8021as_mib_optional=" +
      snmp_feature_ieee_8021as_mib_optional().to_string(),
      "snmp_feature_bridge_mib_optional=" +
      snmp_feature_bridge_mib_optional().to_string(),
      "snmp_feature_pno_mib_optional=" +
      snmp_feature_pno_mib_optional().to_string(),
    ].join("\n"),
    [
      "[dhcp]",
      "dhcp_service_optional=" + dhcp_service_optional().to_string(),
      "dhcp_subnet_mask_option_required=" +
      dhcp_subnet_mask_option_required().to_string(),
      "dhcp_gateway_option_required=" +
      dhcp_gateway_option_required().to_string(),
      "dhcp_parameter_data_required_value=" +
      dhcp_parameter_data_required_value().to_string(),
      "dhcp_other_options_optional=" + dhcp_other_options_optional().to_string(),
    ].join("\n"),
  ].join("\n\n")
}

///|
pub fn standard_baseline_markdown_report() -> String {
  [
    "## DCP Defaults\n- default_dcp_identify_timeout_ms: " +
    default_dcp_identify_timeout_ms().to_string() +
    "\n- default_dcp_set_get_timeout_ms: " +
    default_dcp_set_get_timeout_ms().to_string() +
    "\n- default_dcp_set_get_max_retry_limit: " +
    default_dcp_set_get_max_retry_limit().to_string(),
    "## Behavior\n- ip_address_change_bumpless: " +
    ip_address_change_bumpless().to_string() +
    "\n- station_name_change_bumpless: " +
    station_name_change_bumpless().to_string() +
    "\n- mandatory_set_usage_time_ms: " +
    mandatory_set_usage_time_ms().to_string() +
    "\n- recommended_ip_startup_time_ms: " +
    recommended_ip_startup_time_ms().to_string() +
    "\n- mandatory_ip_startup_time_ms: " +
    mandatory_ip_startup_time_ms().to_string() +
    "\n- recommended_reset_to_factory_time_ms: " +
    recommended_reset_to_factory_time_ms().to_string() +
    "\n- mandatory_reset_to_factory_time_ms: " +
    mandatory_reset_to_factory_time_ms().to_string() +
    "\n- recommended_ar_resource_release_timeout_ms: " +
    recommended_ar_resource_release_timeout_ms().to_string() +
    "\n- mandatory_ar_resource_release_timeout_ms: " +
    mandatory_ar_resource_release_timeout_ms().to_string() +
    "\n- recommended_autonegotiation_timeout_ms: " +
    recommended_autonegotiation_timeout_ms().to_string() +
    "\n- mandatory_autonegotiation_timeout_ms: " +
    mandatory_autonegotiation_timeout_ms().to_string() +
    "\n- minimum_operational_link_speed_mbps: " +
    minimum_operational_link_speed_mbps().to_string() +
    "\n- required_operational_duplex_mode: " +
    required_operational_duplex_mode() +
    "\n- autonegotiation_fault_requires_link_restart: " +
    autonegotiation_fault_requires_link_restart().to_string() +
    "\n- pd_port_statistic_record_index: " +
    pd_port_statistic_record_index() +
    "\n- pd_port_mrp_data_real_record_index: " +
    pd_port_mrp_data_real_record_index() +
    "\n- pd_port_mrplc_data_real_record_index: " +
    pd_port_mrplc_data_real_record_index() +
    "\n- pd_interface_mrp_data_real_record_index: " +
    pd_interface_mrp_data_real_record_index() +
    "\n- pd_interface_data_real_record_index: " +
    pd_interface_data_real_record_index() +
    "\n- pdev_data_record_index: " +
    pdev_data_record_index() +
    "\n- pd_real_data_record_index: " +
    pd_real_data_record_index() +
    "\n- pd_port_data_real_extended_record_index: " +
    pd_port_data_real_extended_record_index() +
    "\n- pd_port_data_real_record_index: " +
    pd_port_data_real_record_index() +
    "\n- pd_port_data_check_record_index: " +
    pd_port_data_check_record_index() +
    "\n- pd_port_data_check_supported_blocks: " +
    pd_port_data_check_supported_blocks() +
    "\n- mandatory_set_storage_time_ms: " +
    mandatory_set_storage_time_ms().to_string(),
    "## Diagnosis And LLDP\n- maximum_diagnosis_data_per_submodule_octets_exclusive_upper_bound: " +
    maximum_diagnosis_data_per_submodule_octets_exclusive_upper_bound().to_string() +
    "\n- diagnosis_link_state_mismatch_code: " +
    diagnosis_link_state_mismatch_code() +
    "\n- diagnosis_mau_type_mismatch_code: " +
    diagnosis_mau_type_mismatch_code() +
    "\n- diagnosis_line_delay_mismatch_code: " +
    diagnosis_line_delay_mismatch_code() +
    "\n- minimum_logbook_entries: " +
    minimum_logbook_entries().to_string() +
    "\n- lldp_msg_tx_interval_ms: " +
    lldp_msg_tx_interval_ms().to_string() +
    "\n- lldp_tx_ttl_ms: " +
    lldp_tx_ttl_ms().to_string(),
    "## Network\n- minimum_arp_cache_size: " +
    minimum_arp_cache_size().to_string() +
    "\n- arp_cache_timeout_ms: " +
    arp_cache_timeout_ms().to_string() +
    "\n- arp_response_timeout_ms: " +
    arp_response_timeout_ms().to_string() +
    "\n- dns_request_timeout_ms: " +
    dns_request_timeout_ms().to_string(),
    "## SNMP\n- snmp_service_optional: " +
    snmp_service_optional().to_string() +
    "\n- snmp_default_access_disabled: " +
    snmp_default_access_disabled().to_string() +
    "\n- recommended_snmp_set_timeout_ms: " +
    recommended_snmp_set_timeout_ms().to_string() +
    "\n- mandatory_snmp_set_timeout_ms: " +
    mandatory_snmp_set_timeout_ms().to_string(),
    "## DHCP\n- dhcp_service_optional: " +
    dhcp_service_optional().to_string() +
    "\n- dhcp_parameter_data_required_value: " +
    dhcp_parameter_data_required_value().to_string() +
    "\n- dhcp_other_options_optional: " +
    dhcp_other_options_optional().to_string(),
  ].join("\n\n")
}

///|
pub fn probeability_matrix_report() -> String {
  [
    "metric=set_usage_time|method=" +
    set_usage_time_probeability() +
    "|class=" +
    set_usage_time_probeability_class(),
    "metric=ip_startup_time|method=" +
    ip_startup_time_probeability() +
    "|class=" +
    ip_startup_time_probeability_class(),
    "metric=reset_to_factory_time|method=" +
    reset_to_factory_time_probeability() +
    "|class=" +
    reset_to_factory_time_probeability_class(),
    "metric=ar_resource_release_time|method=" +
    ar_resource_release_time_probeability() +
    "|class=" +
    ar_resource_release_time_probeability_class(),
    "metric=autonegotiation_time|method=" +
    autonegotiation_time_probeability() +
    "|class=" +
    autonegotiation_time_probeability_class(),
    "metric=pd_port_statistic|method=" +
    pd_port_statistic_probeability() +
    "|class=" +
    pd_port_statistic_probeability_class(),
    "metric=pd_port_mrp_data_real|method=" +
    pd_port_mrp_data_real_probeability() +
    "|class=" +
    pd_port_mrp_data_real_probeability_class(),
    "metric=pd_port_mrplc_data_real|method=" +
    pd_port_mrplc_data_real_probeability() +
    "|class=" +
    pd_port_mrplc_data_real_probeability_class(),
    "metric=pd_real_data|method=" +
    pd_real_data_probeability() +
    "|class=" +
    pd_real_data_probeability_class(),
    "metric=pd_interface_mrp_data_real|method=" +
    pd_interface_mrp_data_real_probeability() +
    "|class=" +
    pd_interface_mrp_data_real_probeability_class(),
    "metric=pd_interface_data_real|method=" +
    pd_interface_data_real_probeability() +
    "|class=" +
    pd_interface_data_real_probeability_class(),
    "metric=pdev_data|method=" +
    pdev_data_probeability() +
    "|class=" +
    pdev_data_probeability_class(),
    "metric=pd_port_data_real|method=" +
    pd_port_data_real_probeability() +
    "|class=" +
    pd_port_data_real_probeability_class(),
    "metric=lldp_neighbor_state|method=" +
    lldp_neighbor_probeability() +
    "|class=" +
    lldp_neighbor_probeability_class(),
    "metric=logbook_data|method=" +
    logbook_data_probeability() +
    "|class=" +
    logbook_data_probeability_class(),
    "metric=snmp_default_state|method=" +
    snmp_default_state_probeability() +
    "|class=" +
    snmp_default_state_probeability_class(),
    "metric=snmp_timeout|method=" +
    snmp_timeout_probeability() +
    "|class=" +
    snmp_timeout_probeability_class(),
    "metric=snmp_mib_update|method=" +
    snmp_mib_update_probeability() +
    "|class=" +
    snmp_mib_update_probeability_class(),
    "metric=dhcp_option_support|method=" +
    dhcp_option_support_probeability() +
    "|class=" +
    dhcp_option_support_probeability_class(),
    "metric=dhcp_runtime_state|method=" +
    dhcp_runtime_state_probeability() +
    "|class=" +
    dhcp_runtime_state_probeability_class(),
  ].join("\n")
}

// ── Alarm facade ────────────────────────────────────────────────

///|
pub fn encode_alarm_cr_block_req() -> Bytes {
  @alarm.encode_alarm_cr_block_req(@alarm.AlarmCRBlockReq::default())
}

///|
pub fn parse_alarm_cr_block_res(
  data : Bytes,
  offset : Int,
) -> @alarm.AlarmCRBlockRes raise @frame.FrameError {
  @alarm.parse_alarm_cr_block_res(data, offset)
}

///|
pub fn parse_alarm_notification(
  data : Bytes,
  offset : Int,
) -> @alarm.AlarmNotification raise @frame.FrameError {
  @alarm.parse_alarm_notification(data, offset)
}

///|
pub fn format_alarm_notification(alarm : @alarm.AlarmNotification) -> String {
  @alarm.format_alarm_notification(alarm)
}

// ── RPC/DCE facade ──────────────────────────────────────────────

///|
pub fn encode_dce_header(header : @rpc.DceHeader) -> Bytes {
  @rpc.encode_dce_header(header)
}

///|
pub fn parse_dce_header(
  data : Bytes,
  offset : Int,
) -> @rpc.DceHeader raise @frame.FrameError {
  @rpc.parse_dce_header(data, offset)
}

///|
pub fn format_dce_header(header : @rpc.DceHeader) -> String {
  @rpc.format_dce_header(header)
}

// ── AR/IOCR facade ──────────────────────────────────────────────

///|
pub fn encode_ar_block_req(req : @ar.ARBlockReq) -> Bytes {
  @ar.encode_ar_block_req(req)
}

///|
pub fn parse_ar_block_res(
  data : Bytes,
  offset : Int,
) -> @ar.ARBlockRes raise @frame.FrameError {
  @ar.parse_ar_block_res(data, offset)
}

///|
pub fn encode_iocr_block_req(req : @ar.IOCRBlockReq) -> Bytes {
  @ar.encode_iocr_block_req(req)
}

///|
pub fn parse_iocr_block_res(
  data : Bytes,
  offset : Int,
) -> @ar.IOCRBlockRes raise @frame.FrameError {
  @ar.parse_iocr_block_res(data, offset)
}

// ── IO Data Exchange facade ─────────────────────────────────────

///|
pub fn encode_cyclic_frame(frame : @io.IoCyclicFrame) -> Bytes {
  @io.encode_cyclic_frame(frame)
}

///|
pub fn parse_cyclic_frame(
  data : Bytes,
  offset : Int,
  data_length : Int,
) -> @io.IoCyclicFrame raise @frame.FrameError {
  @io.parse_cyclic_frame(data, offset, data_length)
}

///|
pub fn parse_iam0(
  data : Bytes,
  offset : Int,
) -> @io.IAndM0 raise @frame.FrameError {
  @io.parse_iam0(data, offset)
}

///|
pub fn format_iam0(iam0 : @io.IAndM0) -> String {
  @io.format_iam0(iam0)
}

// ── Record Read/Write facade ────────────────────────────────────

///|
pub fn encode_iod_read_req_header(req : @record.IODReadReqHeader) -> Bytes {
  @record.encode_iod_read_req_header(req)
}

///|
pub fn encode_iod_write_req_header(req : @record.IODWriteReqHeader) -> Bytes {
  @record.encode_iod_write_req_header(req)
}

///|
pub fn encode_iod_control_req(req : @record.IODControlReq) -> Bytes {
  @record.encode_iod_control_req(req)
}

///|
pub fn parse_iod_control_req(
  data : Bytes,
  offset : Int,
) -> @record.IODControlReq raise @frame.FrameError {
  @record.parse_iod_control_req(data, offset)
}

// ── PROFIdrive facade ───────────────────────────────────────────

///|
pub fn encode_profidrive_param_request(req : @profidrive.ParamRequest) -> Bytes {
  @profidrive.encode_param_request(req)
}

///|
pub fn parse_profidrive_param_response(
  data : Bytes,
  offset : Int,
) -> @profidrive.ParamResponse raise @frame.FrameError {
  @profidrive.parse_param_response(data, offset)
}

///|
pub fn format_profidrive_param_request(
  req : @profidrive.ParamRequest,
) -> String {
  @profidrive.format_param_request(req)
}

// ── SNMP facade ─────────────────────────────────────────────────

///|
pub fn build_snmp_get_request(
  community : String,
  request_id : Int,
  oid : String,
) -> @snmp.SnmpMessage {
  @snmp.build_get_request(community, request_id, oid)
}

///|
pub fn build_snmp_get_next_request(
  community : String,
  request_id : Int,
  oid : String,
) -> @snmp.SnmpMessage {
  @snmp.build_get_next_request(community, request_id, oid)
}

///|
pub fn format_snmp_message(msg : @snmp.SnmpMessage) -> String {
  @snmp.format_snmp_message(msg)
}

// ── LLDP facade ─────────────────────────────────────────────────

///|
pub fn parse_lldp_tlvs(
  data : Bytes,
  offset : Int,
) -> Array[@lldp.LldpTlv] raise @frame.FrameError {
  @lldp.parse_lldp_tlvs(data, offset)
}

///|
pub fn extract_lldp_neighbor(tlvs : Array[@lldp.LldpTlv]) -> @lldp.LldpNeighbor {
  @lldp.extract_neighbor(tlvs)
}

///|
pub fn format_lldp_neighbor(n : @lldp.LldpNeighbor) -> String {
  @lldp.format_neighbor(n)
}

// ── DHCP facade ─────────────────────────────────────────────────

///|
pub fn build_dhcp_discover(
  mac : Bytes,
  xid : Int,
  hostname? : String = "",
) -> @dhcp.DhcpMessage {
  @dhcp.build_discover(mac, xid, hostname~)
}

///|
pub fn encode_dhcp_message(msg : @dhcp.DhcpMessage) -> Bytes {
  @dhcp.encode_dhcp_message(msg)
}

///|
pub fn parse_dhcp_message(
  data : Bytes,
) -> @dhcp.DhcpMessage raise @frame.FrameError {
  @dhcp.parse_dhcp_message(data)
}

///|
pub fn format_dhcp_message(msg : @dhcp.DhcpMessage) -> String {
  @dhcp.format_dhcp_message(msg)
}

///|
pub fn probeability_matrix_markdown_report() -> String {
  [
    "| Metric | Method | Class |",
    "| --- | --- | --- |",
    "| set_usage_time | " +
    set_usage_time_probeability() +
    " | " +
    set_usage_time_probeability_class() +
    " |",
    "| ip_startup_time | " +
    ip_startup_time_probeability() +
    " | " +
    ip_startup_time_probeability_class() +
    " |",
    "| reset_to_factory_time | " +
    reset_to_factory_time_probeability() +
    " | " +
    reset_to_factory_time_probeability_class() +
    " |",
    "| ar_resource_release_time | " +
    ar_resource_release_time_probeability() +
    " | " +
    ar_resource_release_time_probeability_class() +
    " |",
    "| autonegotiation_time | " +
    autonegotiation_time_probeability() +
    " | " +
    autonegotiation_time_probeability_class() +
    " |",
    "| pd_port_statistic | " +
    pd_port_statistic_probeability() +
    " | " +
    pd_port_statistic_probeability_class() +
    " |",
    "| pd_port_mrp_data_real | " +
    pd_port_mrp_data_real_probeability() +
    " | " +
    pd_port_mrp_data_real_probeability_class() +
    " |",
    "| pd_port_mrplc_data_real | " +
    pd_port_mrplc_data_real_probeability() +
    " | " +
    pd_port_mrplc_data_real_probeability_class() +
    " |",
    "| pd_real_data | " +
    pd_real_data_probeability() +
    " | " +
    pd_real_data_probeability_class() +
    " |",
    "| pd_interface_mrp_data_real | " +
    pd_interface_mrp_data_real_probeability() +
    " | " +
    pd_interface_mrp_data_real_probeability_class() +
    " |",
    "| pd_interface_data_real | " +
    pd_interface_data_real_probeability() +
    " | " +
    pd_interface_data_real_probeability_class() +
    " |",
    "| pdev_data | " +
    pdev_data_probeability() +
    " | " +
    pdev_data_probeability_class() +
    " |",
    "| pd_port_data_real | " +
    pd_port_data_real_probeability() +
    " | " +
    pd_port_data_real_probeability_class() +
    " |",
    "| lldp_neighbor_state | " +
    lldp_neighbor_probeability() +
    " | " +
    lldp_neighbor_probeability_class() +
    " |",
    "| logbook_data | " +
    logbook_data_probeability() +
    " | " +
    logbook_data_probeability_class() +
    " |",
    "| snmp_default_state | " +
    snmp_default_state_probeability() +
    " | " +
    snmp_default_state_probeability_class() +
    " |",
    "| snmp_timeout | " +
    snmp_timeout_probeability() +
    " | " +
    snmp_timeout_probeability_class() +
    " |",
    "| snmp_mib_update | " +
    snmp_mib_update_probeability() +
    " | " +
    snmp_mib_update_probeability_class() +
    " |",
    "| dhcp_option_support | " +
    dhcp_option_support_probeability() +
    " | " +
    dhcp_option_support_probeability_class() +
    " |",
    "| dhcp_runtime_state | " +
    dhcp_runtime_state_probeability() +
    " | " +
    dhcp_runtime_state_probeability_class() +
    " |",
  ].join("\n")
}

///|
pub fn acquisition_channel_skeleton_report() -> String {
  [
    "class=requires_protocol_extension|metric=ar_resource_release_time|channel=ar_session_trace|planned_api=trace_ar_resource_release_time|planned_inputs=fixture_text|status=offline_fixture_ready",
    "class=requires_link_state_capture|metric=autonegotiation_time|channel=link_state_trace|planned_api=trace_link_state_autonegotiation|planned_inputs=fixture_text|status=offline_fixture_ready",
    "class=requires_protocol_extension|metric=pd_port_statistic|channel=record_read_pdportstatistic|planned_api=read_pd_port_statistic|planned_inputs=fixture_text|status=offline_fixture_ready",
    "class=requires_protocol_extension|metric=pd_port_mrp_data_real|channel=record_read_pdportmrpdatareal|planned_api=read_pd_port_mrp_data_real|planned_inputs=fixture_text|status=offline_fixture_ready",
    "class=requires_protocol_extension|metric=pd_port_mrplc_data_real|channel=record_read_pdportmrplcdatareal|planned_api=read_pd_port_mrplc_data_real|planned_inputs=fixture_text|status=offline_fixture_ready",
    "class=requires_protocol_extension|metric=pd_real_data|channel=record_read_pdrealdata|planned_api=read_pd_real_data|planned_inputs=fixture_text|status=offline_fixture_ready",
    "class=requires_protocol_extension|metric=pd_interface_mrp_data_real|channel=record_read_pdinterfacemrpdatareal|planned_api=read_pd_interface_mrp_data_real|planned_inputs=fixture_text|status=offline_fixture_ready",
    "class=requires_protocol_extension|metric=pd_interface_data_real|channel=record_read_pdinterfacedatareal|planned_api=read_pd_interface_data_real|planned_inputs=fixture_text|status=offline_fixture_ready",
    "class=requires_protocol_extension|metric=pdev_data|channel=record_read_pdevdata|planned_api=read_pdev_data|planned_inputs=fixture_text|status=offline_fixture_ready",
    "class=requires_protocol_extension|metric=pd_port_data_real|channel=record_read_pdportdatareal|planned_api=read_pd_port_data_real|planned_inputs=fixture_text|status=offline_fixture_ready",
    "class=indirect_only|metric=dhcp_runtime_state|channel=indirect_ip_observation|planned_api=observe_dhcp_runtime_state|planned_inputs=fixture_text|status=offline_fixture_ready",
    "class=requires_protocol_extension|metric=logbook_data|channel=record_read_logbookdata|planned_api=read_logbook_data|planned_inputs=fixture_text|status=offline_fixture_ready",
    "class=requires_protocol_extension|metric=snmp_default_state|channel=record_read_cimsnmpreal|planned_api=read_cimsnmp_real|planned_inputs=fixture_text|status=offline_fixture_ready",
    "class=requires_protocol_extension|metric=snmp_timeout|channel=active_snmp_roundtrip|planned_api=measure_snmp_roundtrip|planned_inputs=fixture_text|status=offline_fixture_ready",
    "class=requires_protocol_extension|metric=snmp_mib_update|channel=active_snmp_polling|planned_api=measure_snmp_mib_update|planned_inputs=fixture_text|status=offline_fixture_ready",
    "class=requires_packet_capture|metric=lldp_neighbor_state|channel=passive_lldp_capture|planned_api=capture_lldp_neighbors|planned_inputs=fixture_text|status=offline_fixture_ready",
  ].join("\n")
}

///|
pub fn acquisition_channel_skeleton_markdown_report() -> String {
  [
    "| Class | Metric | Channel | Planned API | Planned Inputs | Status |", "| --- | --- | --- | --- | --- | --- |",
    "| requires_protocol_extension | ar_resource_release_time | ar_session_trace | trace_ar_resource_release_time | fixture_text | offline_fixture_ready |",
    "| requires_link_state_capture | autonegotiation_time | link_state_trace | trace_link_state_autonegotiation | fixture_text | offline_fixture_ready |",
    "| requires_protocol_extension | pd_port_statistic | record_read_pdportstatistic | read_pd_port_statistic | fixture_text | offline_fixture_ready |",
    "| requires_protocol_extension | pd_port_mrp_data_real | record_read_pdportmrpdatareal | read_pd_port_mrp_data_real | fixture_text | offline_fixture_ready |",
    "| requires_protocol_extension | pd_port_mrplc_data_real | record_read_pdportmrplcdatareal | read_pd_port_mrplc_data_real | fixture_text | offline_fixture_ready |",
    "| requires_protocol_extension | pd_real_data | record_read_pdrealdata | read_pd_real_data | fixture_text | offline_fixture_ready |",
    "| requires_protocol_extension | pd_interface_mrp_data_real | record_read_pdinterfacemrpdatareal | read_pd_interface_mrp_data_real | fixture_text | offline_fixture_ready |",
    "| requires_protocol_extension | pd_interface_data_real | record_read_pdinterfacedatareal | read_pd_interface_data_real | fixture_text | offline_fixture_ready |",
    "| requires_protocol_extension | pdev_data | record_read_pdevdata | read_pdev_data | fixture_text | offline_fixture_ready |",
    "| requires_protocol_extension | pd_port_data_real | record_read_pdportdatareal | read_pd_port_data_real | fixture_text | offline_fixture_ready |",
    "| indirect_only | dhcp_runtime_state | indirect_ip_observation | observe_dhcp_runtime_state | fixture_text | offline_fixture_ready |",
    "| requires_protocol_extension | logbook_data | record_read_logbookdata | read_logbook_data | fixture_text | offline_fixture_ready |",
    "| requires_protocol_extension | snmp_default_state | record_read_cimsnmpreal | read_cimsnmp_real | fixture_text | offline_fixture_ready |",
    "| requires_protocol_extension | snmp_timeout | active_snmp_roundtrip | measure_snmp_roundtrip | fixture_text | offline_fixture_ready |",
    "| requires_protocol_extension | snmp_mib_update | active_snmp_polling | measure_snmp_mib_update | fixture_text | offline_fixture_ready |",
    "| requires_packet_capture | lldp_neighbor_state | passive_lldp_capture | capture_lldp_neighbors | fixture_text | offline_fixture_ready |",
  ].join("\n")
}

///|
pub fn parse_gsdml_summary_text(xml_text : String) -> String raise {
  let summary = @gsd.parse_gsdml_summary(xml_text)
  format_gsd_summary(summary)
}

// ── GSD detail facade ───────────────────────────────────────────

///|
pub fn parse_gsdml_detail_text(xml_text : String) -> String raise {
  let detail = @gsd.parse_gsdml_detail(xml_text)
  @gsd.format_gsd_detail(detail)
}

// ── PROFIdrive controller facade ────────────────────────────────

///|
pub fn profidrive_stw1_for_state(target : @profidrive.DriveState) -> Int {
  @profidrive.stw1_for_transition(target)
}

///|
pub fn profidrive_state_from_zsw1(zsw1 : Int) -> String {
  @profidrive.drive_state_label(@profidrive.drive_state_from_zsw1(zsw1))
}

///|
pub fn profidrive_format_telegram(tg : @profidrive.TelegramData) -> String {
  @profidrive.format_telegram(tg)
}

///|
pub fn profidrive_pnu_label_ext(pnu : Int) -> String {
  @profidrive.pnu_label_ext(pnu)
}

// ── Security facade ─────────────────────────────────────────────

///|
pub fn security_format_info(
  mode : @security.SecurityMode,
  alg : @security.AeadAlgorithm,
) -> String {
  @security.format_security_info(mode, alg)
}

///|
pub fn security_encode_header(sd : @security.SecurityData) -> Bytes {
  @security.encode_security_data(sd)
}

///|
pub fn security_parse_header(
  data : Bytes,
  offset : Int,
) -> @security.SecurityData raise {
  @security.parse_security_data(data, offset)
}

///|
pub fn security_format_header(sd : @security.SecurityData) -> String {
  @security.format_security_data(sd)
}

// ── Alarm hex facade ────────────────────────────────────────────

///|
pub fn decode_alarm_notification_hex(hex : StringView) -> String raise {
  let data = @frame.bytes_from_hex(hex)
  let notif = @alarm.parse_alarm_notification(data, 0)
  @alarm.format_alarm_notification(notif)
}

// ── RPC hex facade ──────────────────────────────────────────────

///|
pub fn decode_rpc_header_hex(hex : StringView) -> String raise {
  let data = @frame.bytes_from_hex(hex)
  let hdr = @rpc.parse_dce_header(data, 0)
  @rpc.format_dce_header(hdr)
}

// ── AR hex facade ───────────────────────────────────────────────

///|
pub fn format_ar_block_req_default(station_name : String) -> String {
  let req = @ar.ARBlockReq::default(
    @rpc.Uuid::empty(),
    @frame.MacAddress::broadcast(),
    station_name,
  )
  @ar.format_ar_block_req(req)
}

///|
pub fn format_iocr_block_req_default(frame_id : Int) -> String {
  let req = @ar.IOCRBlockReq::default_input(frame_id)
  @ar.format_iocr_block_req(req)
}

// ── IO hex facade ───────────────────────────────────────────────

///|
pub fn decode_io_cyclic_frame_hex(hex : StringView) -> String raise {
  let data = @frame.bytes_from_hex(hex)
  // frame_id(2) + payload(N) + cycle_counter(2) + data_status(1) + transfer_status(1)
  let payload_len = data.length() - 6
  guard payload_len >= 0 else {
    raise @frame.FrameError::InvalidMacLength(data.length())
  }
  let frame = @io.parse_cyclic_frame(data, 0, payload_len)
  let lines : Array[String] = []
  lines.push("frame_id=0x" + @frame.uint16_to_hex(frame.frame_id))
  lines.push("cycle_counter=" + frame.cycle_counter.to_string())
  lines.push(
    "data_status=0x" + @frame.uint16_to_hex(frame.data_status.to_int()),
  )
  let data_status = @io.decode_data_status(frame.data_status)
  lines.push("data_status_state=" + data_status.state)
  lines.push("data_status_redundancy=" + data_status.redundancy)
  lines.push("data_status_data_valid=" + data_status.data_valid)
  lines.push("data_status_provider_state=" + data_status.provider_state)
  lines.push("data_status_station_problem=" + data_status.station_problem)
  lines.push("data_status_ignore=" + data_status.ignore)
  lines.push(
    "transfer_status=0x" + @frame.uint16_to_hex(frame.transfer_status.to_int()),
  )
  lines.push("payload_length=" + frame.payload.length().to_string())
  lines.join("\n")
}

///|
pub fn decode_iam0_hex(hex : StringView) -> String raise {
  let data = @frame.bytes_from_hex(hex)
  let iam0 = @io.parse_iam0(data, 0)
  @io.format_iam0(iam0)
}

// ── Record hex facade ───────────────────────────────────────────

///|
pub fn encode_record_read_hex(slot : Int, subslot : Int, index : Int) -> String {
  let req = @record.IODReadReqHeader::{
    seq_number: 0,
    ar_uuid: @rpc.Uuid::empty(),
    api: 0,
    slot_number: slot,
    subslot_number: subslot,
    index,
    record_data_length: 0,
  }
  @frame.bytes_to_hex(@record.encode_iod_read_req_header(req), separator="")
}

///|
pub fn format_record_read_req(slot : Int, subslot : Int, index : Int) -> String {
  let req = @record.IODReadReqHeader::{
    seq_number: 0,
    ar_uuid: @rpc.Uuid::empty(),
    api: 0,
    slot_number: slot,
    subslot_number: subslot,
    index,
    record_data_length: 0,
  }
  @record.format_iod_read_req(req)
}

// ── SNMP hex facade ─────────────────────────────────────────────

///|
pub fn encode_snmp_get_hex(oid : String, community : String) -> String {
  let msg = @snmp.build_get_request(community, 1, oid)
  @frame.bytes_to_hex(@snmp.encode_snmp_message(msg), separator="")
}

// ── LLDP hex facade ─────────────────────────────────────────────

///|
pub fn decode_lldp_hex(hex : StringView) -> String raise {
  let data = @frame.bytes_from_hex(hex)
  let tlvs = @lldp.parse_lldp_tlvs(data, 0)
  let neighbor = @lldp.extract_neighbor(tlvs)
  @lldp.format_neighbor(neighbor)
}

// ── DHCP hex facade ─────────────────────────────────────────────

///|
pub fn decode_dhcp_hex(hex : StringView) -> String raise {
  let data = @frame.bytes_from_hex(hex)
  let msg = @dhcp.parse_dhcp_message(data)
  @dhcp.format_dhcp_message(msg)
}

///|
pub fn encode_dhcp_discover_hex(
  mac : StringView,
  hostname : String,
) -> String raise {
  let mac_addr = @frame.MacAddress::from_hex(mac)
  let mac_bytes = mac_addr.octets()
  let msg = @dhcp.build_discover(mac_bytes, 0x12345678, hostname~)
  @frame.bytes_to_hex(@dhcp.encode_dhcp_message(msg), separator="")
}