diff --git a/example/Demo.ipynb b/example/Demo.ipynb
new file mode 100644
index 0000000..0b9c5cf
--- /dev/null
+++ b/example/Demo.ipynb
@@ -0,0 +1,1337 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "7fd0a68d-08b1-4e51-91fe-7b6a28b3e9e1",
+ "metadata": {},
+ "source": [
+ "# Memento Demo"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "154a348b-b553-4901-9cd0-b8af1e68f834",
+ "metadata": {},
+ "source": [
+ "## Imports"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "1448051e-c0f0-4a60-8d51-5d2ba6d644ef",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from twosigma.memento import memento_function\n",
+ "import time"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b69fe0fe-365f-401b-9d26-8b435ec20bb0",
+ "metadata": {},
+ "source": [
+ "## Set up a Demo Sandbox (not normally necessary)\n",
+ "Expand and run this section if you wish to sandbox and reset the memoization state"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "a6bccc0c-1760-4270-882c-964e10c2c39e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from twosigma.memento import list_memoized_functions, Environment, ConfigurationRepository, forget_cluster\n",
+ "import os\n",
+ "from pathlib import Path\n",
+ "\n",
+ "demo_home = f\"{os.path.expanduser('~')}/.memento/env/memento_demo\"\n",
+ "Path.mkdir(Path(demo_home), parents=True, exist_ok=True)\n",
+ "Environment.set({\"name\": \"memento_demo\", \"base_dir\": demo_home})"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "6c6b03ad-3821-4573-bc95-39bf301ff8a2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "forget_cluster()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "52ee7606-0061-4e11-9c7d-ec065decf522",
+ "metadata": {},
+ "source": [
+ "## Hello, World\n",
+ "This demo shows caching in action. The function `hello` has an artificial 1 second delay which is clearly run the first time it encounters the \"hello\" input but not the second.\n",
+ "\n",
+ "Calling the function with a different input incurs the delay again, as it is a unique computation."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "0769dd65-0613-4f11-ad52-dc6d350f67c5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "@memento_function\n",
+ "def hello(n: str) -> str:\n",
+ " print(f\"Calculating for {n}...\")\n",
+ " time.sleep(1)\n",
+ " return f\"hello, {n}!\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "013530f7-9d70-48fe-b423-a3c5d1d902ee",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Calculating for world...\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "'hello, world!'"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "hello(\"world\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "96b4f5b5-fcb7-4658-9b61-3bebb1207470",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'hello, world!'"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "hello(\"world\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "85948e2d-29d3-4cc5-8b94-1409ed2c6b03",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Calculating for there...\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "'hello, there!'"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "hello(\"there\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3bc6194e-b4d8-4891-84fc-60b76c38542f",
+ "metadata": {},
+ "source": [
+ "Memento calculates a version of the function"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "bce812f3-e320-427b-84f9-366ced01206d",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'a3170059eeed6797'"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "v1 = hello.version()\n",
+ "v1"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "923b9a99-becc-4845-b431-6796a6bc99e8",
+ "metadata": {},
+ "source": [
+ "If we change the function, the version changes:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "9bc35c5f-298e-4ed3-97f2-8f99658d275a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "@memento_function\n",
+ "def hello(n: str) -> str:\n",
+ " print(f\"Calculating for {n}...\")\n",
+ " time.sleep(1)\n",
+ " return f\"Hello, {n.title()}!\" # Hello is captialized, and we use the title case for n as well"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "c7bd455d-f3f8-4dbe-990e-caa8a13ff83b",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'4b2ee18534d039f7'"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "v2 = hello.version()\n",
+ "v2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "324355f0-6f25-4a32-aeaf-cf75bf8b74ab",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Calculating for world...\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "'Hello, World!'"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "hello(\"world\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a7ff5c03-9093-4965-a15c-4144a8c9796a",
+ "metadata": {},
+ "source": [
+ "Now, if we change it back, the version goes back to what it was before"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "id": "8cb1c3a4-efcb-458d-ac08-36e8397cc728",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "@memento_function\n",
+ "def hello(n: str) -> str:\n",
+ " print(f\"Calculating for {n}...\")\n",
+ " time.sleep(1)\n",
+ " return f\"hello, {n}!\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "68f822c6-6c0a-4ab5-ab92-ee96b1223700",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'a3170059eeed6797'"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "v3 = hello.version()\n",
+ "v3"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "id": "19465222-8fa4-4382-bef0-fc9d89fa7f6e",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "v3 == v1"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "eb70dbc9-dd33-476a-a16b-189f196e1cff",
+ "metadata": {
+ "jp-MarkdownHeadingCollapsed": true
+ },
+ "source": [
+ "## Double and Add\n",
+ "This demo shows three functions, `increment(x)`, `double(x)`, and `increment_and_double(x)`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "id": "66f681dc-d8db-413d-9a6c-b6cb1f68f4db",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "@memento_function\n",
+ "def increment(x):\n",
+ " print(f\"increment({x})\")\n",
+ " return x + 1\n",
+ "\n",
+ "@memento_function\n",
+ "def double(x):\n",
+ " print(f\"double({x})\")\n",
+ " return x * 2\n",
+ "\n",
+ "@memento_function\n",
+ "def increment_and_double(x):\n",
+ " print(f\"increment_and_double({x})\")\n",
+ " return double(increment(x))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e727b85f-6e82-464d-b478-15b186ecea8e",
+ "metadata": {},
+ "source": [
+ "Basic usage"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "id": "657c2175-ffa8-47ed-a5fc-beb3fe22ea34",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "increment(1)\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "2"
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "increment(1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "id": "c02cbf91-f1ed-4771-afed-ee6a58bc8400",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "double(2)\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "4"
+ ]
+ },
+ "execution_count": 17,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "double(2)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e83e6d17-d4ed-4dc5-8e11-04558a16fbd0",
+ "metadata": {},
+ "source": [
+ "Now, we call increment_and_double"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "id": "2c64ac03-fc14-41a2-9bdb-fd10182f018d",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "increment_and_double(2)\n",
+ "increment(2)\n",
+ "double(3)\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "6"
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "increment_and_double(2)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4b900e40-b298-4000-8d4b-0613ff3df04d",
+ "metadata": {},
+ "source": [
+ "We can instruct Memento to graph the dependencies of `increment_and_double`, which it gets from static analysis of the code. This is the expected call graph (which can differ from the actual if branches are taken)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "id": "d37e37a6-b367-4b40-a17c-69639d389181",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 19,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "increment_and_double.dependencies()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1c5077c0-833c-40ab-8f7f-c29e1fc9bdc1",
+ "metadata": {},
+ "source": [
+ "We can introspect on the memento (the metadata artifact recorded when we called `increment_and_double(2)`)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "id": "31a44896-a95d-4d56-9465-24c044a608d6",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Memento(time=datetime.datetime(2024, 3, 31, 21, 13, 30, 18678, tzinfo=tzutc()), invocation_metadata=InvocationMetadata(fn_reference_with_args=FunctionReferenceWithArguments(fn_reference=FunctionReference('__main__:increment_and_double#eaa2b7f9012bc881', partial_args=(), partial_kwargs=None, external=False), args=(2,), kwargs={}, context_args={}), invocations=[FunctionReferenceWithArguments(fn_reference=FunctionReference('__main__:increment#b67215ccb618c9d0', partial_args=(), partial_kwargs=None, external=False), args=(2,), kwargs={}, context_args={}), FunctionReferenceWithArguments(fn_reference=FunctionReference('__main__:double#885a872da7be0a6d', partial_args=(), partial_kwargs=None, external=False), args=(3,), kwargs={}, context_args={})], runtime=datetime.timedelta(microseconds=4276), result_type=), function_dependencies={FunctionReference('__main__:double#885a872da7be0a6d', partial_args=(), partial_kwargs=None, external=False), FunctionReference('__main__:increment#b67215ccb618c9d0', partial_args=(), partial_kwargs=None, external=False), FunctionReference('__main__:increment_and_double#eaa2b7f9012bc881', partial_args=(), partial_kwargs=None, external=False)}, runner={'type': 'local'}, correlation_id='cid_3810c7b9f91f', content_key=VersionedDataSourceKey(key='c/31068125b3d6543518fbb7ce7878b1db2ebfb1268f2af67483779f91f5c99530', version='146b29b5-3d13-495b-ac7c-418bbc1cb2cf'))"
+ ]
+ },
+ "execution_count": 20,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "increment_and_double.memento(2)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "30f43fcf-d667-4633-8bc6-fed6f419de79",
+ "metadata": {},
+ "source": [
+ "We can ask Memento to show what it actually observed from the call graph:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "id": "769c4f69-b8b3-40ea-8531-43fa4c8b8b14",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "increment_and_double.memento(2).graph()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fd6b8561-e2c4-4473-9ab7-c0a459c57033",
+ "metadata": {},
+ "source": [
+ "## Fizz Buzz Example\n",
+ "In this example, we implement Fizz Buzz, defined as follows:\n",
+ "```\n",
+ "Given an integer n, return a string array answer (1-indexed) where:\n",
+ "\n",
+ "answer[i] == \"FizzBuzz\" if i is divisible by 3 and 5.\n",
+ "answer[i] == \"Fizz\" if i is divisible by 3.\n",
+ "answer[i] == \"Buzz\" if i is divisible by 5.\n",
+ "answer[i] == i (as a string) if none of the above conditions are true.\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "id": "13363352-3237-4e9c-bba7-0bea0c2a3af9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "@memento_function\n",
+ "def fizz_buzz(n: int) -> list[str]:\n",
+ " print(f\"Calculating {n}\")\n",
+ " time.sleep(0.2)\n",
+ " if n == 0:\n",
+ " return []\n",
+ " answer = \"\"\n",
+ " if (n % 3) == 0:\n",
+ " answer += \"Fizz\"\n",
+ " if (n % 5) == 0:\n",
+ " answer += \"Buzz\"\n",
+ " return fizz_buzz(n-1) + [answer or str(n)]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "id": "d505d40f-6ffd-4478-bdca-219f2b8c83f0",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Calculating 1\n",
+ "Calculating 0\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "['1']"
+ ]
+ },
+ "execution_count": 23,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "fizz_buzz(1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "id": "c0b53630-291f-436d-83fb-c3f3b6cd012d",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['1']"
+ ]
+ },
+ "execution_count": 24,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "fizz_buzz(1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "id": "2bdc6994-f968-4e12-8936-bef8a6702997",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Calculating 5\n",
+ "Calculating 4\n",
+ "Calculating 3\n",
+ "Calculating 2\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "['1', '2', 'Fizz', '4', 'Buzz']"
+ ]
+ },
+ "execution_count": 25,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "fizz_buzz(5)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "id": "bc68c92a-3c53-4b62-8177-7c3c346c67c1",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Calculating 20\n",
+ "Calculating 19\n",
+ "Calculating 18\n",
+ "Calculating 17\n",
+ "Calculating 16\n",
+ "Calculating 15\n",
+ "Calculating 14\n",
+ "Calculating 13\n",
+ "Calculating 12\n",
+ "Calculating 11\n",
+ "Calculating 10\n",
+ "Calculating 9\n",
+ "Calculating 8\n",
+ "Calculating 7\n",
+ "Calculating 6\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "['1',\n",
+ " '2',\n",
+ " 'Fizz',\n",
+ " '4',\n",
+ " 'Buzz',\n",
+ " 'Fizz',\n",
+ " '7',\n",
+ " '8',\n",
+ " 'Fizz',\n",
+ " 'Buzz',\n",
+ " '11',\n",
+ " 'Fizz',\n",
+ " '13',\n",
+ " '14',\n",
+ " 'FizzBuzz',\n",
+ " '16',\n",
+ " '17',\n",
+ " 'Fizz',\n",
+ " '19',\n",
+ " 'Buzz']"
+ ]
+ },
+ "execution_count": 26,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "fizz_buzz(20)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "id": "866846a5-59fd-4f30-b288-2f74ee1315f0",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "m = fizz_buzz.memento(1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "id": "52b2efec-64e8-4af6-b628-0b4155b7d031",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[(0,),\n",
+ " (1,),\n",
+ " (2,),\n",
+ " (3,),\n",
+ " (4,),\n",
+ " (5,),\n",
+ " (6,),\n",
+ " (7,),\n",
+ " (8,),\n",
+ " (9,),\n",
+ " (10,),\n",
+ " (11,),\n",
+ " (12,),\n",
+ " (13,),\n",
+ " (14,),\n",
+ " (15,),\n",
+ " (16,),\n",
+ " (17,),\n",
+ " (18,),\n",
+ " (19,),\n",
+ " (20,)]"
+ ]
+ },
+ "execution_count": 28,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sorted([m.invocation_metadata.fn_reference_with_args.args for m in fizz_buzz.list_mementos()])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "id": "4b9f2e90-6f7a-4352-9233-9d72fe2b69a1",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 29,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "fizz_buzz.memento(20).graph()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "id": "c643653c-1968-4e92-bdf7-cfe5eea1b56f",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['1',\n",
+ " '2',\n",
+ " 'Fizz',\n",
+ " '4',\n",
+ " 'Buzz',\n",
+ " 'Fizz',\n",
+ " '7',\n",
+ " '8',\n",
+ " 'Fizz',\n",
+ " 'Buzz',\n",
+ " '11',\n",
+ " 'Fizz',\n",
+ " '13',\n",
+ " '14',\n",
+ " 'FizzBuzz']"
+ ]
+ },
+ "execution_count": 30,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "fizz_buzz(15)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}