{"id":34024115,"url":"https://github.com/ciena/afkak","last_synced_at":"2026-04-04T12:59:41.891Z","repository":{"id":46296346,"uuid":"53896229","full_name":"ciena/afkak","owner":"ciena","description":"Kafka client written in Twisted Python","archived":false,"fork":false,"pushed_at":"2023-08-30T20:29:52.000Z","size":1651,"stargazers_count":32,"open_issues_count":14,"forks_count":24,"subscribers_count":7,"default_branch":"master","last_synced_at":"2026-02-13T13:53:29.069Z","etag":null,"topics":["kafka-client","python","twisted"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ciena.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.md","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-03-14T22:24:30.000Z","updated_at":"2024-08-02T17:52:04.000Z","dependencies_parsed_at":"2024-06-19T16:05:39.115Z","dependency_job_id":"ecc7e2b1-3443-47f1-ab86-04737a591012","html_url":"https://github.com/ciena/afkak","commit_stats":{"total_commits":668,"total_committers":20,"mean_commits":33.4,"dds":0.5209580838323353,"last_synced_commit":"ad39648b35dbe625cb6dc7b5f04a5848dbdbf1b0"},"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/ciena/afkak","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ciena%2Fafkak","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ciena%2Fafkak/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ciena%2Fafkak/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ciena%2Fafkak/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ciena","download_url":"https://codeload.github.com/ciena/afkak/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ciena%2Fafkak/sbom","scorecard":{"id":282692,"data":{"date":"2025-08-11","repo":{"name":"github.com/ciena/afkak","commit":"4853c52f4da3586851dd580585277e79f1babc4d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.1,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":7,"reason":"Found 5/7 approved changesets -- score normalized to 7","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/integration.yml:1","Warn: no topLevel permission defined: .github/workflows/unit.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/integration.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/ciena/afkak/integration.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/integration.yml:31: update your workflow using https://app.stepsecurity.io/secureworkflow/ciena/afkak/integration.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/integration.yml:40: update your workflow using https://app.stepsecurity.io/secureworkflow/ciena/afkak/integration.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/unit.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/ciena/afkak/unit.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/unit.yml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/ciena/afkak/unit.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/unit.yml:54: update your workflow using https://app.stepsecurity.io/secureworkflow/ciena/afkak/unit.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/unit.yml:57: update your workflow using https://app.stepsecurity.io/secureworkflow/ciena/afkak/unit.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/unit.yml:75: update your workflow using https://app.stepsecurity.io/secureworkflow/ciena/afkak/unit.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/unit.yml:80: update your workflow using https://app.stepsecurity.io/secureworkflow/ciena/afkak/unit.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/unit.yml:89: update your workflow using https://app.stepsecurity.io/secureworkflow/ciena/afkak/unit.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/unit.yml:106: update your workflow using https://app.stepsecurity.io/secureworkflow/ciena/afkak/unit.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/unit.yml:109: update your workflow using https://app.stepsecurity.io/secureworkflow/ciena/afkak/unit.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/integration.yml:48","Warn: pipCommand not pinned by hash: .github/workflows/unit.yml:37","Warn: pipCommand not pinned by hash: .github/workflows/unit.yml:65","Warn: pipCommand not pinned by hash: .github/workflows/unit.yml:97","Warn: pipCommand not pinned by hash: .github/workflows/unit.yml:117","Info:   0 out of  12 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   5 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact 20.10.0 not signed: https://api.github.com/repos/ciena/afkak/releases/32349237","Warn: release artifact 20.9.0 not signed: https://api.github.com/repos/ciena/afkak/releases/31010175","Warn: release artifact 19.10.0 not signed: https://api.github.com/repos/ciena/afkak/releases/20928350","Warn: release artifact 19.8.0 not signed: https://api.github.com/repos/ciena/afkak/releases/19669020","Warn: release artifact 19.8.0b2 not signed: https://api.github.com/repos/ciena/afkak/releases/19453765","Warn: release artifact 20.10.0 does not have provenance: https://api.github.com/repos/ciena/afkak/releases/32349237","Warn: release artifact 20.9.0 does not have provenance: https://api.github.com/repos/ciena/afkak/releases/31010175","Warn: release artifact 19.10.0 does not have provenance: https://api.github.com/repos/ciena/afkak/releases/20928350","Warn: release artifact 19.8.0 does not have provenance: https://api.github.com/repos/ciena/afkak/releases/19669020","Warn: release artifact 19.8.0b2 does not have provenance: https://api.github.com/repos/ciena/afkak/releases/19453765"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T16:19:31.752Z","repository_id":46296346,"created_at":"2025-08-17T16:19:31.752Z","updated_at":"2025-08-17T16:19:31.752Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31400460,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T10:20:44.708Z","status":"ssl_error","status_checked_at":"2026-04-04T10:20:06.846Z","response_time":60,"last_error":"SSL_read: 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":["kafka-client","python","twisted"],"created_at":"2025-12-13T16:05:12.962Z","updated_at":"2026-04-04T12:59:41.875Z","avatar_url":"https://github.com/ciena.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# \u003cimg src=\"docs/_static/afkak.png\" width=\"23\" height=\"36\" alt=\"\"\u003e Afkak: Twisted Python Kafka Client\n\n\u003ca href=\"https://pypi.org/projects/afkak\"\u003e\u003cimg src=\"https://img.shields.io/pypi/v/afkak.svg\" alt=\"PyPI\"\u003e\u003c/a\u003e\n\u003ca href=\"https://calver.org/\"\u003e\u003cimg src=\"https://img.shields.io/badge/calver-YY.MM.MICRO-22bfda.svg\" alt=\"calver: YY.MM.MICRO\"\u003e\u003c/a\u003e\n\u003ca href=\"./LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/pypi/l/afkak.svg\" alt=\"Apache 2.0\"\u003e\u003c/a\u003e\n\u003ca href=\"https://afkak.readthedocs.io/en/latest/\"\u003e\u003cimg src=\"https://readthedocs.org/projects/pip/badge/\" alt=\"Documentation\"\u003e\u003c/a\u003e\n\n\u003c!--\nEverything between the LONG_DESCRIPTION_START and LONG_DESCRIPTION_END\ncomments is taken as the package long_description by setup.py. Do not\nchange the formatting of these lines lest that break.\n--\u003e\n\u003c!-- LONG_DESCRIPTION_START --\u003e\n\nAfkak is a [Twisted](https://twistedmatrix.com/)-native [Apache Kafka](https://kafka.apache.org/) client library.\nIt provides support for:\n\n* Producing messages, with automatic batching and optional compression.\n* Consuming messages, with group coordination and automatic commit.\n\nLearn more in the **[documentation](https://afkak.readthedocs.io/en/latest/)**, download [from PyPI](https://pypi.org/projects/afkak), or review the [contribution guidelines](./CONTRIBUTING.md).\nPlease report any issues [on GitHub](https://github.com/ciena/afkak/issues).\n\n# Status\n\nAfkak supports these Pythons:\n\n- CPython 3.7, 3.8, and 3.9\n- PyPy3\n\nWe aim to support Kafka 1.1.\u003cvar\u003ex\u003c/var\u003e and later.\nIntegration tests are run against these Kafka broker versions:\n\n- 0.9.0.1\n- 1.1.1\n\nTesting against 2.0.0 is planned (see [#45](https://github.com/ciena/afkak/issues/45)).\n\nNewer broker releases will generally function, but not all Afkak features will work on older brokers.\nIn particular, the coordinated consumer won’t work before Kafka 0.9.0.1.\nWe don’t recommend deploying such old releases of Kafka anyway, as they have serious bugs.\n\n# Usage\n\n### High level\n\nNote: This code is not meant to be runnable. See [producer\\_example](./producer_example) and [consumer\\_example](./consumer_example) for runnable example code.\n\n```python\nfrom afkak.client import KafkaClient\nfrom afkak.consumer import Consumer\nfrom afkak.producer import Producer\nfrom afkak.common import (OFFSET_EARLIEST, PRODUCER_ACK_ALL_REPLICAS,\n    PRODUCER_ACK_LOCAL_WRITE)\n\nkClient = KafkaClient(\"localhost:9092\")\n\n# To send messages\nproducer = Producer(kClient)\nd1 = producer.send_messages(\"my-topic\", msgs=[b\"some message\"])\nd2 = producer.send_messages(\"my-topic\", msgs=[b\"takes a list\", b\"of messages\"])\n# To get confirmations/errors on the sends, add callbacks to the returned deferreds\nd1.addCallbacks(handleResponses, handleErrors)\n\n# To wait for acknowledgements\n# PRODUCER_ACK_LOCAL_WRITE : server will wait till the data is written to\n#                         a local log before sending response\n# [ the default ]\n# PRODUCER_ACK_ALL_REPLICAS : server will block until the message is committed\n#                            by all in sync replicas before sending a response\nproducer = Producer(kClient,\n                    req_acks=Producer.PRODUCER_ACK_LOCAL_WRITE,\n                    ack_timeout=2000)\n\nresponseD = producer.send_messages(\"my-topic\", msgs=[b\"message\"])\n\n# Using twisted's @inlineCallbacks:\nresponses = yield responseD\nif response:\n    print(response[0].error)\n    print(response[0].offset)\n\n# To send messages in batch: You can use a producer with any of the\n# partitioners for doing this. The following producer will collect\n# messages in batch and send them to Kafka after 20 messages are\n# collected or every 60 seconds (whichever comes first). You can\n# also batch by number of bytes.\n# Notes:\n# * If the producer dies before the messages are sent, the caller would\n# * not have had the callbacks called on the send_messages() returned\n# * deferreds, and so can retry.\n# * Calling producer.stop() before the messages are sent will\n# errback() the deferred(s) returned from the send_messages call(s)\nproducer = Producer(kClient, batch_send=True,\n                    batch_send_every_n=20,\n                    batch_send_every_t=60)\nresponseD1 = producer.send_messages(\"my-topic\", msgs=[b\"message\"])\nresponseD2 = producer.send_messages(\"my-topic\", msgs=[b\"message 2\"])\n\n# To consume messages\n# define a function which takes a list of messages to process and\n# possibly returns a deferred which fires when the processing is\n# complete.\ndef processor_func(consumer, messages):\n    #  Store_Messages_In_Database may return a deferred\n    result = store_messages_in_database(messages)\n    # record last processed message\n    consumer.commit()\n    return result\n\nthe_partition = 3  # Consume only from partition 3.\nconsumer = Consumer(kClient, \"my-topic\", the_partition, processor_func)\nd = consumer.start(OFFSET_EARLIEST)  # Start reading at earliest message\n# The deferred returned by consumer.start() will fire when an error\n# occurs that can't handled by the consumer, or when consumer.stop()\n# is called\nyield d\n\nconsumer.stop()\nkClient.close()\n```\n\n#### Keyed messages\n```python\nfrom afkak.client import KafkaClient\nfrom afkak.producer import Producer\nfrom afkak.partitioner import HashedPartitioner, RoundRobinPartitioner\n\nkafka = KafkaClient(\"localhost:9092\")\n\n# Use the HashedPartitioner so that the producer will use the optional key\n# argument on send_messages()\nproducer = Producer(kafka, partitioner_class=HashedPartitioner)\nproducer.send_messages(\"my-topic\", \"key1\", [b\"some message\"])\nproducer.send_messages(\"my-topic\", \"key2\", [b\"this method\"])\n\n\n```\n\n### Low level\n\n```python\nfrom afkak.client import KafkaClient\nkafka = KafkaClient(\"localhost:9092\")\nreq = ProduceRequest(topic=\"my-topic\", partition=1,\n    messages=[KafkaProtocol.encode_message(b\"some message\")])\nresps = afkak.send_produce_request(payloads=[req], fail_on_error=True)\nkafka.close()\n\nresps[0].topic      # b\"my-topic\"\nresps[0].partition  # 1\nresps[0].error      # 0 (hopefully)\nresps[0].offset     # offset of the first message sent in this request\n```\n\n# Install\n\nAfkak releases are [available on PyPI][afkak-pypi].\n\nBecause the Afkak dependencies [Twisted][twisted] and [python-snappy][python-snappy] have binary extension modules you will need to install the Python development headers for the interpreter you wish to use:\n\n[afkak-pypi]: https://pypi.python.org/pypi/afkak\n[twisted]: https://pypi.python.org/pypi/Twisted\n[python-snappy]: https://pypi.python.org/pypi/python-snappy\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003ctd\u003eDebian/Ubuntu:\n\u003ctd\u003e\u003ccode\u003esudo apt-get install build-essential python3-dev pypy3-dev libsnappy-dev\u003c/code\u003e\n\u003ctr\u003e\n\u003ctd\u003eOS X\n\u003ctd\u003e\u003ccode\u003ebrew install python pypy snappy\u003c/code\u003e\u003c/br\u003e\n\u003ccode\u003epip install virtualenv\u003c/code\u003e\u003c/td\u003e\n\u003c/table\u003e\n\nThen Afkak can be [installed with pip as usual][pip-install]:\n\n[pip-install]: https://packaging.python.org/en/latest/installing/\n\n# License\n\nCopyright 2013, 2014, 2015 David Arthur under Apache License, v2.0. See `LICENSE`\n\nCopyright 2014, 2015 Cyan, Inc. under Apache License, v2.0. See `LICENSE`\n\nCopyright 2015–2021 Ciena Corporation under Apache License, v2.0. See `LICENSE`\n\nThis project began as a port of the [kafka-python][kafka-python] library to Twisted.\n\n[kafka-python]: https://github.com/mumrah/kafka-python\n\nSee [AUTHORS.md](./AUTHORS.md) for the full contributor list.\n\n\u003c!-- LONG_DESCRIPTION_END --\u003e\n\n# Tests\n\nIn order to run Afkak's tests, you need to install the\ndependencies as specified in the [install](#install) section.\n\nThe Afkak test suite uses [Tox](https://tox.readthedocs.io) to execute the tests\nin all the supported Python versions.\nThe preferred method to run the tests is to install Tox in a virtual\nenvironment before running the tests:\n\n```shell\nmake venv\n```\n\n### Testing Strategy\n\nAfkak has two types of tests:\n\n* Unit tests — unit tests are fast tests.\n  They don't do I/O.\n\n* Integration tests — tests that run against a real Kafka broker.\n\n### Run the unit tests\n\nTo run all unit tests in all the supported Python versions (requires all\nthe versions to be installed in the system where the tests will run):\n\n```shell\nmake toxu\n```\n\nAlternatively, you might want to run unit tests in a list of specific\nPython versions:\n\n```shell\n.env/bin/tox -e py35-unit-snappy,py38-unit-snappy\n```\n\nPlease run the tests on the minimum and maximum supported Python versions\nbefore submitting a pull request.\n\n### Run the integration tests\n\nThe integration tests will actually start up real local ZooKeeper\ninstance and Kafka brokers, and send messages in using the client.\n\nThe makefile knows how to download several versions of Kafka.\nThis will run just the integration tests against Kafka 1.1.1:\n\n```shell\nKAFKA_VER=1.1.1 make toxi\n```\n\n### Run all the tests against the default Kafka version\n\n```shell\nmake toxa\n```\n\n### Run the integration tests against all the Kafka versions the Makefile knows about\n\n```shell\nmake toxik\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fciena%2Fafkak","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fciena%2Fafkak","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fciena%2Fafkak/lists"}