{"id":37124280,"url":"https://github.com/nervsystems/cotlib","last_synced_at":"2026-01-14T14:21:16.473Z","repository":{"id":291508975,"uuid":"924470249","full_name":"NERVsystems/cotlib","owner":"NERVsystems","description":"cotlib is a secure, high-performance Go library for parsing, validating, and generating Cursor-on-Target (CoT) XML messages.  It features a comprehensive, embedded type catalog with metadata and XSD catalogue, robust validation logic, and LLM/AI-friendly search APIs. Designed for reliability, composability, and security.","archived":false,"fork":false,"pushed_at":"2025-12-21T19:07:29.000Z","size":3073,"stargazers_count":6,"open_issues_count":4,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-22T18:56:56.416Z","etag":null,"topics":["ai","atak","code-mil","cot","cursor-on-target","geospatial","interoperability","llm","mcp","military","mitre","model-context-protocol","standards","tak","xml"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NERVsystems.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"security_report.json","support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.md","dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-01-30T04:09:05.000Z","updated_at":"2025-12-21T15:29:25.000Z","dependencies_parsed_at":"2025-05-22T10:08:13.236Z","dependency_job_id":"b5d211dd-3211-44fc-aaa3-830378f74655","html_url":"https://github.com/NERVsystems/cotlib","commit_stats":null,"previous_names":["nervsystems/cotlib","pdfinn/cotlib"],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/NERVsystems/cotlib","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NERVsystems%2Fcotlib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NERVsystems%2Fcotlib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NERVsystems%2Fcotlib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NERVsystems%2Fcotlib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NERVsystems","download_url":"https://codeload.github.com/NERVsystems/cotlib/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NERVsystems%2Fcotlib/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28422715,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T13:30:50.153Z","status":"ssl_error","status_checked_at":"2026-01-14T13:29:08.907Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","atak","code-mil","cot","cursor-on-target","geospatial","interoperability","llm","mcp","military","mitre","model-context-protocol","standards","tak","xml"],"created_at":"2026-01-14T14:21:15.632Z","updated_at":"2026-01-14T14:21:16.452Z","avatar_url":"https://github.com/NERVsystems.png","language":"Go","readme":"![Cursor On Target](cotlogo.png)\n\n'…we want the target dead or saved…we gotta get away from platform centric thinking…and we gotta focus on this thing where the sum of the wisdom is a cursor over the target…and we're indifferent [to the source]'  — Gen. John Jumper\n\n# CoT Library\n\n[![Go Report Card](https://goreportcard.com/badge/github.com/NERVsystems/cotlib)](https://goreportcard.com/report/github.com/NERVsystems/cotlib) [![CI](https://github.com/NERVsystems/cotlib/actions/workflows/ci.yml/badge.svg)](https://github.com/NERVsystems/cotlib/actions/workflows/ci.yml)\n\n\n\nA comprehensive Go library for creating, validating, and working with Cursor-on-Target (CoT) events.\n\n## Features\n\n- **High-performance processing**: Sub-microsecond event creation, millions of validations/sec\n- Complete CoT event creation and manipulation\n- XML serialization and deserialization with security protections\n- Full CoT type catalog with metadata\n- **Zero-allocation type lookups** and optimized memory usage\n- **How and relation value support** with comprehensive validation\n- Coordinate and spatial data handling\n- Event relationship management\n- Type validation and registration\n- Secure logging with slog\n- Thread-safe operations\n- Detail extensions with round-trip preservation\n- GeoChat message and receipt support\n- Predicate-based event classification\n- Security-first design\n- Wildcard pattern support for types\n- Type search by description or full name\n\n## Installation\n\n```bash\ngo get github.com/NERVsystems/cotlib\n```\n**Note:** Schema validation relies on the `libxml2` library and requires CGO to be enabled when building.\nSee [MIGRATION.md](MIGRATION.md) for guidance when upgrading from older versions.\n\n## Usage\n\n### Creating and Managing CoT Events\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"log/slog\"\n    \"os\"\n    \"github.com/NERVsystems/cotlib\"\n)\n\nfunc main() {\n    logger := slog.New(slog.NewTextHandler(os.Stdout, nil))\n\n    // Create a new CoT event\n    event, err := cotlib.NewEvent(\"UNIT-123\", \"a-f-G\", 37.422, -122.084, 0.0)\n    if err != nil {\n        logger.Error(\"Failed to create event\", \"error\", err)\n        return\n    }\n\n    // Add detail information\n    event.Detail = \u0026cotlib.Detail{\n        Contact: \u0026cotlib.Contact{\n            Callsign: \"ALPHA-7\",\n        },\n        Group: \u0026cotlib.Group{\n            Name: \"Team Blue\",\n            Role: \"Infantry\",\n        },\n    }\n\n    // Add relationship link\n    event.AddLink(\u0026cotlib.Link{\n        Uid:      \"HQ-1\",\n        Type:     \"a-f-G-U-C\",\n        Relation: \"p-p\",\n    })\n\n    // Convert to XML\n    xmlData, err := event.ToXML()\n    if err != nil {\n        logger.Error(\"Failed to convert to XML\", \"error\", err)\n        return\n    }\n\n    fmt.Println(string(xmlData))\n}\n```\n### Building Events with EventBuilder\n\n```go\nbuilder := cotlib.NewEventBuilder(\"B1\", \"a-f-G\", 34.0, -117.0, 0).\n    WithContact(\u0026cotlib.Contact{Callsign: \"ALPHA\"}).\n    WithGroup(\u0026cotlib.Group{Name: \"Team Blue\", Role: \"Infantry\"}).\n    WithStaleTime(time.Now().Add(10 * time.Second))\nevent, err := builder.Build()\nif err != nil {\n    log.Fatal(err)\n}\n_ = event\n```\n### Parsing CoT XML\n\n```go\npackage main\n\nimport (\n    \"errors\"\n    \"fmt\"\n    \"github.com/NERVsystems/cotlib\"\n)\n\nfunc main() {\n    xmlData := `\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cevent version=\"2.0\" uid=\"UNIT-123\" type=\"a-f-G\" time=\"2023-05-15T18:30:22Z\"\n       start=\"2023-05-15T18:30:22Z\" stale=\"2023-05-15T18:30:32Z\"\u003e\n  \u003cpoint lat=\"37.422000\" lon=\"-122.084000\" hae=\"0.0\" ce=\"9999999.0\" le=\"9999999.0\"/\u003e\n  \u003cdetail\u003e\n    \u003ccontact callsign=\"ALPHA-7\"/\u003e\n    \u003cgroup name=\"Team Blue\" role=\"Infantry\"/\u003e\n  \u003c/detail\u003e\n\u003c/event\u003e`\n\n    // Parse XML into CoT event\n    event, err := cotlib.UnmarshalXMLEvent(context.Background(), []byte(xmlData))\n    if err != nil {\n        fmt.Printf(\"Error parsing XML: %v\\n\", err)\n        return\n    }\n\n    // Access event data\n    fmt.Printf(\"Event Type: %s\\n\", event.Type)\n    fmt.Printf(\"Location: %.6f, %.6f\\n\", event.Point.Lat, event.Point.Lon)\n    fmt.Printf(\"Callsign: %s\\n\", event.Detail.Contact.Callsign)\n\n    // Check event predicates\n    if event.Is(\"friend\") {\n        fmt.Println(\"This is a friendly unit\")\n    }\n\n    if event.Is(\"ground\") {\n        fmt.Println(\"This is a ground-based entity\")\n    }\n}\n```\n\n#### Handling Detail Extensions\n\nCoT events often include TAK-specific extensions inside the `\u003cdetail\u003e` element.\n`cotlib` preserves many of these extensions and validates them using embedded TAKCoT schemas. These extensions go beyond canonical CoT and include elements such as:\n\n- `__chat`\n- `__chatReceipt`\n- `__chatreceipt`\n- `__geofence`\n- `__serverdestination`\n- `__video`\n- `__group`\n- `archive`\n- `attachmentList`\n- `environment`\n- `fileshare`\n- `precisionlocation`\n- `takv`\n- `track`\n- `mission`\n- `status`\n- `shape`\n- `strokecolor`\n- `strokeweight`\n- `fillcolor`\n- `labelson`\n- `uid`\n- `bullseye`\n- `routeInfo`\n- `color`\n- `hierarchy`\n- `link`\n- `usericon`\n- `emergency`\n- `height`\n- `height_unit`\n- `remarks`\n\nThe `remarks` extension now follows the MITRE *CoT Remarks Schema* and includes\na `\u003cremarks\u003e` root element, enabling validation through the\n`tak-details-remarks` schema.\n\nAll of these known TAK extensions are validated against embedded schemas when decoding and during event validation. Invalid XML will result in an error. Chat messages produced by TAK clients often include a `\u003cchatgrp\u003e` element inside `\u003c__chat\u003e`. `cotlib` first validates against the standard `chat` schema and automatically falls back to the TAK-specific `tak-details-__chat` schema so these messages are accepted.\n\nExample: adding a `shape` extension with a `strokeColor` attribute:\n\n```go\nevent.Detail = \u0026cotlib.Detail{\n    Shape: \u0026cotlib.Shape{Raw: []byte(`\u003cshape strokeColor=\"#00FF00\"/\u003e`)},\n}\n```\n\nAny unknown elements are stored in `Detail.Unknown` and serialized back\nverbatim.\nUnknown extensions are not validated. Although cotlib enforces XML size and depth limits, the data may still contain unexpected or malicious content. Treat these elements as untrusted and validate them separately if needed.\n\n```go\nxmlData := `\u003c?xml version=\"1.0\"?\u003e\n\u003cevent version=\"2.0\" uid=\"EXT-1\" type=\"t-x-c\" time=\"2023-05-15T18:30:22Z\" start=\"2023-05-15T18:30:22Z\" stale=\"2023-05-15T18:30:32Z\"\u003e\n  \u003cpoint lat=\"0\" lon=\"0\" ce=\"9999999.0\" le=\"9999999.0\"/\u003e\n  \u003cdetail\u003e\n    \u003c__chat chatroom=\"room\" groupOwner=\"false\" senderCallsign=\"Alpha\"\u003e\n      \u003cchatgrp id=\"room\" uid0=\"u0\"/\u003e\n    \u003c/__chat\u003e\n    \u003c__video url=\"http://example/video\"/\u003e\n  \u003c/detail\u003e\n\u003c/event\u003e`\n\nevt, _ := cotlib.UnmarshalXMLEvent(context.Background(), []byte(xmlData))\nout, _ := evt.ToXML()\nfmt.Println(string(out)) // prints the same XML\n```\n\nThe `id` attribute on `__chat` and `__chatreceipt` elements is optional.\n\n`Chat` now exposes additional fields such as `Chatroom`, `GroupOwner`,\n`SenderCallsign`, `Parent`, `MessageID` and a slice of `ChatGrp` entries\nrepresenting group membership.\n\n### GeoChat Messaging\n\n`cotlib` provides full support for GeoChat messages and receipts. The `Chat`\nstructure models the `__chat` extension including optional `\u003cchatgrp\u003e` elements\nand any embedded hierarchy. Incoming chat events automatically populate\n`Event.Message` from the `\u003cremarks\u003e` element. The `Marti` type holds destination\ncallsigns and `Remarks` exposes the message text along with the `source`, `to`,\nand `time` attributes.\n\nChat receipts are represented by the `ChatReceipt` structure which handles both\n`__chatReceipt` and TAK-specific `__chatreceipt` forms. Parsing falls back to the\nTAK schemas when required so messages from ATAK and WinTAK are accepted without\nextra handling.\n\nExample of constructing and serializing a chat message:\n\n```go\nevt, _ := cotlib.NewEvent(\"GeoChat.UID.Room.example\", \"b-t-f\", 0, 0, 0)\nevt.Detail = \u0026cotlib.Detail{\n    Chat: \u0026cotlib.Chat{\n        ID:             \"Room\",\n        Chatroom:       \"Room\",\n        GroupOwner:     \"false\",\n        SenderCallsign: \"Alpha\",\n        ChatGrps: []cotlib.ChatGrp{\n            {ID: \"Room\", UID0: \"AlphaUID\", UID1: \"BravoUID\"},\n        },\n    },\n    Marti: \u0026cotlib.Marti{Dest: []cotlib.MartiDest{{Callsign: \"Bravo\"}}},\n    Remarks: \u0026cotlib.Remarks{\n        Source: \"Example.Alpha\",\n        To:     \"Room\",\n        Text:   \"Hello team\",\n    },\n}\nout, _ := evt.ToXML()\n```\n\nNote: the `groupOwner` attribute is mandatory for TAK chat messages. It must be\npresent for schema validation to succeed when using the TAK chat format.\n\nDelivery or read receipts can be sent by populating `Detail.ChatReceipt` with\nthe appropriate `Ack`, `ID`, and `MessageID` fields.\n\n### Validator Package\n\nThe optional `validator` subpackage provides schema checks for common detail\nextensions. `validator.ValidateAgainstSchema` validates XML against embedded\nXSD files. `Event.Validate` automatically checks extensions such as\n`__chat`, `__chatReceipt`, `__group`, `__serverdestination`, `__video`,\n`attachment_list`, `usericon`, and the drawing-related details using these\nschemas. All schemas in this repository's `takcot/xsd` directory are embedded\nand validated, including those like `Route.xsd` that reference other files.\n\n### Type Validation and Catalog\n\nThe library provides comprehensive type validation and catalog management:\n\n```go\npackage main\n\nimport (\n    \"errors\"\n    \"fmt\"\n    \"log\"\n    \"github.com/NERVsystems/cotlib\"\n)\n\nfunc main() {\n    // Register a custom CoT type\n    if err := cotlib.RegisterCoTType(\"a-f-G-U-C-F\"); err != nil {\n        log.Fatal(err)\n    }\n\n    // Validate a CoT type\n    if err := cotlib.ValidateType(\"a-f-G-U-C-F\"); err != nil {\n        if errors.Is(err, cotlib.ErrInvalidType) {\n            log.Fatal(err)\n        }\n    }\n\n    // Look up type metadata\n    fullName, err := cotlib.GetTypeFullName(\"a-f-G-E-X-N\")\n    if err != nil {\n        log.Fatal(err)\n    }\n    fmt.Printf(\"Full name: %s\\n\", fullName)\n    // Output: Full name: Gnd/Equip/Nbc Equipment\n\n    // Get type description\n    desc, err := cotlib.GetTypeDescription(\"a-f-G-E-X-N\")\n    if err != nil {\n        log.Fatal(err)\n    }\n    fmt.Printf(\"Description: %s\\n\", desc)\n    // Output: Description: NBC EQUIPMENT\n\n    // Retrieve full type information\n    info, err := cotlib.GetTypeInfo(\"a-f-G-E-X-N\")\n    if err != nil {\n        log.Fatal(err)\n    }\n    fmt.Printf(\"%s - %s\\n\", info.FullName, info.Description)\n    // Output: Gnd/Equip/Nbc Equipment - NBC EQUIPMENT\n\n    // Batch lookup for multiple types\n    infos, err := cotlib.GetTypeInfoBatch([]string{\"a-f-G-E-X-N\", \"a-f-G-U-C\"})\n    if err != nil {\n        log.Fatal(err)\n    }\n    fmt.Printf(\"Batch size: %d\\n\", len(infos))\n\n    // Search for types by description\n    types := cotlib.FindTypesByDescription(\"NBC\")\n    for _, t := range types {\n        fmt.Printf(\"Found type: %s (%s)\\n\", t.Name, t.Description)\n    }\n\n    // Search for types by full name\n    types = cotlib.FindTypesByFullName(\"Equipment\")\n    for _, t := range types {\n        fmt.Printf(\"Found type: %s (%s)\\n\", t.Name, t.FullName)\n    }\n}\n```\n\n`catalog.Upsert` precomputes upper-case versions of each type's `FullName` and\n`Description`. `FindByDescription` and `FindByFullName` reuse these cached\nstrings so searches are allocation-free.\n\n### Type Validation\n\nThe library enforces strict validation of CoT types:\n- Basic syntax checking\n- Standard prefix validation\n- Length limits\n- Wildcard pattern validation\n- Type catalog verification\n- Automatic resolution of `f`, `h`, `n`, or `u` segments to catalog\n  entries containing `.`\n\n```go\n// Examples of different validation scenarios:\ncotlib.ValidateType(\"a-f-G\")             // Valid - Friendly Ground\ncotlib.ValidateType(\"b-m-r\")             // Valid - Route\ncotlib.ValidateType(\"invalid\")           // Error - Unknown type\n```\n\n### How and Relation Values\n\nThe library provides full support for CoT how values (indicating position source) and relation values (for event relationships):\n\n#### How Values\n\nHow values indicate the source or method of position determination:\n\n```go\npackage main\n\nimport (\n    \"errors\"\n    \"fmt\"\n    \"log\"\n    \"github.com/NERVsystems/cotlib\"\n)\n\nfunc main() {\n    // Create an event\n    event, _ := cotlib.NewEvent(\"UNIT-123\", \"a-f-G\", 37.422, -122.084, 0.0)\n    \n    // Set how value using descriptor (recommended)\n    err := cotlib.SetEventHowFromDescriptor(event, \"gps\")\n    if err != nil {\n        log.Fatal(err)\n    }\n    // This sets event.How to \"h-g-i-g-o\"\n    \n    // Or set directly if you know the code\n    event.How = \"h-e\" // manually entered\n    \n    // Validate how value\n    if err := cotlib.ValidateHow(event.How); err != nil {\n        if errors.Is(err, cotlib.ErrInvalidHow) {\n            log.Fatal(err)\n        }\n    }\n    \n    // Get human-readable description\n    desc, _ := cotlib.GetHowDescriptor(\"h-g-i-g-o\")\n    fmt.Printf(\"How: %s\\n\", desc) // Output: How: gps\n}\n```\n\n#### Relation Values\n\nRelation values specify the relationship type in link elements:\n\n```go\n// Add a validated link with parent-point relation\nerr := event.AddValidatedLink(\"HQ-1\", \"a-f-G-U-C\", \"p-p\")\nif err != nil {\n    if errors.Is(err, cotlib.ErrInvalidRelation) {\n        log.Fatal(err)\n    }\n}\n\n// Or add manually (validation happens during event.Validate())\nevent.AddLink(\u0026cotlib.Link{\n    Uid:      \"CHILD-1\",\n    Type:     \"a-f-G\",\n    Relation: \"p-c\", // parent-child\n})\n\n// Validate relation value\nif err := cotlib.ValidateRelation(\"p-c\"); err != nil {\n    if errors.Is(err, cotlib.ErrInvalidRelation) {\n        log.Fatal(err)\n    }\n}\n\n// Get relation description\ndesc, _ := cotlib.GetRelationDescription(\"p-p\")\nfmt.Printf(\"Relation: %s\\n\", desc) // Output: Relation: parent-point\n```\n\n#### Available Values\n\n**How values include:**\n- `h-e` (manual entry)\n- `h-g-i-g-o` (GPS)\n- `m-g` (GPS - MITRE)\n- And many others from both MITRE and TAK specifications\n\n**Relation values include:**\n- `c` (connected)\n- `p-p` (parent-point)\n- `p-c` (parent-child)  \n- `p` (parent - MITRE)\n- And many others from both MITRE and TAK specifications\n\n#### Validation\n\nEvent validation automatically checks how and relation values:\n\n```go\nevent.How = \"invalid-how\"\nerr := event.Validate() // Will fail\n\nevent.AddLink(\u0026cotlib.Link{\n    Uid:      \"test\",\n    Type:     \"a-f-G\", \n    Relation: \"invalid-relation\",\n})\nerr = event.Validate() // Will fail\n```\n\n### Custom Types\n\nYou can register custom type codes that extend the standard prefixes:\n\n```go\n// Register a custom type\ncotlib.RegisterCoTType(\"a-f-G-E-V-custom\")\n\n// Validate the custom type\nif err := cotlib.ValidateType(\"a-f-G-E-V-custom\"); err != nil {\n    log.Fatal(err)\n}\n\nctx := cotlib.WithLogger(context.Background(), logger)\n\n// Register types from a file\nif err := cotlib.RegisterCoTTypesFromFile(ctx, \"my-types.xml\"); err != nil {\n    log.Fatal(err)\n}\n\n// Register types from a string\nxmlContent := `\u003ctypes\u003e\n    \u003ccot cot=\"a-f-G-custom\"/\u003e\n    \u003ccot cot=\"a-h-A-custom\"/\u003e\n\u003c/types\u003e`\nif err := cotlib.RegisterCoTTypesFromXMLContent(ctx, xmlContent); err != nil {\n    log.Fatal(err)\n}\n```\n\n### Generating Type Metadata (`cotgen`)\n\nThe `cmd/cotgen` utility expands the CoT XML definitions and writes the\n`cottypes/generated_types.go` file used by the library. Ensure the\n`cot-types` directory (or `cottypes` as a fallback) is present, then run:\n\n```bash\ngo run ./cmd/cotgen\n# or simply\ngo generate ./cottypes\n```\n\nAdd your custom type entries to `cottypes/CoTtypes.xml` (or `cot-types/CoTtypes.xml`) before running the\ngenerator to embed them into the resulting Go code.\n\nThe test suite ensures `generated_types.go` is up to date. If it fails,\nregenerate the file with `go generate ./cottypes` and commit the result.\n\n## TAK Types and Extensions\n\nThe library supports both canonical MITRE CoT types and TAK-specific extensions. TAK types are maintained separately to ensure clear namespace separation and avoid conflicts with official MITRE specifications.\n\n### Adding New CoT Types\n\n**For MITRE/canonical types:** Add entries to `cottypes/CoTtypes.xml`\n**For TAK-specific types:** Add entries to `cottypes/TAKtypes.xml`\n\nThe generator automatically discovers and processes all `*.xml` files in the `cot-types/` directory (falling back to `cottypes/` if needed).\n\n### TAK Namespace\n\nAll TAK-specific types use the `TAK/` namespace prefix in their `full` attribute to distinguish them from MITRE types:\n\n```xml\n\u003c!-- TAK-specific types in cottypes/TAKtypes.xml --\u003e\n\u003ccot cot=\"b-t-f\" full=\"TAK/Bits/File\" desc=\"File Transfer\" /\u003e\n\u003ccot cot=\"u-d-f\" full=\"TAK/Drawing/FreeForm\" desc=\"Free Form Drawing\" /\u003e\n\u003ccot cot=\"t-x-c\" full=\"TAK/Chat/Message\" desc=\"Chat Message\" /\u003e\n```\n\n### Working with TAK Types\n\n```go\n// Check if a type is TAK-specific\ntyp, err := cottypes.GetCatalog().GetType(\"b-t-f\")\nif err != nil {\n    log.Fatal(err)\n}\n\nif cottypes.IsTAK(typ) {\n    fmt.Printf(\"%s is a TAK type: %s\\n\", typ.Name, typ.FullName)\n    // Output: b-t-f is a TAK type: TAK/Bits/File\n}\n\n// Search for TAK types specifically\ntakTypes := cottypes.GetCatalog().FindByFullName(\"TAK/\")\nfmt.Printf(\"Found %d TAK types\\n\", len(takTypes))\n\n// Validate TAK types\nif err := cotlib.ValidateType(\"b-t-f\"); err != nil {\n    log.Fatal(err) // TAK types are fully validated\n}\n```\n\n### Generator Workflow\n\n1. The generator scans `cot-types/*.xml` (or `cottypes/*.xml`) for type definitions\n2. Parses each XML file into the standard `\u003ctypes\u003e\u003ccot\u003e` structure  \n3. Validates TAK namespace integrity (no `a-` prefixes with `TAK/` full names)\n4. Expands MITRE wildcards (`a-.-`) but leaves TAK types unchanged\n5. Generates `cottypes/generated_types.go` with all types\n\n### Adding New Types\n\nTo add new CoT types to the catalog:\n\n1. **For MITRE types:** Edit `cottypes/CoTtypes.xml` (or `cot-types/CoTtypes.xml`)\n2. **For TAK extensions:** Edit `cottypes/TAKtypes.xml` (or `cot-types/TAKtypes.xml`)\n3. **For new categories:** Create a new XML file in `cottypes/` or `cot-types/`\n4. Run `go generate ./cottypes` to regenerate the catalog\n5. Verify with tests: `go test ./cottypes -v -run TestTAK`\n\nExample TAK type entry:\n```xml\n\u003ccot cot=\"b-m-p-c-z\" full=\"TAK/Map/Zone\" desc=\"Map Zone\" /\u003e\n```\n\n**Important:** TAK types should never use the `a-` prefix (reserved for MITRE affiliation-based types) and must always use the `TAK/` namespace prefix.\n\n### Event Predicates\n\nThe library provides convenient type classification with the `Is()` method:\n\n```go\n// Create a friendly ground unit event\nevent, _ := cotlib.NewEvent(\"test123\", \"a-f-G\", 30.0, -85.0, 0.0)\n\n// Check various predicates\nfmt.Printf(\"Is friendly: %v\\n\", event.Is(\"friend\"))  // true\nfmt.Printf(\"Is hostile: %v\\n\", event.Is(\"hostile\")) // false\nfmt.Printf(\"Is ground: %v\\n\", event.Is(\"ground\"))   // true\nfmt.Printf(\"Is air: %v\\n\", event.Is(\"air\"))         // false\n```\n\n### Thread Safety\n\nAll operations in the library are thread-safe. The type catalog uses internal synchronization to ensure safe concurrent access.\n\n### Security Features\n\nThe library implements several security measures:\n\n- XML parsing restrictions to prevent XXE attacks\n- Input validation on all fields\n- Coordinate range enforcement\n- Time field validation to prevent time-based attacks\n- Maximum value length controls\n- Configurable parser limits\n- UID values are limited to 64 characters and may not contain whitespace\n- Secure logging practices\n\n```go\n// Set maximum allowed length for XML attribute values\n// This protects against memory exhaustion attacks\ncotlib.SetMaxValueLen(500 * 1024) // 500KB limit\ncotlib.SetMaxXMLSize(2 \u003c\u003c 20)    // 2MB overall XML size\ncotlib.SetMaxElementDepth(32)    // nesting depth limit\ncotlib.SetMaxElementCount(10000) // total element limit\ncotlib.SetMaxTokenLen(1024)      // single token size\n```\n\n### Logging\n\nThe library uses `slog` for structured logging:\n- Debug level for detailed operations\n- Info level for normal events\n- Warn level for recoverable issues\n- Error level for critical problems\n\n```go\nlogger := slog.New(slog.NewTextHandler(os.Stdout, \u0026slog.HandlerOptions{\n    Level: slog.LevelDebug,\n}))\n\nctx := cotlib.WithLogger(context.Background(), logger)\nlog := cotlib.LoggerFromContext(ctx)\nlog.Info(\"logger ready\")\n```\n\n### Event Pooling\n\n`UnmarshalXMLEvent` reuses `Event` objects from an internal pool to reduce\nallocations. When you are done with an event, return it to the pool:\n\n```go\nevt, _ := cotlib.UnmarshalXMLEvent(context.Background(), data)\ndefer cotlib.ReleaseEvent(evt)\n```\n## Build Tags\n\nThe optional `novalidator` build tag disables XML schema validation. When this\ntag is provided, `ValidateAgainstSchema` becomes a no-op and always returns\n`nil`, so *any* XML is parsed without verification, including malformed or\nmalicious content.\n\nOnly use this tag when performance is critical and the input XML is already\ntrusted. Do **not** use it when processing untrusted or potentially invalid CoT,\nas skipping schema validation may expose your application to malformed data.\n\n```bash\ngo build -tags novalidator\n```\n\n\n## Benchmarks\n\nRun benchmarks with the standard Go tooling:\n\n```bash\ngo test -bench=. ./...\n```\n\nThis executes any `Benchmark...` functions across the module, allowing you to\nprofile serialization, validation, or other operations.\n\n## Performance\n\nThis library is optimized for high-performance CoT processing with minimal memory allocations:\n\n### Core Operations (Apple M4)\n\n| Operation | Speed | Allocations | Memory | Throughput |\n|-----------|--------|-------------|---------|------------|\n| **Event Creation** | 157.4 ns/op | 1 alloc | 288 B | ~6.4M events/sec |\n| **XML Generation** | 583.2 ns/op | 4 allocs | 360 B | ~1.7M events/sec |\n| **XML Parsing** | 5.08 μs/op | 73 allocs | 3.48 KB | ~197K events/sec |\n| **XML Decode w/ Limits** | 2.31 μs/op | 49 allocs | 2.62 KB | ~433K events/sec |\n\n### Type Validation\n\n| Type Pattern | Speed | Allocations | Throughput |\n|--------------|--------|-------------|------------|\n| **Simple Types** (`a-f-G`) | 21.9 ns/op | 0 allocs | ~45.7M validations/sec |\n| **Complex Types** (`a-f-G-E-X-N`) | 22.3 ns/op | 0 allocs | ~44.8M validations/sec |  \n| **Wildcards** (`a-f-G-*`) | 53.7 ns/op | 0 allocs | ~18.6M validations/sec |\n| **Atomic Wildcards** (`a-.-X`) | 32.3 ns/op | 0 allocs | ~31.0M validations/sec |\n\n### Catalog Operations\n\n| Operation | Speed | Allocations | Throughput |\n|-----------|--------|-------------|------------|\n| **Type Lookup** | 18.9 ns/op | 0 allocs | ~52.9M lookups/sec |\n| **Search by Description** | 67.4 μs/op | 0 allocs | ~14.8K searches/sec |\n| **Search by Full Name** | 104.4 μs/op | 0 allocs | ~9.6K searches/sec |\n\n### XML Schema Validation\n\n| Metric | Performance | Allocations | Throughput Range |\n|--------|-------------|-------------|------------------|\n| **Average** | 2.89 μs/op | 0 allocs | ~346K validations/sec |\n| **Fastest** | 2.25 μs/op | 0 allocs | ~444K validations/sec |\n| **Slowest** | 5.25 μs/op | 0 allocs | ~190K validations/sec |\n\n*Validation performance across 13 schema types (Contact, Track, Color, Environment, Precision Location, Shape, Event Point, Status, Video, Mission, TAK Version, Bullseye, Route Info)*\n\n### Key Performance Features\n\n- **Zero-allocation lookups**: Type catalog operations don't allocate memory\n- **Object pooling**: XML parsing reuses event objects to minimize GC pressure  \n- **Optimized validation**: Fast-path validation for common type patterns\n- **Efficient searching**: Pre-computed uppercase strings for case-insensitive search\n- **Minimal serialization overhead**: Direct byte buffer manipulation for XML generation\n\n### Real-World Scenarios\n\n**High-frequency tracking**: Process 200,000+ position updates per second\n**Bulk operations**: Validate millions of type codes with zero GC impact  \n**Memory-constrained environments**: Minimal allocation footprint\n**Low-latency systems**: Sub-microsecond event processing\n\n*Benchmarks run on Apple M4 with Go 1.21. Your mileage may vary by platform.*\n\n## Documentation\n\nFor detailed documentation and examples, see:\n- [GoDoc](https://pkg.go.dev/github.com/NERVsystems/cotlib)\n- [CoT Specification](https://www.mitre.org/sites/default/files/pdf/09_4937.pdf)\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## Project History\n\nOriginally created by [@pdfinn](https://github.com/pdfinn).\nAll core functionality and initial versions developed prior to organisational transfer.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnervsystems%2Fcotlib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnervsystems%2Fcotlib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnervsystems%2Fcotlib/lists"}