diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fc65c28..de9463d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.9", "3.13"] + python-version: ["3.10", "3.13"] steps: - uses: actions/checkout@v4 diff --git a/README.md b/README.md index 08559fe..754c2c3 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,9 @@ Game tree drawing tool for extensive form games that generates TikZ code, LaTeX documents, PDFs, and PNGs. +Pass in an extensive form game file in `.ef` format with layout formatting, and `draw_tree` will generate a visual representation of the game tree. +You can also pass in a file in `.efg` format, which will be converted to `.ef` internally, applying a default layout. + ## Installation Clone the repo and install the package using pip: @@ -14,7 +17,7 @@ pip install -e . ## Requirements -- Python 3.9+ (tested on 3.13) +- Python 3.10+ (tested on 3.13) - LaTeX with TikZ (for PDF/PNG generation) - (optional) ImageMagick or Ghostscript or Poppler (for PNG generation) @@ -73,18 +76,11 @@ generate_png('games/example.ef', output_png='mygame.png', scale_factor=0.8) # ### Rendering in Jupyter Notebooks -First install the requirements, which include the `jupyter-tikz` extension: -```bash -pip install -r requirements.txt -``` - In a Jupyter notebook, run: ```python -%load_ext jupyter_tikz from draw_tree import draw_tree -example_tikz = draw_tree('games/example.ef') -get_ipython().run_cell_magic("tikz", "", example_tikz) +draw_tree('games/example.ef') ``` ## Developer docs: Testing diff --git a/pyproject.toml b/pyproject.toml index 6ef4d10..ca3c578 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,8 +25,10 @@ classifiers = [ ] keywords = ["game theory", "tikz", "visualization", "trees", "economics"] +# Required runtime dependencies (previously optional under the 'jupyter' extra) +dependencies = ["jupyter-tikz", "ipykernel"] + [project.optional-dependencies] -jupyter = ["jupyter-tikz", "ipykernel"] dev = ["pytest>=7.0.0", "pytest-cov"] [project.scripts] diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index ee4fa39..0000000 --- a/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -jupyter-tikz -ipykernel -pytest>=7.0.0 -pytest-cov \ No newline at end of file diff --git a/src/draw_tree/__init__.py b/src/draw_tree/__init__.py index dd60563..eef1210 100644 --- a/src/draw_tree/__init__.py +++ b/src/draw_tree/__init__.py @@ -9,6 +9,7 @@ from .core import ( draw_tree, + generate_tikz, generate_tex, generate_pdf, generate_png, @@ -19,6 +20,7 @@ __all__ = [ "draw_tree", + "generate_tikz", "generate_tex", "generate_pdf", "generate_png", diff --git a/src/draw_tree/core.py b/src/draw_tree/core.py index 39c46af..4ad4a84 100644 --- a/src/draw_tree/core.py +++ b/src/draw_tree/core.py @@ -15,6 +15,7 @@ from pathlib import Path from typing import List, Optional +from IPython.core.getipython import get_ipython # Constants DEFAULTFILE: str = "example.ef" @@ -1250,7 +1251,7 @@ def ef_to_tex(ef_file: str, scale_factor: float = 1.0, show_grid: bool = False) scale = original_scale grid = original_grid -def draw_tree(ef_file: str, scale_factor: float = 1.0, show_grid: bool = False) -> str: +def generate_tikz(ef_file: str, scale_factor: float = 1.0, show_grid: bool = False) -> str: """ Generate complete TikZ code from an extensive form (.ef) file. @@ -1323,6 +1324,39 @@ def draw_tree(ef_file: str, scale_factor: float = 1.0, show_grid: bool = False) return tikz_code +def draw_tree(ef_file: str, scale_factor: float = 1.0, show_grid: bool = False) -> Optional[str]: + """ + Generate TikZ code and display in Jupyter notebooks. + + Args: + ef_file: Path to the .ef file to process. + scale_factor: Scale factor for the diagram (default: 1.0). + show_grid: Whether to show grid lines (default: False). + + Returns: + The result of the Jupyter cell magic execution, or the TikZ code string + if cell magic fails. + """ + # Ensure we are in a Jupyter notebook environment + ip = get_ipython() + if ip: + # Only attempt to load the extension if it's not already loaded + em = getattr(ip, 'extension_manager', None) + loaded = getattr(em, 'loaded', None) + try: + jpt_loaded = 'jupyter_tikz' in loaded # type: ignore + except Exception: + jpt_loaded = False + if not jpt_loaded: + ip.run_line_magic("load_ext", "jupyter_tikz") + + # Generate TikZ code and execute cell magic + tikz_code = generate_tikz(ef_file, scale_factor, show_grid) + return ip.run_cell_magic("tikz", "", tikz_code) + else: + raise EnvironmentError("draw_tree function requires a Jupyter notebook environment.") + + def latex_wrapper(tikz_code: str) -> str: """ Wrap TikZ code in a complete LaTeX document. @@ -1391,8 +1425,8 @@ def generate_tex(ef_file: str, output_tex: Optional[str] = None, scale_factor: f except Exception: pass - # Generate TikZ content using draw_tree - tikz_content = draw_tree(ef_file, scale_factor, show_grid) + # Generate TikZ content using generate_tikz + tikz_content = generate_tikz(ef_file, scale_factor, show_grid) # Wrap in complete LaTeX document latex_document = latex_wrapper(tikz_content) @@ -1430,8 +1464,8 @@ def generate_pdf(ef_file: str, output_pdf: Optional[str] = None, scale_factor: f ef_path = Path(ef_file) output_pdf = ef_path.with_suffix('.pdf').name - # Generate TikZ content using draw_tree - tikz_content = draw_tree(ef_file, scale_factor, show_grid) + # Generate TikZ content using generate_tikz + tikz_content = generate_tikz(ef_file, scale_factor, show_grid) # Create LaTeX wrapper document latex_document = latex_wrapper(tikz_content) @@ -2233,7 +2267,7 @@ def emit_node(n: 'DefaultLayout.Node'): def efg_to_ef(efg_file: str) -> str: - """Convert a Gambit .efg file to the `.ef` format used by draw_tree. + """Convert a Gambit .efg file to the `.ef` format used by generate_tikz. The function implements a focused parser and deterministic layout heuristics for producing `.ef` directives from a conservative subset of diff --git a/tests/test_drawtree.py b/tests/test_drawtree.py index d2ecf3a..85e44bf 100644 --- a/tests/test_drawtree.py +++ b/tests/test_drawtree.py @@ -263,7 +263,7 @@ def test_draw_tree_basic(self): ef_file_path = ef_file.name try: - result = draw_tree.draw_tree(ef_file_path) + result = draw_tree.generate_tikz(ef_file_path) # Verify the result contains expected components assert isinstance(result, str) @@ -282,6 +282,69 @@ def test_draw_tree_basic(self): finally: os.unlink(ef_file_path) + def test_draw_tree_raises_when_no_ipython(self): + """When IPython is not available, draw_tree should raise EnvironmentError.""" + with patch('draw_tree.core.get_ipython', return_value=None): + with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.ef') as ef_file: + ef_file.write("player 1\n") + ef_file.write("level 0 node root player 1\n") + ef_file_path = ef_file.name + try: + with pytest.raises(EnvironmentError): + draw_tree.draw_tree(ef_file_path) + finally: + os.unlink(ef_file_path) + + def test_draw_tree_calls_ipython_magic_when_available(self): + """When IPython is available, draw_tree should load the jupyter_tikz + extension if needed and call the tikz cell magic with the generated code. + """ + # Create a simple .ef file for testing + with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.ef') as ef_file: + ef_file.write("player 1\n") + ef_file.write("level 0 node root player 1\n") + ef_file_path = ef_file.name + + class DummyEM: + def __init__(self, loaded=None): + self.loaded = loaded or set() + + class DummyIP: + def __init__(self, em): + self.extension_manager = em + self._loaded_magics = [] + self._run_cell_magic_calls = [] + + def run_line_magic(self, name, arg): + # record that load_ext was called + self._loaded_magics.append((name, arg)) + + def run_cell_magic(self, magic_name, args, code): + # record call and return a sentinel + self._run_cell_magic_calls.append((magic_name, args, code)) + return "MAGIC-RESULT" + + try: + # Case 1: extension already loaded + em = DummyEM(loaded={'jupyter_tikz'}) + ip = DummyIP(em) + with patch('draw_tree.core.get_ipython', return_value=ip): + res = draw_tree.draw_tree(ef_file_path) + # Should call run_cell_magic and return its value + assert res == "MAGIC-RESULT" + + # Case 2: extension not loaded -> run_line_magic should be called + em2 = DummyEM(loaded=set()) + ip2 = DummyIP(em2) + with patch('draw_tree.core.get_ipython', return_value=ip2): + res2 = draw_tree.draw_tree(ef_file_path) + assert res2 == "MAGIC-RESULT" + # run_line_magic should have been called to load the extension + assert ('load_ext', 'jupyter_tikz') in ip2._loaded_magics + + finally: + os.unlink(ef_file_path) + def test_draw_tree_with_options(self): """Test draw_tree with different options.""" # Create a simple .ef file for testing @@ -292,15 +355,15 @@ def test_draw_tree_with_options(self): try: # Test with scale - result_scaled = draw_tree.draw_tree(ef_file_path, scale_factor=2.0) + result_scaled = draw_tree.generate_tikz(ef_file_path, scale_factor=2.0) assert "scale=2" in result_scaled # Test with grid - result_grid = draw_tree.draw_tree(ef_file_path, show_grid=True) + result_grid = draw_tree.generate_tikz(ef_file_path, show_grid=True) assert "\\draw [help lines, color=green]" in result_grid # Test without grid (default) - result_no_grid = draw_tree.draw_tree(ef_file_path, show_grid=False) + result_no_grid = draw_tree.generate_tikz(ef_file_path, show_grid=False) assert "% \\draw [help lines, color=green]" in result_no_grid finally: @@ -310,7 +373,7 @@ def test_draw_tree_missing_files(self): """Test draw_tree with missing files.""" # Test with missing .ef file with pytest.raises(FileNotFoundError): - draw_tree.draw_tree("nonexistent.ef") + draw_tree.generate_tikz("nonexistent.ef") # Test with valid .ef file (should work with built-in macros) with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.ef') as ef_file: @@ -318,7 +381,7 @@ def test_draw_tree_missing_files(self): ef_file_path = ef_file.name try: - result = draw_tree.draw_tree(ef_file_path) + result = draw_tree.generate_tikz(ef_file_path) # Should work with built-in macros assert "\\begin{tikzpicture}" in result assert "\\newcommand\\chancecolor{red}" in result diff --git a/tutorial/basic_usage.ipynb b/tutorial/basic_usage.ipynb index f4912fc..c11f4f6 100644 --- a/tutorial/basic_usage.ipynb +++ b/tutorial/basic_usage.ipynb @@ -2,70 +2,18 @@ "cells": [ { "cell_type": "code", - "execution_count": 5, - "id": "733a7ced", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The jupyter_tikz extension is already loaded. To reload it, use:\n", - " %reload_ext jupyter_tikz\n" - ] - } - ], - "source": [ - "%load_ext jupyter_tikz" - ] - }, - { - "cell_type": "code", - "execution_count": 6, + "execution_count": 1, "id": "162e2935", "metadata": {}, "outputs": [], "source": [ - "from draw_tree import draw_tree, generate_tex, generate_pdf, generate_png\n", - "\n", - "from IPython import get_ipython" + "from draw_tree import draw_tree, generate_tex, generate_pdf, generate_png" ] }, { "cell_type": "code", - "execution_count": 7, - "id": "26ae62eb", - "metadata": {}, - "outputs": [], - "source": [ - "example_games = [\n", - " \"efg/one_card_poker.efg\",\n", - " \"efg/trust_game.efg\",\n", - " \"efg/2smp.efg\",\n", - " \"efg/2s2x2x2.efg\",\n", - " \"efg/cent2.efg\",\n", - " \"one_card_poker.ef\",\n", - " \"2smp.ef\",\n", - " \"2s2x2x2.ef\",\n", - " \"cent2.ef\",\n", - " \"crossing.ef\",\n", - " \"Figure1.ef\",\n", - " \"MyTree1.ef\",\n", - " \"oldex.ef\",\n", - " \"x1.ef\",\n", - " \"efg/cross.efg\",\n", - " \"efg/holdout.efg\",\n", - "]\n", - "tikz_codes = {\n", - " game.split(\".\")[0]: draw_tree(f\"../games/{game}\", show_grid=False, scale_factor=1)\n", - " for game in example_games\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "c9e84d02", + "execution_count": 2, + "id": "55aebb9a-ac08-4e8b-9c60-b85274881d9f", "metadata": {}, "outputs": [ { @@ -408,18 +356,18 @@ "" ] }, - "execution_count": 8, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "get_ipython().run_cell_magic(\"tikz\", \"\", tikz_codes[\"one_card_poker\"])" + "draw_tree(\"../games/one_card_poker.ef\")" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 3, "id": "176cb959-b61b-43ad-b44f-3e95eafcdbf8", "metadata": {}, "outputs": [ @@ -763,18 +711,18 @@ "" ] }, - "execution_count": 9, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "get_ipython().run_cell_magic(\"tikz\", \"\", tikz_codes[\"efg/one_card_poker\"])" + "draw_tree(\"../games/efg/one_card_poker.efg\")" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 4, "id": "5fd3f2b4-c4f2-4a6d-b8cf-3525a73e8761", "metadata": {}, "outputs": [ @@ -944,18 +892,18 @@ "" ] }, - "execution_count": 10, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "get_ipython().run_cell_magic(\"tikz\", \"\", tikz_codes[\"efg/trust_game\"])" + "draw_tree(\"../games/efg/trust_game.efg\")" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 5, "id": "c58d058a-cd34-49e5-9b45-c336867ae0e3", "metadata": {}, "outputs": [ @@ -1455,18 +1403,18 @@ "" ] }, - "execution_count": 11, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "get_ipython().run_cell_magic(\"tikz\", \"\", tikz_codes[\"2smp\"])" + "draw_tree(\"../games/2smp.ef\")" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 6, "id": "8ce755bf-083a-4378-aa53-5232ef24544b", "metadata": {}, "outputs": [ @@ -1966,18 +1914,18 @@ "" ] }, - "execution_count": 12, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "get_ipython().run_cell_magic(\"tikz\", \"\", tikz_codes[\"efg/2smp\"])" + "draw_tree(\"../games/efg/2smp.efg\")" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 7, "id": "8b0d5897-76f1-4728-94e2-0e33167b6830", "metadata": {}, "outputs": [ @@ -2488,18 +2436,18 @@ "" ] }, - "execution_count": 13, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "get_ipython().run_cell_magic(\"tikz\", \"\", tikz_codes[\"2s2x2x2\"])" + "draw_tree(\"../games/2s2x2x2.ef\")" ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 8, "id": "6622c1b7-5128-43a9-9d84-0c9265d9cb13", "metadata": {}, "outputs": [ @@ -3010,18 +2958,18 @@ "" ] }, - "execution_count": 14, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "get_ipython().run_cell_magic(\"tikz\", \"\", tikz_codes[\"efg/2s2x2x2\"])" + "draw_tree(\"../games/efg/2s2x2x2.efg\")" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 9, "id": "01d4f44e-d260-4866-bfed-00ebadab5199", "metadata": {}, "outputs": [ @@ -3844,18 +3792,18 @@ "" ] }, - "execution_count": 15, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "get_ipython().run_cell_magic(\"tikz\", \"\", tikz_codes[\"cent2\"])" + "draw_tree(\"../games/cent2.ef\")" ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 10, "id": "24d174f6-e34e-435e-97bd-fea8cfeded8e", "metadata": {}, "outputs": [ @@ -4678,18 +4626,18 @@ "" ] }, - "execution_count": 16, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "get_ipython().run_cell_magic(\"tikz\", \"\", tikz_codes[\"efg/cent2\"])" + "draw_tree(\"../games/efg/cent2.efg\")" ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 11, "id": "584e6cdc", "metadata": {}, "outputs": [ @@ -4829,18 +4777,18 @@ "" ] }, - "execution_count": 17, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "get_ipython().run_cell_magic(\"tikz\", \"\", tikz_codes[\"crossing\"])" + "draw_tree(\"../games/crossing.ef\")" ] }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 12, "id": "f6160e69", "metadata": {}, "outputs": [ @@ -5116,18 +5064,18 @@ "" ] }, - "execution_count": 18, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "get_ipython().run_cell_magic(\"tikz\", \"\", tikz_codes[\"Figure1\"])" + "draw_tree(\"../games/Figure1.ef\")" ] }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 13, "id": "22534773", "metadata": {}, "outputs": [ @@ -5346,18 +5294,18 @@ "" ] }, - "execution_count": 19, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "get_ipython().run_cell_magic(\"tikz\", \"\", tikz_codes[\"MyTree1\"])" + "draw_tree(\"../games/MyTree1.ef\")" ] }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 14, "id": "23d9ad2e", "metadata": {}, "outputs": [ @@ -5501,18 +5449,18 @@ "" ] }, - "execution_count": 20, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "get_ipython().run_cell_magic(\"tikz\", \"\", tikz_codes[\"oldex\"])" + "draw_tree(\"../games/oldex.ef\")" ] }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 15, "id": "cc060d85", "metadata": {}, "outputs": [ @@ -5666,18 +5614,18 @@ "" ] }, - "execution_count": 21, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "get_ipython().run_cell_magic(\"tikz\", \"\", tikz_codes[\"x1\"])" + "draw_tree(\"../games/x1.ef\")" ] }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 16, "id": "1f81020a-14da-47a4-8d1e-c3a3f3b3eaeb", "metadata": {}, "outputs": [ @@ -5979,98 +5927,98 @@ "" ] }, - "execution_count": 22, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "get_ipython().run_cell_magic(\"tikz\", \"\", tikz_codes[\"efg/cross\"])" + "draw_tree(\"../games/efg/cross.efg\")" ] }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 17, "id": "1b0ad93a-dfd9-4c66-b789-82ddcea13cfb", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ - "\n", + "\n", "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", "\n", @@ -6092,1813 +6040,1818 @@ "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", "" ], "text/plain": [ "" ] }, - "execution_count": 23, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "get_ipython().run_cell_magic(\"tikz\", \"\", tikz_codes[\"efg/holdout\"])" + "draw_tree(\"../games/efg/holdout.efg\")" ] }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 18, "id": "168a43f8-8609-4610-9cdd-474a8086bcc0", "metadata": {}, "outputs": [ @@ -7908,7 +7861,7 @@ "'/Users/echalstrey/projects/draw_tree/tutorial/x1.png'" ] }, - "execution_count": 24, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -7921,7 +7874,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 19, "id": "9a6167a9-e270-4874-9b4b-40887b3e4d6e", "metadata": {}, "outputs": [ @@ -7931,7 +7884,7 @@ "'/Users/echalstrey/projects/draw_tree/tutorial/one_card_poker.png'" ] }, - "execution_count": 26, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" }