{"id":13502171,"url":"https://github.com/i2y/mochi","last_synced_at":"2025-05-16T06:04:22.114Z","repository":{"id":23043544,"uuid":"26396554","full_name":"i2y/mochi","owner":"i2y","description":"Dynamically typed functional programming language","archived":false,"fork":false,"pushed_at":"2016-07-07T21:20:56.000Z","size":541,"stargazers_count":913,"open_issues_count":14,"forks_count":28,"subscribers_count":46,"default_branch":"master","last_synced_at":"2025-05-16T06:03:31.550Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","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/i2y.png","metadata":{"files":{"readme":"README.en.md","changelog":"CHANGES.txt","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-11-09T13:35:19.000Z","updated_at":"2025-05-10T15:20:27.000Z","dependencies_parsed_at":"2022-08-21T18:50:45.883Z","dependency_job_id":null,"html_url":"https://github.com/i2y/mochi","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i2y%2Fmochi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i2y%2Fmochi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i2y%2Fmochi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i2y%2Fmochi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/i2y","download_url":"https://codeload.github.com/i2y/mochi/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254478186,"owners_count":22077675,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-07-31T22:02:04.667Z","updated_at":"2025-05-16T06:04:22.086Z","avatar_url":"https://github.com/i2y.png","language":"Python","readme":"Mochi\n====\nMochi is a dynamically typed programming language for functional programming and actor-style programming.\n\nIts interpreter is written in Python3. The interpreter translates a program written in Mochi to Python3's AST / bytecode.\n\n## Features\n- Python-like syntax\n- Tail recursion optimization (self tail recursion only), and no loop syntax\n- Re-assignments are not allowed in function definition.\n- Basic collection type is a persistent data structure. (using Pyrsistent)\n- Pattern matching / Data types, like algebraic data types\n- Pipeline operator\n- Syntax sugar of anonymous function definition\n- Actor, like the actor of Erlang (using Eventlet)\n- Macro, like the traditional macro of Lisp\n- Builtin functions includes functions exported by itertools module, recipes, functools module and operator module\n\n\n## Examples\n### Factorial\n```python\ndef factorial(n, m):\n    if n == 1:\n        m\n    else:\n        factorial(n - 1, n * m)\n\n\nfactorial(10000, 1)\n# =\u003e 28462596809170545189064132121198688...\n\n# Or\n\ndef factorial:\n    n: factorial(n, 1)\n    0, acc: acc\n    n, acc: factorial(n - 1, acc * n)\n    \nfactorial(10000)\n# =\u003e 28462596809170545189064132121198688...\n```\n\n### FizzBuzz\n```python\ndef fizzbuzz(n):\n    match [n % 3, n % 5]:\n        [0, 0]: \"fizzbuzz\"\n        [0, _]: \"fizz\"\n        [_, 0]: \"buzz\"\n        _: n\n\nrange(1, 31)\n|\u003e map(fizzbuzz)\n|\u003e pvector()\n|\u003e print()\n```\n\n### Actor\n```python\ndef show():\n    receive:\n        message:\n            print(message)\n            show()\n\nactor = spawn(show)\n\nsend('foo', actor)\nactor ! 'bar' # send('bar', actor)\n\nsleep(1)\n# -\u003e foo\n# -\u003e bar\n\n\n'foo' !\u003e spawn(show)\n\nsleep(1)\n# -\u003e foo\n\n['foo', 'bar'] !\u0026\u003e spawn(show)\n# The meaning of the above is the same as the meaning of the following.\n# spawn(show) ! 'foo'\n# spawn(show) ! 'bar'\n\nsleep(1)\n# -\u003e foo\n# -\u003e bar\n\ndef show_loop():\n    receive:\n        [tag, value]:\n            print(tag, value)\n            show_loop()\n\nactor2 = spawn(show_loop)\n\nactor2 ! [\"bar\", 2000]\nsleep(1)\n# -\u003e bar 2000\n\n['foo', 1000] !\u003e spawn(show_loop)\nsleep(1)\n# -\u003e foo 1000\n\n[['foo', 1000],['bar', 2000]] !\u0026\u003e spawn(show_loop)\nsleep(1)\n# -\u003e foo 1000\n# -\u003e bar 2000\n```\n\n### Distributed Computing\n```python\n# comsumer.mochi\nfrom mochi.actor.mailbox import KombuMailbox, ZmqInbox, SQSMailbox\n\ndef consumer():\n    receive:\n        'exit':\n            print('exit!')\n        other:\n            print(other)\n            consumer()\n\nkombu_mailbox = KombuMailbox('sqs://\u003caccess_key_id\u003e@\u003csecret_access_key\u003e:80//',\n                             '\u003cqueue_name\u003e',\n                             dict(region='\u003cregion\u003e'))\nspawn_with_mailbox(consumer, kombu_mailbox)\n\nzmq_mailbox = ZmqInbox('tcp://*:9999')\nspawn_with_mailbox(consumer, zmq_mailbox)\n\nsqs_mailbox = SQSMailbox('\u003cqueue_name\u003e')\nspawn_with_mailbox(consumer, sqs_mailbox)\n\nwait_all()\n```\n\n\n```python\n# producer.mochi\nfrom mochi.actor.mailbox import KombuMailbox, ZmqOutbox, SQSMailbox\n\nkombu_mailbox = KombuMailbox('sqs://\u003caccess_key_id\u003e@\u003csecret_access_key\u003e:80//',\n                             '\u003cqueue_name\u003e',\n                             dict(region='\u003cregion\u003e'))\nkombu_mailbox ! [1, 2, 3]\nkombu_mailbox ! 'exit'\n\nzmq_mailbox = ZmqOutbox('tcp://localhost:9999')\nzmq_mailbox ! [4, 5, 6]\nzmq_mailbox ! 'exit'\n\nsqs_mailbox = SQSMailbox('\u003cqueue_name\u003e')\nsqs_mailbox ! [7, 8, 9]\nsqs_mailbox ! 'exit'\n```\n\n\n### Flask\n```python\nfrom flask import Flask\n\napp = Flask('demo')\n\n@app.route('/')\ndef hello():\n    'Hello World!'\n\napp.run()\n```\n\n### RxPY\n```python\n# usage: mochi -no-mp timer.mochi\n# original:\n# https://github.com/ReactiveX/RxPY/blob/master/examples/parallel/timer.py\n\nimport rx\nimport concurrent.futures\nimport time\n\nseconds = [5, 1, 2, 4, 3]\n\n\ndef sleep(t):\n    time.sleep(t)\n    return t\n\n\ndef output(result):\n    print('%d seconds' % result)\n\n\nwith concurrent.futures.ProcessPoolExecutor(5) as executor:\n    rx.Observable.from_(seconds)\n                 .flat_map((s) -\u003e executor.submit(sleep, s))\n                 .subscribe(output)\n\n# 1 seconds\n# 2 seconds\n# 3 seconds\n# 4 seconds\n# 5 seconds\n```\n\n### aif (Anaphoric macro)\n```python\nmacro aif(test, true_expr, false_expr):\n    quasi_quote:\n        it = unquote(test)\n        if it:\n            unquote(true_expr)\n        else:\n            unquote(false_expr)\n\naif([], first(it), \"empty\")\n# =\u003e \"empty\"\naif([10, 20], first(it), \"empty\")\n# =\u003e 10\n```\n\n## Requirements\nSee requiremetns.txt\n\n## Installation\n```sh\n$ pip3 install mochi\n```\n### Optional Installation\n```sh\n$ pip3 install flask Flask-RESTful Pillow RxPY  # to run the examples\n$ pip3 install kombu # to use KombuMailbox\n$ pip3 install boto # to use SQS as transport of KombuMailbox\n$ pip3 install boto3 # to use SQSMailbox\n```\n\nTh error of the following may occur when you run Mochi on PyPy.\n```\nImportError: Importing zmq.backend.cffi failed with version mismatch, 0.8.2 != 0.9.2\n```\n\nIn this case, please change the version of cffi to 0.8.2 using pip on PyPy.\n```sh\n$ pip3 uninstall cffi\n$ pip3 install cffi==0.8.2\n```\n\n## Usage\n\n### REPL\n```sh\n$ mochi\n\u003e\u003e\u003e\n```\n\n### loading and running a file\n```sh\n$ cat kinako.mochi\nprint('kinako')\n$ mochi kinako.mochi\nkinako\n$ mochi -no-mp kinako.mochi  # not apply eventlet's monkey patching\nkinako\n```\n\n### byte compilation\n```sh\n$ mochi -c kinako.mochi \u003e kinako.mochic\n```\n\n### running a byte-compiled file\n```sh\n$ mochi -e kinako.mochic\nkinako\n$ mochi -e -no-mp kinako.mochic  # not apply eventlet's monkey patching\nkinako\n```\n\n### generating .pyc\n```sh\n$ ls\nkagami.mochi\n$ cat kagami.mochi\nprint('kagami')\n$ mochi\n\u003e\u003e\u003e import kagami\nkagami\n\u003e\u003e\u003e exit()\n$ ls\nkagami.mochi kagami.pyc\n$ python3 kagami.pyc\nkagami\n```\n\nOr\n\n```sh\n$ mochi -pyc kagami.mochi \u003e kagami.pyc\n$ python3 kagami.pyc\nkagami\n$ mochi -pyc -no-mp kagami.mochi \u003e kagami.pyc  # not apply eventlet's monkey patching\n$ python3 kagami.pyc\nkagami\n```\n\n## Examples for each feature\n\n### Persistent data structures\n```python\n[1, 2, 3]\n# =\u003e pvector([1, 2, 3])\n\nv(1, 2, 3)\n# =\u003e pvector([1, 2, 3])\n\nvec = [1, 2, 3]\nvec2 = vec.set(0, 8)\n# =\u003e pvector([8, 2, 3]\nvec\n# =\u003e pvector([1, 2, 3])\n[x, y, z] = vec\nx # =\u003e 1\ny # =\u003e 2\nz # =\u003e 3\n\nget(vec, 0) # =\u003e 1\nget(vec, 0, 2) # =\u003e [1, 2]\n\nvec[0] # =\u003e 1\nvec[0:2] # =\u003e [1, 2]\n\n{'x': 100, 'y': 200}\n# =\u003e pmap({'y': 200, 'x': 100})\n\nma = {'x': 100, 'y': 200}\nma.get('x') # =\u003e 100\nma.x # =\u003e 100\nma['x'] # =\u003e 100\nma2 = ma.set('x', 10000)\n# =\u003e pmap({'y': 200, 'x': 10000})\nma # =\u003e pmap({'y': 200, 'x': 100})\nget(ma, 'y') # =\u003e 200\nma['y'] # =\u003e 200\n\nm(x=100, y=200)\n# =\u003e pmap({'y': 200, 'x': 100})\n\ns(1, 2, 3)\n# =\u003e pset([1, 2, 3])\n\nb(1, 2, 3)\n# =\u003e pbag([1, 2, 3])\n```\n\n### Function definitions\n```python\ndef hoge(x):\n    'hoge' + str(x)\n\nhoge(3)\n# =\u003e hoge3\n```\n\n### Pattern matching\n```python\nlis = [1, 2, 3]\n\n# Sequence pattern\nmatch lis:\n    [1, 2, x]: x\n    _: None\n# =\u003e 3\n\nmatch lis:\n    [1, \u0026rest]: rest\n    _: None\n\n# =\u003e pvector([2, 3])\n\n\nfoo_map = {'foo' : 'bar'}\n\n# Mapping pattern\nmatch foo_map:\n    {'foo' : value}: value\n    _: None\n# =\u003e 'bar'\n\n\n# Type pattern\n# \u003cname of variable refers to type\u003e \u003cpattern\u003e: \u003caction\u003e\nmatch 10:\n    int x: 'int'\n    float x: 'float'\n    str x: 'str'\n    bool x: 'bool'\n    _: 'other'\n# =\u003e 'int'\n\nmatch [1, 2, 3]:\n    [1, str x, 3]: 'str'\n    [1, int x, 3]: 'int'\n    _: 'other'\n# =\u003e 'int'\n\nnum = union(int, float)\nvector nums[num]\nvector strs[str]\n\nmatch nums([1, 2, 3]):\n    nums[x, y, z]: z\n    strs[x, y, z]: x\n# =\u003e 3\n\nPositive = predicate(-\u003e $1 \u003e 0)\nEven = predicate(-\u003e $1 % 2 == 0)\nEvenAndPositive = predicate(-\u003e ($1 % 2 == 0) and ($1 \u003e= 0)) \n\nmatch 10:\n    EvenAndPositive n: str(n) + ':Even and Positive'\n    Even n: str(n) + ':Even'\n    Positive n: str(n) + ':Positive'\n\n# =\u003e 10:Even and Positive\n\n\n# Or pattern\nmatch ['foo', 100]:\n    ['foo' or 'bar', value]: value\n    _: 10000\n# =\u003e 100\n\nmatch ['foo', 100]:\n    [str x or int x, value]: value\n    _: 10000\n# =\u003e 100\n\n\n# Record pattern\nrecord Person(name, age)\n\nfoo = Person('foo', 32)\n\nmatch foo:\n    Person('bar', age):\n        'bar:' + str(age)\n    Person('foo', age):\n        'foo:' + str(age)\n    _: None\n# =\u003e 'foo:32'\n```\n\n### Records\n```python\nrecord Mochi\nrecord AnkoMochi(anko) \u003c Mochi\nrecord KinakoMochi(kinako) \u003c Mochi\n\nanko_mochi = AnkoMochi(anko=3)\n\nisinstance(anko_mochi, Mochi)\n# =\u003e True\nisinstance(anko_mochi, AnkoMochi)\n# =\u003e True\nisinstance(anko_mochi, KinakoMochi)\n# =\u003e False\n\nmatch anko_mochi:\n    KinakoMochi(kinako): 'kinako ' * kinako + ' mochi'\n    AnkoMochi(anko): 'anko ' * anko + 'mochi'\n    Mochi(_): 'mochi'\n# =\u003e 'anko anko anko mochi'\n\n\nrecord Person(name, age):\n    def show(self):\n        print(self.name + ': ' + self.age)\n\nfoo = Person('foo', '32')\nfoo.show()\n# -\u003e foo: 32\n\n# runtime type checking\nrecord Point(x:int, y:int, z:optional(int))\nPoint(1, 2, None)\n# =\u003e Point(x=1, y=2, z=None)\nPoint(1, 2, 3)\n# =\u003e Point(x=1, y=2, z=3)\nPoint(1, None, 3)\n# =\u003e TypeError\n```\n\n### Bindings\n```python\nx = 3000\n# =\u003e 3000\n\n[a, b] = [1, 2]\na\n# =\u003e 1\nb\n# =\u003e 2\n\n[c, \u0026d] = [1, 2, 3]\nc\n# =\u003e 1\nd\n# =\u003e pvector([2, 3])\n```\n\n### Data types, like algebraic data types\n```python\ndata Point:\n    Point2D(x, y)\n    Point3D(x, y, z)\n\n# The meaning of the above is the same as the meaning of the following.\n# record Point\n# record Point2D(x, y) \u003c Point\n# record Point3D(x, y, z) \u003c Point\n\np1 = Point2D(x=1, y=2)\n# =\u003e Point2D(x=1, y=2)\n\np2 = Point2D(3, 4)\n# =\u003e Point2D(x=3, y=4)\n\np1.x\n# =\u003e 1\n```\n\n### Pattern-matching function definitions\n```python\ndata Point:\n    Point2D(x, y)\n    Point3D(x, y, z)\n\ndef offset:\n    Point2D(x1, y1), Point2D(x2, y2):\n        Point2D(x1 + x2, y1 + y2)\n    Point3D(x1, y1, z1), Point3D(x2, y2, z2):\n        Point3D(x1 + x2, y1 + y2, z1 + z2)\n    _: None\n\noffset(Point2D(1, 2), Point2D(3, 4))\n# =\u003e Point2D(x=4, y=6)\noffset(Point3D(1, 2, 3), Point3D(4, 5, 6))\n# =\u003e Point3D(x=5, y=7, z=9)\n\ndef show:\n    int x, message: print('int', x, message)\n    float x, message: print('float', x, message)\n    _: None\n\nshow(1.0, 'msg')\n# -\u003e float 1.0 msg\n# =\u003e None\n\nFileMode = options('r', 'w', 'a', 'r+', 'w+', 'a+')\n\ndef open_file:\n    str path, FileMode mode: \n        open(path, mode)\n    str path:\n        open(path, 'r')\n```\n\n### Anonymous function\n```python\n# Arrow expression.\nadd = (x, y) -\u003e x + y\nadd(1, 2)\n# =\u003e 3\n\nadd = -\u003e $1 + $2\nadd(1, 2)\n# =\u003e 3\n\nfoo = (x, y) -\u003e\n    if x == 0:\n        y\n    else:\n        x\n\nfoo(1, 2)\n# =\u003e 1\n\nfoo(0, 2)\n# =\u003e 2\n\npvector(map(-\u003e $1 * 2, [1, 2, 3]))\n# =\u003e pvector([2, 4, 6])\n```\n\n### Pipeline operator \n```python\nadd = -\u003e $1 + $2\n2 |\u003e add(10) |\u003e add(12)\n# =\u003e 24\nNone |\u003e? add(10) |\u003e? add(12)\n# =\u003e None\n```\n\n### Lazy sequences\n```python\ndef fizzbuzz(n):\n    match [n % 3, n % 5]:\n        [0, 0]: \"fizzbuzz\"\n        [0, _]: \"fizz\"\n        [_, 0]: \"buzz\"\n        _: n\n\n\nresult = range(1, 31) |\u003e map(fizzbuzz)\npvector(result)\n# =\u003e pvector([1, 2, fizz, 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz', 16, 17, 'fizz', 19, 'buzz', 'fizz', 22, 23, 'fizz', 'buzz', 26, 'fizz', 28, 29, 'fizzbuzz'])\npvector(result)\n# =\u003e pvector([])\npvector(result)\n# =\u003e pvector([])\n\n\n# Iterator -\u003e lazyseq\nlazy_result = range(1, 31) |\u003e map(fizzbuzz) |\u003e lazyseq()\npvector(lazy_result)\n# =\u003e pvector([1, 2, fizz, 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz', 16, 17, 'fizz', 19, 'buzz', 'fizz', 22, 23, 'fizz', 'buzz', 26, 'fizz', 28, 29, 'fizzbuzz'])\npvector(lazy_result)\n# =\u003e pvector([1, 2, fizz, 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz', 16, 17, 'fizz', 19, 'buzz', 'fizz', 22, 23, 'fizz', 'buzz', 26, 'fizz', 28, 29, 'fizzbuzz'])\npvector(lazy_result)\n# =\u003e pvector([1, 2, fizz, 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz', 16, 17, 'fizz', 19, 'buzz', 'fizz', 22, 23, 'fizz', 'buzz', 26, 'fizz', 28, 29, 'fizzbuzz'])\n```\n\n### Trailing closures\n```python\n# The following trailing closure expression is passed to a function as the function’s first argument.\nresult = map([1, 2, 3]) -\u003e\n    print($1)\n    $1 * 2\n\nprint(doall(result))\n\n# -\u003e 1\n# -\u003e 2\n# -\u003e 3\n# =\u003e pvector([2, 4, 6])\n\n\ndef foreach(closure, seq):\n    doall(filter(closure, seq))\n\n# The following trailing closure expression is passed to a function as the function’s first argument.\nforeach([1, 2, 3]) (item) -\u003e\n    new_item = item * 100\n    print(new_item)\n\n# -\u003e 100\n# -\u003e 200\n# -\u003e 300\n# =\u003e pvector([])\n\n# Or\n\ndef foreach(seq, closure):\n    doall(filter(closure, seq))\n\n# The following trailing closure expression is passed to a function as the function’s final argument.\nforeach([1, 2, 3]) @ (item) -\u003e\n    new_item = item * 100\n    print(new_item)\n\n# -\u003e 100\n# -\u003e 200\n# -\u003e 300\n# =\u003e pvector([])\n```\n\n### Short form for keyword arguments and dict keys\n```python\ndef foo(a, b, c):\n    a + b + c\n    \na = 1\nb = 2\nc = 3\n\n# This is the same as foo(a=a, b=b, c=c)\nfoo(=a, =b, =c))\n# =\u003e 6\n\n# This is the same as {'a': a, 'b': b}\n{=a, =b}\n# =\u003e pmap({'a': 1, 'b': 2})\n```\n\n### Macros\n```python\nmacro rest_if_first_is_true(first, \u0026args):\n     match first:\n         quote(True): quasi_quote(v(unquote_splicing(args)))\n         _: quote(False)\n\nrest_if_first_is_true(True, 1, 2, 3)\n# =\u003e pvector([1, 2, 3])\nrest_if_first_is_true(\"foo\", 1, 2, 3)\n# =\u003e False\n\nmacro pipeline(\u0026args):\n    [Symbol('|\u003e')] + args\n\npipeline([1, 2, 3],\n         map(-\u003e $1 * 2),\n         filter(-\u003e $1 != 2),\n         pvector())\n# =\u003e pvector([4, 6])\n```\n\n### Including a file at compile time\n```sh\n$ cat anko.mochi\nx = 10000\ny = 20000\n```\n\n```python\nrequire 'anko.mochi'\nx\n# =\u003e 10000\n\nx = 30000\n\nrequire 'anko.mochi' # include once at compile time\nx\n# =\u003e 30000\n```\n\n### Module\n```python\nmodule Math:\n    export add, sub\n    \n    def add(x, y):\n        x + y\n    \n    def sub(x, y):\n        x - y\n\nMath.add(1, 2)\n# =\u003e 3\n```\n\n```sh\n$ cat foobar.mochi\nfoo = 'foo'\nbar = 'bar'\n```\n\n```python\nrequire 'foobar.mochi'\n[foo, bar]\n# =\u003e pvector(['foo', 'bar'])\n\nfoo = 'foofoofoo'\n\nmodule X:\n    export foobar\n    require 'foobar.mochi'\n    def foobar:\n        [foo, bar]\n\nX.foobar()\n# =\u003e pvector(['foo', 'bar'])\n\n[foo, bar]\n# =\u003e pvector(['foofoofoo', 'bar'])\n```\n\n## TODO\n- Improve documentation\n- Improve parsing\n- Support type annotation\n\n## License\nMIT License\n\n## Contributors\nhttps://github.com/i2y/mochi/graphs/contributors\n","funding_links":[],"categories":["Python","Awesome Functional Python"],"sub_categories":["Languages"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fi2y%2Fmochi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fi2y%2Fmochi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fi2y%2Fmochi/lists"}