From 5cc97e02b3aea1faf5748282ce0532bf6104e8c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Augustyniak?= Date: Mon, 2 Dec 2024 08:56:26 +0000 Subject: [PATCH] nbdev --- juddges/_modidx.py | 7 +- nbs/Data/01_Dataset_Description.ipynb | 215 +++++++++++++++--- .../01_Dataset_Description_Raw.ipynb | 139 +++++++++-- nbs/Presentations/01_linie_rzecznicze.ipynb | 190 +++++----------- 4 files changed, 369 insertions(+), 182 deletions(-) diff --git a/juddges/_modidx.py b/juddges/_modidx.py index c3de275..96af010 100644 --- a/juddges/_modidx.py +++ b/juddges/_modidx.py @@ -5,18 +5,22 @@ 'doc_host': 'https://laugustyniak.github.io', 'git_url': 'https://github.com/laugustyniak/juddges', 'lib_path': 'juddges'}, - 'syms': { 'juddges.config': {}, + 'syms': { 'juddges.case_law_trends.constants': {}, + 'juddges.case_law_trends.visualisations': {}, + 'juddges.config': {}, 'juddges.data.database': {}, 'juddges.data.datasets.dummy_dataset': {}, 'juddges.data.datasets.utils': {}, 'juddges.data.pl_court_api': {}, 'juddges.data.pl_court_graph': {}, 'juddges.data.weaviate_db': {}, + 'juddges.data_models': {}, 'juddges.evaluation.eval_full_text': {}, 'juddges.evaluation.eval_structured': {}, 'juddges.evaluation.eval_structured_llm_judge': {}, 'juddges.evaluation.info_extraction': {}, 'juddges.evaluation.parse': {}, + 'juddges.llms': {}, 'juddges.models.factory': {}, 'juddges.models.predict': {}, 'juddges.preprocessing.context_truncator': {}, @@ -26,6 +30,7 @@ 'juddges.preprocessing.text_encoder': {}, 'juddges.prompts.information_extraction': {}, 'juddges.retrieval.mongo_hybrid_search': {}, + 'juddges.retrieval.mongo_term_based_search': {}, 'juddges.settings': {}, 'juddges.utils.config': {}, 'juddges.utils.misc': {}, diff --git a/nbs/Data/01_Dataset_Description.ipynb b/nbs/Data/01_Dataset_Description.ipynb index 4c843a2..6d57c39 100644 --- a/nbs/Data/01_Dataset_Description.ipynb +++ b/nbs/Data/01_Dataset_Description.ipynb @@ -168,9 +168,21 @@ ], "source": [ "# | eval: false\n", - "court_distribution = raw_ds.drop_nulls(subset=\"court_name\").select(\"court_name\").group_by(\"court_name\").len().sort(\"len\", descending=True).collect().to_pandas()\n", + "court_distribution = (\n", + " raw_ds.drop_nulls(subset=\"court_name\")\n", + " .select(\"court_name\")\n", + " .group_by(\"court_name\")\n", + " .len()\n", + " .sort(\"len\", descending=True)\n", + " .collect()\n", + " .to_pandas()\n", + ")\n", "ax = sns.histplot(data=court_distribution, x=\"len\", log_scale=True, kde=True)\n", - "ax.set(title=\"Distribution of judgments per court\", xlabel=\"#Judgements in single court\", ylabel=\"Count\")\n", + "ax.set(\n", + " title=\"Distribution of judgments per court\",\n", + " xlabel=\"#Judgements in single court\",\n", + " ylabel=\"Count\",\n", + ")\n", "plt.show()" ] }, @@ -193,12 +205,29 @@ ], "source": [ "# | eval: false\n", - "judgements_per_year = raw_ds.select(\"date\").collect()[\"date\"].str.split(\" \").list.get(0).str.to_date().dt.year().value_counts().sort(\"date\").to_pandas()\n", + "judgements_per_year = (\n", + " raw_ds.select(\"date\")\n", + " .collect()[\"date\"]\n", + " .str.split(\" \")\n", + " .list.get(0)\n", + " .str.to_date()\n", + " .dt.year()\n", + " .value_counts()\n", + " .sort(\"date\")\n", + " .to_pandas()\n", + ")\n", "judgements_per_year = judgements_per_year[judgements_per_year[\"date\"] < 2024]\n", "\n", "_, ax = plt.subplots(1, 1, figsize=(10, 5))\n", - "ax = sns.pointplot(data=judgements_per_year, x=\"date\", y=\"count\", linestyles=\"--\", ax=ax)\n", - "ax.set(xlabel=\"Year\", ylabel=\"Number of Judgements\", title=\"Yearly Number of Judgements\", yscale=\"log\")\n", + "ax = sns.pointplot(\n", + " data=judgements_per_year, x=\"date\", y=\"count\", linestyles=\"--\", ax=ax\n", + ")\n", + "ax.set(\n", + " xlabel=\"Year\",\n", + " ylabel=\"Number of Judgements\",\n", + " title=\"Yearly Number of Judgements\",\n", + " yscale=\"log\",\n", + ")\n", "plt.xticks(rotation=90)\n", "plt.show()" ] @@ -222,7 +251,15 @@ ], "source": [ "# | eval: false\n", - "types = raw_ds.fill_null(value=\"\").select(\"type\").group_by(\"type\").len().sort(\"len\", descending=True).collect().to_pandas()\n", + "types = (\n", + " raw_ds.fill_null(value=\"\")\n", + " .select(\"type\")\n", + " .group_by(\"type\")\n", + " .len()\n", + " .sort(\"len\", descending=True)\n", + " .collect()\n", + " .to_pandas()\n", + ")\n", "\n", "_, ax = plt.subplots(1, 1, figsize=(8, 8))\n", "ax = sns.barplot(data=types, x=\"len\", y=\"type\", errorbar=None, ax=ax)\n", @@ -249,9 +286,22 @@ ], "source": [ "# | eval: false\n", - "num_judges = raw_ds.with_columns([pl.col(\"judges\").list.len().alias(\"num_judges\")]).select(\"num_judges\").sort(\"num_judges\").collect().to_pandas()\n", - "ax = sns.histplot(data=num_judges, x=\"num_judges\", bins=num_judges[\"num_judges\"].nunique())\n", - "ax.set(xlabel=\"#Judges per judgement\", ylabel=\"Count\", yscale=\"log\", title=\"#Judges per single judgement\")\n", + "num_judges = (\n", + " raw_ds.with_columns([pl.col(\"judges\").list.len().alias(\"num_judges\")])\n", + " .select(\"num_judges\")\n", + " .sort(\"num_judges\")\n", + " .collect()\n", + " .to_pandas()\n", + ")\n", + "ax = sns.histplot(\n", + " data=num_judges, x=\"num_judges\", bins=num_judges[\"num_judges\"].nunique()\n", + ")\n", + "ax.set(\n", + " xlabel=\"#Judges per judgement\",\n", + " ylabel=\"Count\",\n", + " yscale=\"log\",\n", + " title=\"#Judges per single judgement\",\n", + ")\n", "plt.show()" ] }, @@ -274,9 +324,20 @@ ], "source": [ "# | eval: false\n", - "num_lb = raw_ds.with_columns([pl.col(\"legalBases\").list.len().alias(\"num_lb\")]).select(\"num_lb\").sort(\"num_lb\").collect().to_pandas()\n", + "num_lb = (\n", + " raw_ds.with_columns([pl.col(\"legalBases\").list.len().alias(\"num_lb\")])\n", + " .select(\"num_lb\")\n", + " .sort(\"num_lb\")\n", + " .collect()\n", + " .to_pandas()\n", + ")\n", "ax = sns.histplot(data=num_lb, x=\"num_lb\", bins=num_lb[\"num_lb\"].nunique())\n", - "ax.set(xlabel=\"#Legal bases\", ylabel=\"Count\", yscale=\"log\", title=\"#Legal bases per judgement\")\n", + "ax.set(\n", + " xlabel=\"#Legal bases\",\n", + " ylabel=\"Count\",\n", + " yscale=\"log\",\n", + " title=\"#Legal bases per judgement\",\n", + ")\n", "plt.show()" ] }, @@ -303,7 +364,9 @@ ], "source": [ "# | eval: false\n", - "raw_text_ds = load_dataset(\"parquet\", data_dir=\"../../data/datasets/pl/raw/\", columns=[\"_id\", \"text\"])\n", + "raw_text_ds = load_dataset(\n", + " \"parquet\", data_dir=\"../../data/datasets/pl/raw/\", columns=[\"_id\", \"text\"]\n", + ")\n", "raw_text_ds = raw_text_ds.filter(lambda x: x[\"text\"] is not None)" ] }, @@ -340,11 +403,21 @@ "# | eval: false\n", "tokenizer = AutoTokenizer.from_pretrained(\"meta-llama/Meta-Llama-3-8B\")\n", "\n", - "def tokenize(batch: dict[str, list]) -> list[int]: \n", - " tokenized = tokenizer(batch[\"text\"], add_special_tokens=False, return_attention_mask=False, return_token_type_ids=False, return_length=True)\n", + "\n", + "def tokenize(batch: dict[str, list]) -> list[int]:\n", + " tokenized = tokenizer(\n", + " batch[\"text\"],\n", + " add_special_tokens=False,\n", + " return_attention_mask=False,\n", + " return_token_type_ids=False,\n", + " return_length=True,\n", + " )\n", " return {\"length\": tokenized[\"length\"]}\n", "\n", - "raw_text_ds = raw_text_ds.map(tokenize, batched=True, batch_size=16, remove_columns=[\"text\"], num_proc=20)\n", + "\n", + "raw_text_ds = raw_text_ds.map(\n", + " tokenize, batched=True, batch_size=16, remove_columns=[\"text\"], num_proc=20\n", + ")\n", "raw_text_ds" ] }, @@ -370,8 +443,13 @@ "judgement_len = raw_text_ds[\"train\"].to_pandas()\n", "\n", "ax = sns.histplot(data=judgement_len, x=\"length\", bins=50)\n", - "ax.set(xlabel=\"#Tokens\", ylabel=\"Count\", title=\"#Tokens distribution in judgements (llama-3 tokenizer)\", yscale=\"log\")\n", - "ax.xaxis.set_major_formatter(ticker.FuncFormatter(lambda x, pos: f'{int(x/1_000)}k'))\n", + "ax.set(\n", + " xlabel=\"#Tokens\",\n", + " ylabel=\"Count\",\n", + " title=\"#Tokens distribution in judgements (llama-3 tokenizer)\",\n", + " yscale=\"log\",\n", + ")\n", + "ax.xaxis.set_major_formatter(ticker.FuncFormatter(lambda x, pos: f\"{int(x/1_000)}k\"))\n", "plt.show()" ] }, @@ -394,11 +472,23 @@ ], "source": [ "# | eval: false\n", - "per_type_tokens = raw_ds.fill_null(value=\"\").select([\"_id\", \"type\"]).collect().to_pandas().set_index(\"_id\").join(judgement_len.set_index(\"_id\"))\n", + "per_type_tokens = (\n", + " raw_ds.fill_null(value=\"\")\n", + " .select([\"_id\", \"type\"])\n", + " .collect()\n", + " .to_pandas()\n", + " .set_index(\"_id\")\n", + " .join(judgement_len.set_index(\"_id\"))\n", + ")\n", "\n", "_, ax = plt.subplots(1, 1, figsize=(10, 10))\n", "ax = sns.boxenplot(data=per_type_tokens, y=\"type\", x=\"length\")\n", - "ax.set(xscale=\"log\", title=\"Judgement token count per type\", xlabel=\"#Tokens\", ylabel=\"Type\")\n", + "ax.set(\n", + " xscale=\"log\",\n", + " title=\"Judgement token count per type\",\n", + " xlabel=\"#Tokens\",\n", + " ylabel=\"Type\",\n", + ")\n", "plt.show()" ] }, @@ -573,7 +663,7 @@ ], "source": [ "# | eval: false\n", - "df = pd.DataFrame([{\"Split\":k, \"#\": len(v)} for k, v in instruct_ds.items()])\n", + "df = pd.DataFrame([{\"Split\": k, \"#\": len(v)} for k, v in instruct_ds.items()])\n", "df[\"%\"] = df[\"#\"] / df[\"#\"].sum() * 100\n", "df.round(2)" ] @@ -686,13 +776,43 @@ "\n", "\n", "def tokenize_and_comp_length_instruct_ds(batch: dict[str, list]) -> dict[str, list]:\n", - " tokenized_ctx = tokenizer(batch[\"context\"], add_special_tokens=False, return_attention_mask=False, return_token_type_ids=False, return_length=True)\n", - " tokenized_out = tokenizer(batch[\"output\"], add_special_tokens=False, return_attention_mask=False, return_token_type_ids=False, return_length=True)\n", + " tokenized_ctx = tokenizer(\n", + " batch[\"context\"],\n", + " add_special_tokens=False,\n", + " return_attention_mask=False,\n", + " return_token_type_ids=False,\n", + " return_length=True,\n", + " )\n", + " tokenized_out = tokenizer(\n", + " batch[\"output\"],\n", + " add_special_tokens=False,\n", + " return_attention_mask=False,\n", + " return_token_type_ids=False,\n", + " return_length=True,\n", + " )\n", "\n", - " return {\"context_num_tokens\": tokenized_ctx[\"length\"], \"output_num_tokens\": tokenized_out[\"length\"]}\n", + " return {\n", + " \"context_num_tokens\": tokenized_ctx[\"length\"],\n", + " \"output_num_tokens\": tokenized_out[\"length\"],\n", + " }\n", "\n", - "instruct_ds_tok = instruct_ds.map(tokenize_and_comp_length_instruct_ds, batched=True, batch_size=32, remove_columns=[\"prompt\", \"context\", \"output\"], num_proc=20)\n", - "instruct_ds_tok = pd.concat([instruct_ds_tok[\"train\"].to_pandas(), instruct_ds_tok[\"test\"].to_pandas()], axis=0, keys=[\"train\", \"test\"]).reset_index(level=0).rename(columns={\"level_0\": \"split\"})\n", + "\n", + "instruct_ds_tok = instruct_ds.map(\n", + " tokenize_and_comp_length_instruct_ds,\n", + " batched=True,\n", + " batch_size=32,\n", + " remove_columns=[\"prompt\", \"context\", \"output\"],\n", + " num_proc=20,\n", + ")\n", + "instruct_ds_tok = (\n", + " pd.concat(\n", + " [instruct_ds_tok[\"train\"].to_pandas(), instruct_ds_tok[\"test\"].to_pandas()],\n", + " axis=0,\n", + " keys=[\"train\", \"test\"],\n", + " )\n", + " .reset_index(level=0)\n", + " .rename(columns={\"level_0\": \"split\"})\n", + ")\n", "instruct_ds_tok.head()" ] }, @@ -711,7 +831,10 @@ } ], "source": [ - "print(f\"0.95 quantile of maximum output: {instruct_ds_tok['output_num_tokens'].quantile(0.95)}\")" + "# | eval: false\n", + "print(\n", + " f\"0.95 quantile of maximum output: {instruct_ds_tok['output_num_tokens'].quantile(0.95)}\"\n", + ")" ] }, { @@ -733,11 +856,30 @@ ], "source": [ "# | eval: false\n", - "tok_melt = instruct_ds_tok.melt(id_vars=[\"split\"], value_vars=[\"context_num_tokens\", \"output_num_tokens\"], var_name=\"Text\", value_name=\"#Tokens\")\n", - "tok_melt[\"Text\"] = tok_melt[\"Text\"].map({\"context_num_tokens\": \"Context\", \"output_num_tokens\": \"Output\"})\n", + "tok_melt = instruct_ds_tok.melt(\n", + " id_vars=[\"split\"],\n", + " value_vars=[\"context_num_tokens\", \"output_num_tokens\"],\n", + " var_name=\"Text\",\n", + " value_name=\"#Tokens\",\n", + ")\n", + "tok_melt[\"Text\"] = tok_melt[\"Text\"].map(\n", + " {\"context_num_tokens\": \"Context\", \"output_num_tokens\": \"Output\"}\n", + ")\n", "\n", - "g = sns.displot(data=tok_melt, x=\"#Tokens\", col=\"Text\", hue=\"split\", kind=\"kde\", fill=True, log_scale=True, common_norm=False, facet_kws=dict(sharex=False, sharey=False))\n", - "g.figure.suptitle(\"Distribution of #Tokens (llama-3 tokenizer) in Context and Output in instruct dataset\")\n", + "g = sns.displot(\n", + " data=tok_melt,\n", + " x=\"#Tokens\",\n", + " col=\"Text\",\n", + " hue=\"split\",\n", + " kind=\"kde\",\n", + " fill=True,\n", + " log_scale=True,\n", + " common_norm=False,\n", + " facet_kws=dict(sharex=False, sharey=False),\n", + ")\n", + "g.figure.suptitle(\n", + " \"Distribution of #Tokens (llama-3 tokenizer) in Context and Output in instruct dataset\"\n", + ")\n", "g.figure.tight_layout()\n", "plt.show()" ] @@ -762,8 +904,17 @@ "source": [ "# | eval: false\n", "_, ax = plt.subplots(1, 1, figsize=(10, 10))\n", - "ax = sns.countplot(data=per_type_tokens.join(instruct_ds_tok.set_index(\"_id\"), how=\"right\"), y=\"type\", hue=\"split\")\n", - "ax.set(xscale=\"log\", title=\"Distribution of types in dataset splits\", xlabel=\"Count\", ylabel=\"Type\")\n", + "ax = sns.countplot(\n", + " data=per_type_tokens.join(instruct_ds_tok.set_index(\"_id\"), how=\"right\"),\n", + " y=\"type\",\n", + " hue=\"split\",\n", + ")\n", + "ax.set(\n", + " xscale=\"log\",\n", + " title=\"Distribution of types in dataset splits\",\n", + " xlabel=\"Count\",\n", + " ylabel=\"Type\",\n", + ")\n", "plt.show()" ] } diff --git a/nbs/Dataset Cards/01_Dataset_Description_Raw.ipynb b/nbs/Dataset Cards/01_Dataset_Description_Raw.ipynb index c8ff77d..036795c 100644 --- a/nbs/Dataset Cards/01_Dataset_Description_Raw.ipynb +++ b/nbs/Dataset Cards/01_Dataset_Description_Raw.ipynb @@ -19,7 +19,7 @@ "from datasets import load_dataset\n", "from transformers import AutoTokenizer\n", "\n", - "warnings.filterwarnings('ignore')\n", + "warnings.filterwarnings(\"ignore\")\n", "sns.set_theme(\"notebook\")\n", "transformers.logging.set_verbosity_error()\n", "datasets.logging.set_verbosity_error()\n", @@ -280,9 +280,14 @@ "metadata": {}, "outputs": [], "source": [ - "null_count = raw_ds.null_count().collect().to_pandas().T.rename(columns={0: \"Null count\"})\n", + "# | eval: false\n", + "null_count = (\n", + " raw_ds.null_count().collect().to_pandas().T.rename(columns={0: \"Null count\"})\n", + ")\n", "null_count.index.name = \"Field name\"\n", - "null_count[\"Null fraction\"] = (null_count[\"Null count\"] / raw_ds.select(pl.len()).collect().item()).round(2)\n", + "null_count[\"Null fraction\"] = (\n", + " null_count[\"Null count\"] / raw_ds.select(pl.len()).collect().item()\n", + ").round(2)\n", "# print(null_count.to_markdown())" ] }, @@ -338,9 +343,21 @@ "outputs": [], "source": [ "# | eval: false\n", - "court_distribution = raw_ds.drop_nulls(subset=\"court_name\").select(\"court_name\").group_by(\"court_name\").len().sort(\"len\", descending=True).collect().to_pandas()\n", + "court_distribution = (\n", + " raw_ds.drop_nulls(subset=\"court_name\")\n", + " .select(\"court_name\")\n", + " .group_by(\"court_name\")\n", + " .len()\n", + " .sort(\"len\", descending=True)\n", + " .collect()\n", + " .to_pandas()\n", + ")\n", "ax = sns.histplot(data=court_distribution, x=\"len\", log_scale=True, kde=True)\n", - "ax.set(title=\"Distribution of judgments per court\", xlabel=\"#Judgements in single court\", ylabel=\"Count\")\n", + "ax.set(\n", + " title=\"Distribution of judgments per court\",\n", + " xlabel=\"#Judgements in single court\",\n", + " ylabel=\"Count\",\n", + ")\n", "plt.show()" ] }, @@ -352,12 +369,29 @@ "outputs": [], "source": [ "# | eval: false\n", - "judgements_per_year = raw_ds.select(\"date\").collect()[\"date\"].str.split(\" \").list.get(0).str.to_date().dt.year().value_counts().sort(\"date\").to_pandas()\n", + "judgements_per_year = (\n", + " raw_ds.select(\"date\")\n", + " .collect()[\"date\"]\n", + " .str.split(\" \")\n", + " .list.get(0)\n", + " .str.to_date()\n", + " .dt.year()\n", + " .value_counts()\n", + " .sort(\"date\")\n", + " .to_pandas()\n", + ")\n", "judgements_per_year = judgements_per_year[judgements_per_year[\"date\"] < 2024]\n", "\n", "_, ax = plt.subplots(1, 1, figsize=(10, 5))\n", - "ax = sns.pointplot(data=judgements_per_year, x=\"date\", y=\"count\", linestyles=\"--\", ax=ax)\n", - "ax.set(xlabel=\"Year\", ylabel=\"Number of Judgements\", title=\"Yearly Number of Judgements\", yscale=\"log\")\n", + "ax = sns.pointplot(\n", + " data=judgements_per_year, x=\"date\", y=\"count\", linestyles=\"--\", ax=ax\n", + ")\n", + "ax.set(\n", + " xlabel=\"Year\",\n", + " ylabel=\"Number of Judgements\",\n", + " title=\"Yearly Number of Judgements\",\n", + " yscale=\"log\",\n", + ")\n", "plt.xticks(rotation=90)\n", "plt.show()" ] @@ -370,7 +404,15 @@ "outputs": [], "source": [ "# | eval: false\n", - "types = raw_ds.fill_null(value=\"\").select(\"type\").group_by(\"type\").len().sort(\"len\", descending=True).collect().to_pandas()\n", + "types = (\n", + " raw_ds.fill_null(value=\"\")\n", + " .select(\"type\")\n", + " .group_by(\"type\")\n", + " .len()\n", + " .sort(\"len\", descending=True)\n", + " .collect()\n", + " .to_pandas()\n", + ")\n", "\n", "_, ax = plt.subplots(1, 1, figsize=(8, 8))\n", "ax = sns.barplot(data=types, x=\"len\", y=\"type\", errorbar=None, ax=ax)\n", @@ -386,9 +428,22 @@ "outputs": [], "source": [ "# | eval: false\n", - "num_judges = raw_ds.with_columns([pl.col(\"judges\").list.len().alias(\"num_judges\")]).select(\"num_judges\").sort(\"num_judges\").collect().to_pandas()\n", - "ax = sns.histplot(data=num_judges, x=\"num_judges\", bins=num_judges[\"num_judges\"].nunique())\n", - "ax.set(xlabel=\"#Judges per judgement\", ylabel=\"Count\", yscale=\"log\", title=\"#Judges per single judgement\")\n", + "num_judges = (\n", + " raw_ds.with_columns([pl.col(\"judges\").list.len().alias(\"num_judges\")])\n", + " .select(\"num_judges\")\n", + " .sort(\"num_judges\")\n", + " .collect()\n", + " .to_pandas()\n", + ")\n", + "ax = sns.histplot(\n", + " data=num_judges, x=\"num_judges\", bins=num_judges[\"num_judges\"].nunique()\n", + ")\n", + "ax.set(\n", + " xlabel=\"#Judges per judgement\",\n", + " ylabel=\"Count\",\n", + " yscale=\"log\",\n", + " title=\"#Judges per single judgement\",\n", + ")\n", "plt.show()" ] }, @@ -400,9 +455,20 @@ "outputs": [], "source": [ "# | eval: false\n", - "num_lb = raw_ds.with_columns([pl.col(\"legalBases\").list.len().alias(\"num_lb\")]).select(\"num_lb\").sort(\"num_lb\").collect().to_pandas()\n", + "num_lb = (\n", + " raw_ds.with_columns([pl.col(\"legalBases\").list.len().alias(\"num_lb\")])\n", + " .select(\"num_lb\")\n", + " .sort(\"num_lb\")\n", + " .collect()\n", + " .to_pandas()\n", + ")\n", "ax = sns.histplot(data=num_lb, x=\"num_lb\", bins=num_lb[\"num_lb\"].nunique())\n", - "ax.set(xlabel=\"#Legal bases\", ylabel=\"Count\", yscale=\"log\", title=\"#Legal bases per judgement\")\n", + "ax.set(\n", + " xlabel=\"#Legal bases\",\n", + " ylabel=\"Count\",\n", + " yscale=\"log\",\n", + " title=\"#Legal bases per judgement\",\n", + ")\n", "plt.show()" ] }, @@ -414,7 +480,9 @@ "outputs": [], "source": [ "# | eval: false\n", - "raw_text_ds = load_dataset(\"parquet\", data_dir=\"../../data/datasets/pl/raw/\", columns=[\"_id\", \"text\"])\n", + "raw_text_ds = load_dataset(\n", + " \"parquet\", data_dir=\"../../data/datasets/pl/raw/\", columns=[\"_id\", \"text\"]\n", + ")\n", "raw_text_ds = raw_text_ds.filter(lambda x: x[\"text\"] is not None)" ] }, @@ -428,11 +496,21 @@ "# | eval: false\n", "tokenizer = AutoTokenizer.from_pretrained(\"meta-llama/Meta-Llama-3-8B\")\n", "\n", - "def tokenize(batch: dict[str, list]) -> list[int]: \n", - " tokenized = tokenizer(batch[\"text\"], add_special_tokens=False, return_attention_mask=False, return_token_type_ids=False, return_length=True)\n", + "\n", + "def tokenize(batch: dict[str, list]) -> list[int]:\n", + " tokenized = tokenizer(\n", + " batch[\"text\"],\n", + " add_special_tokens=False,\n", + " return_attention_mask=False,\n", + " return_token_type_ids=False,\n", + " return_length=True,\n", + " )\n", " return {\"length\": tokenized[\"length\"]}\n", "\n", - "raw_text_ds = raw_text_ds.map(tokenize, batched=True, batch_size=16, remove_columns=[\"text\"], num_proc=20)" + "\n", + "raw_text_ds = raw_text_ds.map(\n", + " tokenize, batched=True, batch_size=16, remove_columns=[\"text\"], num_proc=20\n", + ")" ] }, { @@ -446,8 +524,13 @@ "judgement_len = raw_text_ds[\"train\"].to_pandas()\n", "\n", "ax = sns.histplot(data=judgement_len, x=\"length\", bins=50)\n", - "ax.set(xlabel=\"#Tokens\", ylabel=\"Count\", title=\"#Tokens distribution in judgements (llama-3 tokenizer)\", yscale=\"log\")\n", - "ax.xaxis.set_major_formatter(ticker.FuncFormatter(lambda x, pos: f'{int(x/1_000)}k'))\n", + "ax.set(\n", + " xlabel=\"#Tokens\",\n", + " ylabel=\"Count\",\n", + " title=\"#Tokens distribution in judgements (llama-3 tokenizer)\",\n", + " yscale=\"log\",\n", + ")\n", + "ax.xaxis.set_major_formatter(ticker.FuncFormatter(lambda x, pos: f\"{int(x/1_000)}k\"))\n", "plt.show()" ] }, @@ -459,11 +542,23 @@ "outputs": [], "source": [ "# | eval: false\n", - "per_type_tokens = raw_ds.fill_null(value=\"\").select([\"_id\", \"type\"]).collect().to_pandas().set_index(\"_id\").join(judgement_len.set_index(\"_id\"))\n", + "per_type_tokens = (\n", + " raw_ds.fill_null(value=\"\")\n", + " .select([\"_id\", \"type\"])\n", + " .collect()\n", + " .to_pandas()\n", + " .set_index(\"_id\")\n", + " .join(judgement_len.set_index(\"_id\"))\n", + ")\n", "\n", "_, ax = plt.subplots(1, 1, figsize=(10, 10))\n", "ax = sns.boxenplot(data=per_type_tokens, y=\"type\", x=\"length\")\n", - "ax.set(xscale=\"log\", title=\"Judgement token count per type\", xlabel=\"#Tokens\", ylabel=\"Type\")\n", + "ax.set(\n", + " xscale=\"log\",\n", + " title=\"Judgement token count per type\",\n", + " xlabel=\"#Tokens\",\n", + " ylabel=\"Type\",\n", + ")\n", "plt.show()" ] } diff --git a/nbs/Presentations/01_linie_rzecznicze.ipynb b/nbs/Presentations/01_linie_rzecznicze.ipynb index 7f01a60..1a6b76a 100644 --- a/nbs/Presentations/01_linie_rzecznicze.ipynb +++ b/nbs/Presentations/01_linie_rzecznicze.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -12,7 +12,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -21,12 +21,13 @@ "True" ] }, - "execution_count": 2, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "# | eval: false\n", "import os\n", "from dotenv import load_dotenv\n", "\n", @@ -45,7 +46,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -54,16 +55,17 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ + "# | eval: false\n", "settings.prepare_langchain_cache()" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -72,16 +74,17 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ + "# | eval: false\n", "judgements = search_judgements(\"kredyt we frankach\", max_docs=200)" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -90,18 +93,19 @@ "200" ] }, - "execution_count": 7, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "# | eval: false\n", "len(judgements)" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -159,6 +163,8 @@ } ], "source": [ + "# | eval: false\n", + "\n", "# Get first judgment\n", "judgment = judgements[-1]\n", "\n", @@ -194,7 +200,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -204,7 +210,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -213,7 +219,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -225,7 +231,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -240,6 +246,7 @@ } ], "source": [ + "# | eval: false\n", "import textwrap\n", "\n", "# When printing output\n", @@ -251,7 +258,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -270,10 +277,11 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ + "# | eval: false\n", "judgements = search_judgements(\n", " \"kredyt hipoteczny we frankach szwajcarskich\", max_docs=1000\n", ")" @@ -281,7 +289,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -412,12 +420,13 @@ "4 [{'score': 8.589164733886719, 'path': 'text', ... " ] }, - "execution_count": 14, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "# | eval: false\n", "import pandas as pd\n", "from juddges.data_models import Judgment\n", "\n", @@ -429,7 +438,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -443,6 +452,7 @@ } ], "source": [ + "# | eval: false\n", "# Convert date column to datetime, using mixed format and extracting just the date portion\n", "df[\"date\"] = pd.to_datetime(\n", " df[\"date\"].str.split().str[0], format=\"mixed\", dayfirst=True\n", @@ -459,7 +469,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -468,84 +478,7 @@ }, { "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "ename": "AttributeError", - "evalue": "'str' object has no attribute 'year'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[17], line 17\u001b[0m\n\u001b[1;32m 13\u001b[0m ax1\u001b[38;5;241m.\u001b[39mgrid(\u001b[38;5;28;01mTrue\u001b[39;00m, alpha\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m0.3\u001b[39m)\n\u001b[1;32m 15\u001b[0m \u001b[38;5;66;03m# Add vertical line for Dziubak judgment\u001b[39;00m\n\u001b[1;32m 16\u001b[0m ax1\u001b[38;5;241m.\u001b[39maxvline(\n\u001b[0;32m---> 17\u001b[0m x\u001b[38;5;241m=\u001b[39m\u001b[43mDZIUBAK_JUDGMENT_DATE\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43myear\u001b[49m, color\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mr\u001b[39m\u001b[38;5;124m\"\u001b[39m, linestyle\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m--\u001b[39m\u001b[38;5;124m\"\u001b[39m, label\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mWyrok Dziubak\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 18\u001b[0m )\n\u001b[1;32m 19\u001b[0m ax1\u001b[38;5;241m.\u001b[39mlegend()\n\u001b[1;32m 21\u001b[0m \u001b[38;5;66;03m# Second subplot - sprawa_frankowiczów distribution over time\u001b[39;00m\n", - "\u001b[0;31mAttributeError\u001b[0m: 'str' object has no attribute 'year'" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA/gAAAPeCAYAAAC4LrG8AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/GU6VOAAAACXBIWXMAAA9hAAAPYQGoP6dpAABqoUlEQVR4nO3deZhWdf0//ufMIAMugAgMqIhbpqaiYiIqLoWS+rFIK7RSJJePhZVSLpiJ2IKZn/Kbkn4qU1tM09RM/WKIWyZuKLkh5ZZWDq4soqz3+f3Rz/k2AsrgrIfH47ru62Le9/uc+/We15lhnnPuc6aqKIoiAAAAQIdW3dYFAAAAAO+fgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8Aq2GfffbJdttt957zNt100xx11FHN9rrPPfdcqqqqctlllzXbPmlfzjrrrFRVVbV1GQB0QAI+AB3aZZddlqqqqoZHp06dstFGG+Woo47KP//5z7YuDwCg1XRq6wIAoDmcffbZ2WyzzbJw4cLce++9ueyyy3L33XfnscceS5cuXdq6PFhlZ5xxRk477bS2LgOADkjAB6AUDjjggOyyyy5JkmOOOSa9evXK9773vdxwww35zGc+08bVlc/SpUtTqVTSuXPnti6ldDp16pROnfyIBkDTeYs+AKU0dOjQJMnTTz/daPy2227L0KFDs84666RHjx75xCc+kZkzZzY8//Y17it7vJs//vGPWXvttXP44Ydn6dKljZ576qmnkiSLFy/OmWeemUGDBqV79+5ZZ511MnTo0Nx+++3L7W/OnDk56qij0r179/To0SOjRo3KnDlzVmn9S5YsyYQJE/KBD3wgXbp0yQYbbJA999wzU6ZMaZhz1FFHZd11180zzzyT4cOHZ5111smGG26Ys88+O0VRLPc5Oe+883L++edniy22SG1tbZ544olVXs/OO++cQw45pNHY9ttvn6qqqjzyyCMNY1dddVWqqqoa9eQ/FUWRXr16ZezYsQ1jlUolPXr0SE1NTaPPz/e+97106tQpb7zxxrt+rubMmZOTTjopm266aWpra7PxxhvnyCOPzCuvvJLk3/dRWNnxcMcddyRJ/v73v+dLX/pSPvjBD6Zr167ZYIMN8ulPfzrPPfdck/uysmvwf/WrX2XQoEHp2rVrevbsmcMOOywvvPDCu64NgDWLXw8DUEpvB6v111+/YezWW2/NAQcckM033zxnnXVW3nrrrVxwwQXZY4898tBDD2XTTTdN796988tf/rLRvpYsWZKTTjrpXc9W33jjjfnUpz6VkSNH5uc//3lqamoanpsyZUquu+66PPvss6lUKvnZz36Www8/PMcee2zmz5+fSy65JMOHD8/999+fHXfcMcm/g+wnPvGJ3H333Tn++OOzzTbb5LrrrsuoUaNWaf1nnXVWJk6cmGOOOSa77rpr5s2blwcffDAPPfRQ9ttvv4Z5y5Yty8c+9rHstttuOffcczN58uSMHz8+S5cuzdlnn91on5deemkWLlyY4447LrW1tenZs2fmzZu3SusZOnRofvOb3zTs67XXXsvjjz+e6urq/OlPf8oOO+yQJPnTn/6U3r17Z5tttlnhuqqqqrLHHnvkrrvuahh75JFHMnfu3FRXV+fPf/5zDjrooIZ97bTTTll33XVX+nl64403MnTo0MycOTNf+MIXsvPOO+eVV17JDTfckH/84x/p1atXzj///OV+SfDDH/4wM2bMyAYbbJAkeeCBB3LPPffksMMOy8Ybb5znnnsuF110UfbZZ5888cQTWXvttZvUl3f6zne+k29+85v5zGc+k2OOOSYvv/xyLrjgguy11155+OGH06NHj5VuC8AapACADuzSSy8tkhS33npr8fLLLxcvvPBCcc011xS9e/cuamtrixdeeKFh7o477lj06dOnePXVVxvG/vKXvxTV1dXFkUceudLX+NKXvlTU1NQUt912W8PY3nvvXXzoQx8qiqIofve73xVrrbVWceyxxxbLli1rmPP6668XvXr1KjbZZJNixowZRVEUxdKlS4tFixY12v/rr79e1NXVFV/4whcaxq6//voiSXHuuec2jC1durQYOnRokaS49NJL3/XzMnDgwOKggw561zmjRo0qkhRf/vKXG8YqlUpx0EEHFZ07dy5efvnloiiK4tlnny2SFN26dSteeumlRvtY1fVcffXVRZLiiSeeKIqiKG644Yaitra2+PjHP16MHDmyYd4OO+xQfPKTn3zXur///e8XNTU1xbx584qiKIof/ehHxYABA4pdd921OPXUU4uiKIply5YVPXr0KE466aR33deZZ55ZJCmuvfba5Z6rVCor3Oa3v/1tkaQ4++yzG8befPPN5eZNmzatSFL84he/aBhblb6MHz+++M8f0Z577rmipqam+M53vtNo3qOPPlp06tRpuXEA1lzeog9AKQwbNiy9e/dO//7986lPfSrrrLNObrjhhmy88cZJkhdffDEzZszIUUcdlZ49ezZst8MOO2S//fbLzTffvML9/uIXv8iPf/zjnHvuudl3332Xe/43v/lNRo4cmf/+7//O//7v/6a6+t//tc6aNSu77LJLXnnlley7774ZOHBgkqSmpqbhnQCVSiWvvfZali5dml122SUPPfRQw35vvvnmdOrUKV/84hcbxmpqavLlL395lT4fPXr0yOOPP56//e1v7zn3hBNOaPh3VVVVTjjhhCxevDi33npro3mHHnpoevfu3WhsVdfz9iUTb595/9Of/pQPf/jD2W+//fKnP/0pyb/fKv/YY481zF2ZoUOHZtmyZbnnnnsa9jV06NAMHTq0YV+PPfZY5syZ8577+t3vfpeBAwfmk5/85HLPreht8k888US+8IUv5BOf+ETOOOOMhvGuXbs2/HvJkiV59dVXs+WWW6ZHjx6NPg9N6cvbrr322lQqlXzmM5/JK6+80vDo27dvPvCBD6zw8g4A1kwCPgClMGnSpEyZMiXXXHNNDjzwwLzyyiupra1teP7vf/97kuSDH/zgcttus802eeWVV7JgwYJG4zNmzMjxxx+fww8/vNE132979tln8/nPfz6HHnpoLrjggkaBcJ111skXvvCFbLLJJsttd/nll2eHHXZouAa7d+/euemmmzJ37txG9fbr12+5t5evqP4VOfvsszNnzpxstdVW2X777XPyySc3utb9bdXV1dl8880bjW211VZJstz145ttttkKX2tV1lNXV5cPfOADDQH87VC+11575V//+leeeeaZ/PnPf06lUnnPUL7zzjtn7bXXXuG+HnzwwSxcuLDhuT333PNd9/X0009nu+22e9c5b5s3b14OOeSQbLTRRvnFL37RqN9vvfVWzjzzzPTv3z+1tbXp1atXevfunTlz5jT6PKxqX/7T3/72txRFkQ984APp3bt3o8fMmTPz0ksvrVL9AJSfa/ABKIVdd9214S76I0aMyJ577pnPfvazmTVr1rteg70yr7/+eg499NBstdVW+dnPfrbCOf369Uu/fv1y880358EHH2x4/STZeOONc/rpp+cnP/lJo21+9atf5aijjsqIESNy8sknp0+fPqmpqcnEiROXuyHg+7HXXnvl6aefzu9///v88Y9/zM9+9rP88Ic/zMUXX5xjjjlmtfb5n2ep39aU9ey5556ZOnVq3nrrrUyfPj1nnnlmtttuu/To0SN/+tOfMnPmzKy77rrZaaed3rWOtdZaK4MHD85dd92Vp556KvX19Rk6dGjq6uqyZMmS3HffffnTn/6Urbfeerl3HLwfRx11VP71r3/l/vvvT7du3Ro99+UvfzmXXnppTjzxxAwZMiTdu3dPVVVVDjvssFQqlYZ5q9OXSqWSqqqq/N//+38b3dvhbatzfANQTgI+AKXzdsDcd999c+GFF+a0007LgAEDkvz7rfPv9OSTT6ZXr15ZZ511kvw7UH3uc5/LnDlzcuuttzbcIO2dunTpkhtvvDEf+chH8rGPfSx33nlnPvShD71rbddcc00233zzXHvttY3OAI8fP77RvAEDBmTq1Kl54403GgW4FdW/Mj179szo0aMzevTovPHGG9lrr71y1llnNQqSlUolzzzzTMNZ+yT561//muTfd49/L6u6nuTfb62/9NJLc+WVV2bZsmXZfffdU11dnT333LMh4O++++4rDLEr2tf3vve93HrrrenVq1e23nrrVFVV5UMf+lD+9Kc/5U9/+lP+67/+6z33s8UWW+Sxxx57z3nnnHNOrr/++lx77bXZeuutl3v+mmuuyahRo/I///M/DWMLFy5c4V89WJW+vLPGoiiy2WabNeoTALyTt+gDUEr77LNPdt1115x//vlZuHBh+vXrlx133DGXX355o9D12GOP5Y9//GMOPPDAhrEJEybklltuyW9+85uVvi39bd27d88tt9ySPn36ZL/99nvPs/Bvh9fiP/4M3X333Zdp06Y1mnfggQdm6dKlueiiixrGli1blgsuuOA9154kr776aqOP11133Wy55ZZZtGjRcnMvvPDChn8XRZELL7wwa621Vj760Y++5+us6nqS/3cd/ve+973ssMMO6d69e8P41KlT8+CDD77n2/P/c1+LFi3K+eefnz333LPhlwtDhw7NL3/5y/zrX/9apX0deuih+ctf/pLrrrtuuefeXtOtt96aM844I9/4xjcyYsSIFe6npqam0ecgSS644IIsW7as0VhT+vK2Qw45JDU1NZkwYcJyr1EUxXL7BGDN5Qw+AKV18skn59Of/nQuu+yyHH/88fn+97+fAw44IEOGDMnRRx/d8GfyunfvnrPOOitJ8uijj+Zb3/pW9tprr7z00kv51a9+1Wifn//855d7nV69emXKlCnZc889M2zYsNx9993ZaKONVljTf/3Xf+Xaa6/NJz/5yRx00EF59tlnc/HFF2fbbbdt9KfYDj744Oyxxx457bTT8txzz2XbbbfNtdde2+h67nez7bbbZp999smgQYPSs2fPPPjgg7nmmmsa3VAv+fe7ECZPnpxRo0Zl8ODB+b//9//mpptuyumnn75Kb29f1fUkyZZbbpm+fftm1qxZjW4WuNdee+XUU09NklUO+EOGDEmnTp0ya9asHHfccY329fYvRVZlXyeffHKuueaafPrTn84XvvCFDBo0KK+99lpuuOGGXHzxxRk4cGAOP/zw9O7dOx/4wAeWOx7222+/1NXV5b/+67/yy1/+Mt27d8+2226badOm5dZbb234M3pvW9W+/Kctttgi3/72tzNu3Lg899xzGTFiRNZbb708++yzue6663Lcccfl61//+ip93gAouTa7fz8ANIO3/0zeAw88sNxzy5YtK7bYYotiiy22KJYuXVoURVHceuutxR577FF07dq16NatW3HwwQc3/Om2oiiK22+/vUiy0sfb/vPP5L3tqaeeKvr161dss802DX9ibsCAAcWoUaMa5lQqleK73/1uMWDAgKK2trbYaaedihtvvLEYNWpUMWDAgEb7e/XVV4sjjjii6NatW9G9e/fiiCOOKB5++OFV+jN53/72t4tdd9216NGjR9G1a9di6623Lr7zne8UixcvbpgzatSoYp111imefvrpYv/99y/WXnvtoq6urhg/fnyjP/f39p/J+/73v7/c6zRlPUVRFJ/+9KeLJMVVV13VMLZ48eJi7bXXLjp37ly89dZb77qu//ThD3+4SFLcd999DWP/+Mc/iiRF//79V3k/r776anHCCScUG220UdG5c+di4403LkaNGlW88sorRVEU73o83H777UVR/PtPA44ePbro1atXse666xbDhw8vnnzyyeX6vyp9eeefyXvb7373u2LPPfcs1llnnWKdddYptt5662LMmDHFrFmzVnmtAJRbVVG8471eAMAa4aijjso111yz3Jl2AKBjcg0+AAAAlICADwAAACUg4AMAAEAJuAYfAAAASsAZfAAAACgBAR8AAABKoFNbF9AeVCqV/Otf/8p6662Xqqqqti4HAACAkiuKIvPnz8+GG26Y6urmOfcu4Cf517/+lf79+7d1GQAAAKxhXnjhhWy88cbNsi8BP8l6662X5N+f2G7durVxNStXqVTy8ssvp3fv3s32Gx5alx52bPrX8elhx6eHHZ8edmz61/HpYfsxb9689O/fvyGPNgcBP2l4W363bt3afcBfuHBhunXr5ouxg9LDjk3/Oj497Pj0sOPTw45N/zo+PWx/mvMycR0FAACAEhDwAQAAoAQEfAAAACgBAR8AAABKQMAHAACAEhDwAQAAoAQEfAAAACgBAR8AAABKQMAHAACAEhDwAQAAoAQEfAAAACgBAR8AAABKQMAHAACAEhDwAQAAoAQEfAAAACgBAR8AAABKQMAHAACAEujU1gUAAAAdx9GXP5CZr1elkqq2LqXFPHfOQW1dAqwWZ/ABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEqgTQP+xIkT8+EPfzjrrbde+vTpkxEjRmTWrFmN5uyzzz6pqqpq9Dj++OMbzXn++edz0EEHZe21106fPn1y8sknZ+nSpa25FAAAAGhTndryxe+8886MGTMmH/7wh7N06dKcfvrp2X///fPEE09knXXWaZh37LHH5uyzz274eO21127497Jly3LQQQelb9++ueeee/Liiy/myCOPzFprrZXvfve7rboeAAAAaCttGvAnT57c6OPLLrssffr0yfTp07PXXns1jK+99trp27fvCvfxxz/+MU888URuvfXW1NXVZccdd8y3vvWtnHrqqTnrrLPSuXPnFl0DAAAAtAdtGvDfae7cuUmSnj17Nhr/9a9/nV/96lfp27dvDj744Hzzm99sOIs/bdq0bL/99qmrq2uYP3z48Hzxi1/M448/np122mm511m0aFEWLVrU8PG8efOSJJVKJZVKpdnX1VwqlUqKomjXNfLu9LBj07+OTw87Pj3s+PSwY6tUKqlKUfobeZX5+PQ12H60RA/aTcCvVCo58cQTs8cee2S77bZrGP/sZz+bAQMGZMMNN8wjjzySU089NbNmzcq1116bJKmvr28U7pM0fFxfX7/C15o4cWImTJiw3PjLL7+chQsXNteSml2lUsncuXNTFEWqq8v+bbWc9LBj07+OTw87Pj3s+PSwY6tUKum/blKVpJKirctpMS+99FJbl9BifA22H/Pnz2/2fbabgD9mzJg89thjufvuuxuNH3fccQ3/3n777dOvX7989KMfzdNPP50ttthitV5r3LhxGTt2bMPH8+bNS//+/dO7d+9069Zt9RbQCiqVSqqqqtK7d29fjB2UHnZs+tfx6WHHp4cdnx52bJVKJS+8kTz5elJJVVuX02L69OnT1iW0GF+D7UeXLl2afZ/tIuCfcMIJufHGG3PXXXdl4403fte5gwcPTpI89dRT2WKLLdK3b9/cf//9jebMnj07SVZ63X5tbW1qa2uXG6+urm73B3lVVVWHqJOV08OOTf86Pj3s+PSw49PDjq1IVSr//6Osyn5s+hpsH1ri89+mHS2KIieccEKuu+663Hbbbdlss83ec5sZM2YkSfr165ckGTJkSB599NFGb6OZMmVKunXrlm233bZF6gYAAID2pk3P4I8ZMyZXXHFFfv/732e99dZruGa+e/fu6dq1a55++ulcccUVOfDAA7PBBhvkkUceyUknnZS99torO+ywQ5Jk//33z7bbbpsjjjgi5557burr63PGGWdkzJgxKzxLDwAAAGXUpmfwL7roosydOzf77LNP+vXr1/C46qqrkiSdO3fOrbfemv333z9bb711vva1r+XQQw/NH/7wh4Z91NTU5MYbb0xNTU2GDBmSz3/+8znyyCNz9tlnt9WyAAAAoNW16Rn8onj3O2/2798/d95553vuZ8CAAbn55pubqywAAADocNxVAQAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEqgTQP+xIkT8+EPfzjrrbde+vTpkxEjRmTWrFmN5ixcuDBjxozJBhtskHXXXTeHHnpoZs+e3WjO888/n4MOOihrr712+vTpk5NPPjlLly5tzaUAAABAm2rTgH/nnXdmzJgxuffeezNlypQsWbIk+++/fxYsWNAw56STTsof/vCHXH311bnzzjvzr3/9K4ccckjD88uWLctBBx2UxYsX55577snll1+eyy67LGeeeWZbLAkAAADaRKe2fPHJkyc3+viyyy5Lnz59Mn369Oy1116ZO3duLrnkklxxxRX5yEc+kiS59NJLs8022+Tee+/Nbrvtlj/+8Y954okncuutt6auri477rhjvvWtb+XUU0/NWWedlc6dO7fF0gAAAKBVtWnAf6e5c+cmSXr27JkkmT59epYsWZJhw4Y1zNl6662zySabZNq0adltt90ybdq0bL/99qmrq2uYM3z48Hzxi1/M448/np122mm511m0aFEWLVrU8PG8efOSJJVKJZVKpUXW1hwqlUqKomjXNfLu9LBj07+OTw87Pj3s+PSwY6tUKqlKUfobeZX5+PQ12H60RA/aTcCvVCo58cQTs8cee2S77bZLktTX16dz587p0aNHo7l1dXWpr69vmPOf4f7t599+bkUmTpyYCRMmLDf+8ssvZ+HChe93KS2mUqlk7ty5KYoi1dVl/7ZaTnrYselfx6eHHZ8ednx62LFVKpX0XzepSlJJ0dbltJiXXnqprUtoMb4G24/58+c3+z7bTcAfM2ZMHnvssdx9990t/lrjxo3L2LFjGz6eN29e+vfvn969e6dbt24t/vqrq1KppKqqKr179/bF2EHpYcemfx2fHnZ8etjx6WHHVqlU8sIbyZOvJ5VUtXU5LaZPnz5tXUKL8TXYfnTp0qXZ99kuAv4JJ5yQG2+8MXfddVc23njjhvG+fftm8eLFmTNnTqOz+LNnz07fvn0b5tx///2N9vf2XfbfnvNOtbW1qa2tXW68urq63R/kVVVVHaJOVk4POzb96/j0sOPTw45PDzu2IlWp/P+Psir7selrsH1oic9/m3a0KIqccMIJue6663Lbbbdls802a/T8oEGDstZaa2Xq1KkNY7Nmzcrzzz+fIUOGJEmGDBmSRx99tNHbaKZMmZJu3bpl2223bZ2FAAAAQBtr0zP4Y8aMyRVXXJHf//73WW+99Rqume/evXu6du2a7t275+ijj87YsWPTs2fPdOvWLV/+8pczZMiQ7LbbbkmS/fffP9tuu22OOOKInHvuuamvr88ZZ5yRMWPGrPAsPQAAAJRRmwb8iy66KEmyzz77NBq/9NJLc9RRRyVJfvjDH6a6ujqHHnpoFi1alOHDh+fHP/5xw9yamprceOON+eIXv5ghQ4ZknXXWyahRo3L22We31jIAAACgzbVpwC+K977zZpcuXTJp0qRMmjRppXMGDBiQm2++uTlLAwAAgA7FXRUAAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEpAwAcAAIASEPABAACgBAR8AAAAKAEBHwAAAEqgyQH/zDPPzO23356FCxe2RD0AAADAamhywJ82bVoOPvjg9OjRI0OHDs0ZZ5yRW2+9NW+99VZL1AcAAACsgiYH/ClTpmTOnDmZOnVqDjzwwDz44IM55JBD0qNHj+y5554tUSMAAADwHjqt1kadOmWPPfZI796907Nnz6y33nq5/vrr8+STTzZ3fQAAAMAqaPIZ/J/85Cf57Gc/m4022ii77757Jk+enD333DMPPvhgXn755ZaoEQAAAHgPTT6Df/zxx6d379752te+li996UtZd911W6IuAAAAoAmafAb/2muvzec+97lceeWV6d27d3bfffecfvrp+eMf/5g333yzJWoEAAAA3kOTz+CPGDEiI0aMSJLMnTs3f/rTn3L11Vfnv/7rv1JdXe3P5wEAAEAbWK2b7L366qu58847c8cdd+SOO+7I448/nvXXXz9Dhw5t7voAAACAVdDkgL/99ttn5syZWX/99bPXXnvl2GOPzd57750ddtihJeoDAAAAVsFq3WRv7733znbbbdcS9QAAAACrockBf8yYMS1RBwAAAPA+rNY1+P/4xz9yww035Pnnn8/ixYsbPfeDH/ygWQoDAAAAVl2TA/7UqVPz8Y9/PJtvvnmefPLJbLfddnnuuedSFEV23nnnlqgRAAAAeA/VTd1g3Lhx+frXv55HH300Xbp0ye9+97u88MIL2XvvvfPpT3+6JWoEAAAA3kOTA/7MmTNz5JFHJkk6deqUt956K+uuu27OPvvsfO9732v2AgEAAID31uSAv8466zRcd9+vX788/fTTDc+98sorzVcZAAAAsMqafA3+brvtlrvvvjvbbLNNDjzwwHzta1/Lo48+mmuvvTa77bZbS9QIAAAAvIcmB/wf/OAHeeONN5IkEyZMyBtvvJGrrroqH/jAB9xBHwAAANpIkwL+smXL8o9//CM77LBDkn+/Xf/iiy9ukcIAAACAVdeka/Bramqy//775/XXX2+pegAAAIDV0OSb7G233XZ55plnWqIWAAAAYDU1OeB/+9vfzte//vXceOONefHFFzNv3rxGj6a46667cvDBB2fDDTdMVVVVrr/++kbPH3XUUamqqmr0+NjHPtZozmuvvZbPfe5z6datW3r06JGjjz664R4BAAAAsKZo8k32DjzwwCTJxz/+8VRVVTWMF0WRqqqqLFu2bJX3tWDBggwcODBf+MIXcsghh6xwzsc+9rFceumlDR/X1tY2ev5zn/tcXnzxxUyZMiVLlizJ6NGjc9xxx+WKK65oyrIAAACgQ2tywL/99tub7cUPOOCAHHDAAe86p7a2Nn379l3hczNnzszkyZPzwAMPZJdddkmSXHDBBTnwwANz3nnnZcMNN2y2WgEAAKA9a3LA33vvvVuijpW644470qdPn6y//vr5yEc+km9/+9vZYIMNkiTTpk1Ljx49GsJ9kgwbNizV1dW577778slPfnKF+1y0aFEWLVrU8PHblxZUKpVUKpUWXM37U6lUUhRFu66Rd6eHHZv+dXx62PHpYcenhx1bpVJJVYqmX+fbwZT5+PQ12H60RA+aHPCT5PXXX88ll1ySmTNnJkm23XbbjB49Oj179mzW4j72sY/lkEMOyWabbZann346p59+eg444IBMmzYtNTU1qa+vT58+fRpt06lTp/Ts2TP19fUr3e/EiRMzYcKE5cZffvnlLFy4sFnX0JwqlUrmzp2boihSXV32b6vlpIcdm/51fHrY8elhx7cm9PDoyx9o6xJaTHWS/usmVUkqKdq6nBbz0ksvtXUJLWZN+BrsKObPn9/s+2xywH/7xnjdu3dvOHP+ox/9KGeffXb+8Ic/ZK+99mq24g477LCGf2+//fbZYYcdssUWW+SOO+7IRz/60dXe77hx4zJ27NiGj+fNm5f+/fund+/e6dat2/uquSVVKpVUVVWld+/evhg7KD3s2PSv49PDjk8PO741oYczX69670kdVHWKFEmefD2ppLzrfOdJxDJZE74GO4ouXbo0+z6bHPDHjBmTkSNH5qKLLkpNTU2SZNmyZfnSl76UMWPG5NFHH232It+2+eabp1evXnnqqafy0Y9+NH379l3ut2tLly7Na6+9ttLr9pN/X9f/zpv1JUl1dXW7P8irqqo6RJ2snB52bPrX8elhx6eHHV/Ze1jm4JskRf69xjKvs6zH5tvK/jXYUbTE57/Je3zqqafyta99rSHcJ0lNTU3Gjh2bp556qlmLe6d//OMfefXVV9OvX78kyZAhQzJnzpxMnz69Yc5tt92WSqWSwYMHt2gtAAAA0J40OeDvvPPODdfe/6eZM2dm4MCBTdrXG2+8kRkzZmTGjBlJkmeffTYzZszI888/nzfeeCMnn3xy7r333jz33HOZOnVqPvGJT2TLLbfM8OHDkyTbbLNNPvaxj+XYY4/N/fffnz//+c854YQTcthhh7mDPgAAAGuUJr9F/ytf+Uq++tWv5qmnnspuu+2WJLn33nszadKknHPOOXnkkUca5u6www7vuq8HH3ww++67b8PHb18XP2rUqFx00UV55JFHcvnll2fOnDnZcMMNs//+++db3/pWo7fX//rXv84JJ5yQj370o6murs6hhx6aH/3oR01dFgAAAHRoTQ74hx9+eJLklFNOWeFzVVVVKYoiVVVVWbZs2bvua5999klRrPzum7fccst71tOzZ89cccUV7zkPAAAAyqzJAf/ZZ59tiToAAACA96HJAX/AgAEtUQcAAADwPjT5JnuXX355brrppoaPTznllPTo0SO77757/v73vzdrcQAAAMCqaXLA/+53v5uuXbsmSaZNm5YLL7ww5557bnr16pWTTjqp2QsEAAAA3luT36L/wgsvZMstt0ySXH/99fnUpz6V4447LnvssUf22Wef5q4PAAAAWAVNPoO/7rrr5tVXX02S/PGPf8x+++2XJOnSpUveeuut5q0OAAAAWCVNPoO/33775ZhjjslOO+2Uv/71rznwwAOTJI8//ng23XTT5q4PAAAAWAVNPoM/adKkDBkyJC+//HJ+97vfZYMNNkiSTJ8+PYcffnizFwgAAAC8tyafwe/Ro0cuvPDC5cYnTJjQLAUBAAAATdfkM/gAAABA+yPgAwAAQAkI+AAAAFACAj4AAACUgIAPAAAAJdDku+gnyTXXXJPf/va3ef7557N48eJGzz300EPNUhgAAACw6pp8Bv9HP/pRRo8enbq6ujz88MPZdddds8EGG+SZZ57JAQcc0BI1AgAAAO+hyQH/xz/+cX7yk5/kggsuSOfOnXPKKadkypQp+cpXvpK5c+e2RI0AAADAe2hywH/++eez++67J0m6du2a+fPnJ0mOOOKI/OY3v2ne6gAAAIBV0uSA37dv37z22mtJkk022ST33ntvkuTZZ59NURTNWx0AAACwSpoc8D/ykY/khhtuSJKMHj06J510Uvbbb7+MHDkyn/zkJ5u9QAAAAOC9Nfku+j/5yU9SqVSSJGPGjMkGG2yQe+65Jx//+Mfz3//9381eIAAAAPDemhzwq6urU139/078H3bYYTnssMOatSgAAACgaZoc8JPk9ddfzyWXXJKZM2cmSbbddtuMHj06PXv2bNbiAAAAgFXT5Gvw77rrrmy22Wb50Y9+lNdffz2vv/56fvSjH2WzzTbLXXfd1RI1AgAAAO+hyWfwx4wZk8985jO56KKLUlNTkyRZtmxZvvSlL2XMmDF59NFHm71IAAAA4N01+Qz+U089la997WsN4T5JampqMnbs2Dz11FPNWhwAAACwapoc8HfeeeeGa+//08yZMzNw4MBmKQoAAABomlV6i/4jjzzS8O+vfOUr+epXv5qnnnoqu+22W5Lk3nvvzaRJk3LOOee0TJUAAADAu1qlgL/jjjumqqoqRVE0jJ1yyinLzfvsZz+bkSNHNl91AAAAwCpZpYD/7LPPtnQdAAAAwPuwSgF/wIABLV0HAAAA8D40+SZ7NTU12XffffPaa681Gp89e3ajO+sDAAAArafJAb8oiixatCi77LJLHn/88eWeAwAAAFpfkwN+VVVVfve73+Xggw/OkCFD8vvf/77RcwAAAEDrW6Vr8P9TURSpqanJ//k//ycf+tCHMnLkyJxxxhk55phjWqI+AACAVrXpaTe1dQktpjpF7jlxl7YugxbS5ID/n4477rh84AMfyKc//encddddzVUTAAAA0ERNfov+gAEDGt1Mb9999829996bF154oVkLAwAAAFZdk8/gP/vss8uNbbnllnn44Ycze/bsZikKAAAAaJomn8F/4IEHct999y03/pe//CUvv/xysxQFAAAANE2Tz+CPGTMmp5xySgYPHtxo/J///Ge+973vrTD8AwDA246+/IHMfL0qlfgLTADNqcln8J944onsvPPOy43vtNNOeeKJJ5qlKAAAAKBpmhzwa2trV3it/YsvvphOnd7XTfkBAACA1dTkgL///vtn3LhxmTt3bsPYnDlzcvrpp2e//fZr1uIAAACAVdPkU+7nnXde9tprrwwYMCA77bRTkmTGjBmpq6vLL3/5y2YvEAAAAHhvTQ74G220UR555JH8+te/zl/+8pd07do1o0ePzuGHH5611lqrJWoEAAAA3sNqXTS/zjrr5LjjjmvuWgAAAIDVtEoB/4YbbsgBBxyQtdZaKzfccMO7zv34xz/eLIUBAAAAq26VAv6IESNSX1+fPn36ZMSIESudV1VVlWXLljVXbQAAAMAqWqWAX6lUVvhvAAAAoH1o8p/JW5l//OMfrssHAACANtJsAf/VV1/NJZdc0ly7AwAAAJqg2QI+AAAA0HYEfAAAACgBAR8AAABKYJXuop8khxxyyLs+P2fOnPdbCwAAALCaVjngd+/e/T2fP/LII993QQAAAEDTrXLAv/TSS1uyDgAAAOB9cA0+AAAAlICADwAAACUg4AMAAEAJCPgAAABQAgI+AAAAlICADwAAACWwyn8mDwCAlrfpaTe1dQktqjpFtlm/rasAKCdn8AEAAKAE2jTg33XXXTn44IOz4YYbpqqqKtdff32j54uiyJlnnpl+/fqla9euGTZsWP72t781mvPaa6/lc5/7XLp165YePXrk6KOPzhtv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yzrrrJMdd9wxv/71r1tyaWuM1vw6fNtTTz2V9dZbLz169Gjm1ax5WrN/RVHkvPPOy1ZbbZXa2tpstNFG+c53vtNSS1tjtGYPb7nlluy2225Zb7310rt37xx66KF57rnnWmhla47m6OFf/vKXHH744enfv3+6du2abbbZJv/n//yf5V7rjjvuyM4775za2tpsueWWueyyy1p6eWuE1urhtddem/322y+9e/dOt27dMmTIkNxyyy2tssaya82vw7f9+c9/TqdOnd7z5x7aloDfiu68886MGTMm9957b6ZMmZIlS5Zk//33z4IFCxrmnHTSSfnDH/6Qq6++OnfeeWf+9a9/5ZBDDlluX1/4whcycuTIFb7OvHnzsv/++2fAgAGZPn16vv/97+ess87KT37ykxZb25qitXp4zz33ZIcddsjvfve7PPLIIxk9enSOPPLI3HjjjS22tjVFa/XwbUuWLMnhhx+eoUOHNvta1kSt2b+vfvWr+dnPfpbzzjsvTz75ZG644YbsuuuuLbKuNUlr9fDZZ5/NJz7xiXzkIx/JjBkzcsstt+SVV15Z4X5omubo4fTp09OnT5/86le/yuOPP55vfOMbGTduXC688MKGOc8++2wOOuig7LvvvpkxY0ZOPPHEHHPMMQJiM2itHt51113Zb7/9cvPNN2f69OnZd999c/DBB+fhhx9u1fWWUWv18G1z5szJkUcemY9+9KOtsj7eh4I289JLLxVJijvvvLMoiqKYM2dOsdZaaxVXX311w5yZM2cWSYpp06Ytt/348eOLgQMHLjf+4x//uFh//fWLRYsWNYydeuqpxQc/+MHmX8QarqV6uCIHHnhgMXr06Gapm/+npXt4yimnFJ///OeLSy+9tOjevXtzl7/Ga6n+PfHEE0WnTp2KJ598ssVq599aqodXX3110alTp2LZsmUNYzfccENRVVVVLF68uPkXsgZ7vz1825e+9KVi3333bfj4lFNOKT70oQ81mjNy5Mhi+PDhzbwCWqqHK7LtttsWEyZMaJ7CadDSPRw5cmRxxhlnNOlnV9qGM/htaO7cuUmSnj17Jvn3b9GWLFmSYcOGNczZeuuts8kmm2TatGmrvN9p06Zlr732SufOnRvGhg8fnlmzZuX1119vpupJWq6HK3utt1+H5tOSPbztttty9dVXZ9KkSc1XMI20VP/+8Ic/ZPPNN8+NN96YzTbbLJtuummOOeaYvPbaa827AFqsh4MGDUp1dXUuvfTSLFu2LHPnzs0vf/nLDBs2LGuttVbzLmIN11w9fOf/c9OmTWu0j+TfP8+83/9PWV5L9fCdKpVK5s+f7+eZFtCSPbz00kvzzDPPZPz48S1QOc1NwG8jlUolJ554YvbYY49st912SZL6+vp07tx5uet06+rqUl9fv8r7rq+vT11d3XL7ePs5mkdL9vCdfvvb3+aBBx7I6NGj30/JvENL9vDVV1/NUUcdlcsuuyzdunVrzrL5/7Vk/5555pn8/e9/z9VXX51f/OIXueyyyzJ9+vR86lOfas4lrPFasoebbbZZ/vjHP+b0009PbW1tevTokX/84x/57W9/25xLWOM1Vw/vueeeXHXVVTnuuOMaxlb288y8efPy1ltvNe9C1mAt2cN3Ou+88/LGG2/kM5/5TLPVT8v28G9/+1tOO+20/OpXv0qnTp1abA00H11qI2PGjMljjz2Wu+++u61LYTW1Vg9vv/32jB49Oj/96U/zoQ99qEVfa03Tkj089thj89nPfjZ77bVXs++bf2vJ/lUqlSxatCi/+MUvstVWWyVJLrnkkgwaNCizZs3KBz/4wWZ/zTVRS/awvr4+xx57bEaNGpXDDz888+fPz5lnnplPfepTmTJlSqqqqpr9NddEzdHDxx57LJ/4xCcyfvz47L///s1YHauitXp4xRVXZMKECfn973+fPn36rPZrsbyW6uGyZcvy2c9+NhMmTGj4v5D2zxn8NnDCCSfkxhtvzO23356NN964Ybxv375ZvHhx5syZ02j+7Nmz07dv31Xef9++fZe72/DbHzdlP6xcS/fwbXfeeWcOPvjg/PCHP8yRRx75fsvmP7R0D2+77bacd9556dSpUzp16pSjjz46c+fOTadOnfLzn/+8uZaxxmrp/vXr1y+dOnVq9APNNttskyR5/vnn31/xJGn5Hk6aNCndu3fPueeem5122il77bVXfvWrX2Xq1Km57777mmsZa7Tm6OETTzyRj370oznuuONyxhlnNHpuZT/PdOvWLV27dm3exayhWrqHb7vyyitzzDHH5Le//e1yl13w/rRkD+fPn58HH3wwJ5xwQsPPM2effXb+8pe/pFOnTrnttttadG2sHgG/FRVFkRNOOCHXXXddbrvttmy22WaNnh80aFDWWmutTJ06tWFs1qxZef755zNkyJBVfp0hQ4bkrrvuypIlSxrGpkyZkg9+8INZf/313/9C1mCt1cPk338a6KCDDsr3vve9d327G03TWj2cNm1aZsyY0fA4++yzs95662XGjBn55Cc/2WzrWdO0Vv/22GOPLF26NE8//XTD2F//+tckyYABA97nKtZsrdXDN998M9XVjX/MqampSfLvd2iw+pqrh48//nj23XffjBo1aoV/gnLIkCGN9pH8++eZpv5/yvJaq4dJ8pvf/CajR4/Ob37zmxx00EEts6A1UGv0sFu3bnn00Ucb/Txz/PHH54Mf/GBmzJiRwYMHt+wiWT1td3+/Nc8Xv/jFonv37sUdd9xRvPjiiw2PN998s2HO8ccfX2yyySbFbbfdVjz44IPFkCFDiiFDhjTaz9/+9rfi4YcfLv77v/+72GqrrYqHH364ePjhhxvumj9nzpyirq6uOOKII4rHHnusuPLKK4u11167+N///d9WXW8ZtVYPb7vttmLttdcuxo0b1+h1Xn311VZdbxm1Vg/fyV30m0dr9W/ZsmXFzjvvXOy1117FQw89VDz44IPF4MGDi/32269V11tGrdXDqVOnFlVVVcWECROKv/71r8X06dOL4cOHFwMGDGj0WjRdc/Tw0UcfLXr37l18/vOfb7SPl156qWHOM888U6y99trFySefXMycObOYNGlSUVNTU0yePLlV11tGrdXDX//610WnTp2KSZMmNZozZ86cVl1vGbVWD9/JXfTbPwG/FSVZ4ePSSy9tmPPWW28VX/rSl4r111+/WHvttYtPfvKTxYsvvthoP3vvvfcK9/Pss882zPnLX/5S7LnnnkVtbW2x0UYbFeecc04rrbLcWquHo0aNWuHze++9d+sttqRa8+vwPwn4zaM1+/fPf/6zOOSQQ4p11123qKurK4466ii/ZGsGrdnD3/zmN8VOO+1UrLPOOkXv3r2Lj3/848XMmTNbaaXl1Rw9HD9+/Ar3MWDAgEavdfvttxc77rhj0blz52LzzTdv9Bqsvtbq4cq+TkeNGtV6iy2p1vw6/E8CfvtXVRRF8V5n+QEAAID2zTX4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AECzuuOOO1JVVZU5c+a0dSkAsEYR8AGARo466qhUVVWlqqoqa621VjbbbLOccsopWbhwYVuXBgC8i05tXQAA0P587GMfy6WXXpolS5Zk+vTpGTVqVKqqqvK9732vrUsDAFbCGXwAYDm1tbXp27dv+vfvnxEjRmTYsGGZMmVKkmTRokX5yle+kj59+qRLly7Zc88988ADD6x0X2+++WYOOOCA7LHHHt62DwAtSMAHAN7VY489lnvuuSedO3dOkpxyyin53e9+l8svvzwPPfRQttxyywwfPjyvvfbactvOmTMn++23XyqVSqZMmZIePXq0cvUAsOYQ8AGA5dx4441Zd91106VLl2y//fZ56aWXcvLJJ2fBggW56KKL8v3vfz8HHHBAtt122/z0pz9N165dc8kllzTaR319ffbee+/069cvf/jDH7L22mu30WoAYM3gGnwAYDn77rtvLrrooixYsCA//OEP06lTpxx66KF55JFHsmTJkuyxxx4Nc9daa63suuuumTlzZqN97Lffftl1111z1VVXpaamprWXAABrHGfwAYDlrLPOOtlyyy0zcODA/PznP89999233Bn693LQQQflrrvuyhNPPNFCVQIA/0nABwDeVXV1dU4//fScccYZ2WKLLdK5c+f8+c9/bnh+yZIleeCBB7Lttts22u6cc87JqFGj8tGPflTIB4BWIOADAO/p05/+dGpqanLRRRfli1/8Yk4++eRMnjw5TzzxRI499ti8+eabOfroo5fb7rzzzsvnPve5fOQjH8mTTz7ZBpUDwJrDNfgAwHvq1KlTTjjhhJx77rl59tlnU6lUcsQRR2T+/PnZZZddcsstt2T99ddf4bY//OEPs2zZsnzkIx/JHXfcka222qqVqweANUNVURRFWxcBAAAAvD/eog8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8A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gJJriRzarq7BBwAAAFaPgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJRAuwz4kyZNyqabbpouXbpk8ODBuf/++991/pw5czJmzJj069cvtbW12WqrrXLzzTe3UrUAAADQ9jq1dQHvdNVVV2Xs2LG5+OKLM3jw4Jx//vkZPnx4Zs2alT59+iw3f/Hixdlvv/3Sp0+fXHPNNdloo43y97//PT169Gj94gEAAKCNVBVFUbR1Ef9p8ODB+fCHP5wLL7wwSVKpVNK/f/98+ctfzmmnnbbc/Isvvjjf//738+STT2attdZardecN29eunfvnrlz56Zbt27vq34AAAB4Ly2RQ9vVW/QXL16c6dOnZ9iwYQ1j1dXVGTZsWKZNm7bCbW644YYMGTIkY8aMSV1dXbbbbrt897vfzbJly1b6OosWLcq8efMaPQAAAKAja1cB/5VXXsmyZctSV1fXaLyuri719fUr3OaZZ57JNddck2XLluXmm2/ON7/5zfzP//xPvv3tb6/0dSZOnJju3bs3PPr379+s6wAAAIDW1q4C/uqoVCrp06dPfvKTn2TQoEEZOXJkvvGNb+Tiiy9e6Tbjxo3L3LlzGx4vvPBCK1YMAAAAza9d3WSvV69eqampyezZsxuNz549O3379l3hNv369ctaa62VmpqahrFtttkm9fX1Wbx4cTp37rzcNrW1tamtrW3e4gEAAKANtasz+J07d86gQYMyderUhrFKpZKpU6dmyJAhK9xmjz32yFNPPZVKpdIw9te//jX9+vVbYbgHAACAMmpXAT9Jxo4dm5/+9Ke5/PLLM3PmzHzxi1/MggULMnr06CTJkUcemXHjxjXM/+IXv5jXXnstX/3qV/PXv/41N910U7773e9mzJgxbbUEAAAAaHXt6i36STJy5Mi8/PLLOfPMM1NfX58dd9wxkydPbrjx3vPPP5/q6v/3e4n+/fvnlltuyUknnZQddtghG220Ub761a/m1FNPbaslAAAAQKurKoqiaOsi2lpL/P1BAAAAWJmWyKHt7i36AAAAQNMJ+AAAAFACAj4AAACUgIAPAAAAJSDgAwAAQAkI+AAAAFACAj4AAACUgIAPAAAAJSDgAwAAQAkI+AAAAFACAj4AAACUgIAPAAAAJSDgAwAAQAkI+AAAAFACAj4AAACUgIAPAAAAJSDgAwAAQAkI+AAAAFACAj4AAACUgIAPAAAAJSDgAwAAQAkI+AAAAFACAj4AAACUgIAPAAAAJSDgAwAAQAkI+AAAAFACAj4AAACUgIAPAAAAJSDgAwAAQAkI+AAAAFACAj4AAACUgIAPAAAAJSDgAwAAQAkI+AAAAFACAj4AAACUgIAPAAAAJSDgAwAAQAkI+AAAAFACAj4AAACUgIAPAAAAJSDgAwAAQAkI+AAAAFACAj4AAACUgIAPAAAAJSDgAwAAQAkI+AAAAFACAj4AAACUgIAPAAAAJSDgAwAAQAkI+AAAAFACAj4AAACUgIAPAAAAJSDgAwAAQAkI+AAAAFACAj4AAACUgIAPAAAAJSDgAwAAQAkI+AAAAFACAj4AAACUgIAPAAAAJSDgAwAAQAkI+AAAAFACAj4AAACUgIAPAAAAJSDgAwAAQAkI+AAAAFACAj4AAACUgIAPAAAAJSDgAwAAQAkI+AAAAFACAj4AAACUgIAPAAAAJSDgAwAAQAm0y4A/adKkbLrppunSpUsGDx6c+++/f5W2u/LKK1NVVZURI0a0bIEAAADQzrS7gH/VVVdl7NixGT9+fB566KEMHDgww4cPz0svvfSu2z333HP5+te/nqFDh7ZSpQAAANB+tLuA/4Mf/CDHHntsRo8enW233TYXX3xx1l577fz85z9f6TbLli3L5z73uUyYMCGbb755K1YLAAAA7UO7CviLFy/O9OnTM2zYsIax6urqDBs2LNOmTVvpdmeffXb69OmTo48+epVeZ9GiRZk3b16jBwAAAHRk7Srgv/LKK1m2bFnq6uoajdfV1aW+vn6F29x999255JJL8tOf/nSVX2fixInp3r17w6N///7vq24AAABoa+0q4DfV/Pnzc8QRR+SnP/1pevXqtcrbjRs3LnPnzm14vPDCCy1YJQAAALS8Tm1dwH/q1atXampqMnv27Ebjs2fPTt++fZeb//TTT+e5557LwQcf3DBWqVSSJJ06dcqsWbOyxRZbLLddbW1tamtrm7l6AAAAaDvt6gx+586dM2jQoEydOrVhrFKpZOrUqRkyZMhy87feeus8+uijmTFjRsPj4x//ePbdd9/MmDHDW+8BAABYY7SrM/hJMnbs2IwaNSq77LJLdt1115x//vlZsGBBRo8enSQ58sgjs9FGG2XixInp0qVLtttuu0bb9+jRI0mWGwcAAIAya3cBf+TIkXn55Zdz5plnpr6+PjvuuGMmT57ccOO9559/PtXV7eqNBwAAANDmqoqiKNq6iLY2b968dO/ePXPnzk23bt3auhwAAABKriVyqFPhAAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUALtMuBPmjQpm266abp06ZLBgwfn/vvvX+ncn/70pxk6dGjWX3/9rL/++hk2bNi7zgcAAIAyancB/6qrrsrYsWMzfvz4PPTQQxk4cGCGDx+el156aYXz77jjjhx++OG5/fbbM23atPTv3z/7779//vnPf7Zy5QAAANB2qoqiKNq6iP80ePDgfPjDH86FF16YJKlUKunfv3++/OUv57TTTnvP7ZctW5b1118/F154YY488shVes158+ale/fumTt3brp16/a+6gcAAID30hI5tF2dwV+8eHGmT5+eYcOGNYxVV1dn2LBhmTZt2irt480338ySJUvSs2fPlc5ZtGhR5s2b1+gBAAAAHVm7CvivvPJKli1blrq6ukbjdXV1qa+vX6V9nHrqqdlwww0b/ZLgnSZOnJju3bs3PPr37/++6gYAAIC21q4C/vt1zjnn5Morr8x1112XLl26rHTeuHHjMnfu3IbHCy+80IpVAgAAQPPr1NYF/KdevXqlpqYms2fPbjQ+e/bs9O3b9123Pe+883LOOefk1ltvzQ477PCuc2tra1NbW/u+6wUAAID2ol2dwe/cuXMGDRqUqVOnNoxVKpVMnTo1Q4YMWel25557br71rW9l8uTJ2WWXXVqjVAAAAGhX2tUZ/CQZO3ZsRo0alV122SW77rprzj///CxYsCCjR49Okhx55JHZaKONMnHixCTJ9773vZx55pm54oorsummmzZcq7/uuutm3XXXbbN1AAAAQGtqdwF/5MiRefnll3PmmWemvr4+O+64YyZPntxw473nn38+1dX/740HF110URYvXpxPfepTjfYzfvz4nHXWWa1ZOgAAALSZqqIoirYuoq21xN8fBAAAgJVpiRzarq7BBwAAAFaPgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJSAgA8AAAAlIOADAABACQj4AAAAUAICPgAAAJRAuwz4kyZNyqabbpouXbpk8ODBuf/++991/tVXX52tt946Xbp0yfbbb5+bb765lSoFAACA9qHdBfyrrroqY8eOzfjx4/PQQw9l4MCBGT58eF566aUVzr/nnnty+OGH5+ijj87DDz+cESNGZMSIEXnsscdauXIAAABoO1VFURRtXcR/Gjx4cD784Q/nwgsvTJJUKpX0798/X/7yl3PaaactN3/kyJFZsGBBbrzxxoax3XbbLTvuuGMuvvjiVXrNefPmpXv37pk7d266devWPAsBAACAlWiJHNqpWfbSTBYvXpzp06dn3LhxDWPV1dUZNmxYpk2btsJtpk2blrFjxzYaGz58eK6//vqVvs6iRYuyaNGiho/nzp2b5N+fYAAAAGhpb+fP5jzn3q4C/iuvvJJly5alrq6u0XhdXV2efPLJFW5TX1+/wvn19fUrfZ2JEydmwoQJy433799/NaoGAACA1fPqq6+me/fuzbKvdhXwW8u4ceManfWfM2dOBgwYkOeff77ZPrHQ3sybNy/9+/fPCy+84FIUSstxzprAcc6awHHOmmDu3LnZZJNN0rNnz2bbZ7sK+L169UpNTU1mz57daHz27Nnp27fvCrfp27dvk+YnSW1tbWpra5cb7969u28glF63bt0c55Se45w1geOcNYHjnDVBdXXz3fu+Xd1Fv3Pnzhk0aFCmTp3aMFapVDJ16tQMGTJkhdsMGTKk0fwkmTJlykrnAwAAQBm1qzP4STJ27NiMGjUqu+yyS3bdddecf/75WbBgQUaPHp0kOfLII7PRRhtl4sSJSZKvfvWr2XvvvfM///M/Oeigg3LllVfmwQcfzE9+8pO2XAYAAAC0qnYX8EeOHJmXX345Z555Zurr67Pjjjtm8uTJDTfSe/755xu9hWH33XfPFVdckTPOOCOnn356PvCBD+T666/Pdtttt8qvWVtbm/Hjx6/wbftQFo5z1gSOc9YEjnPWBI5z1gQtcZxXFc15T34AAACgTbSra/ABAACA1SPgAwAAQAkI+AAAAFACAj4AAACUwBoT8CdNmpRNN900Xbp0yeDBg3P//fe/6/yrr746W2+9dbp06ZLtt98+N998cytVCquvKcf5T3/60wwdOjTrr79+1l9//QwbNuw9vy6gPWjq9/O3XXnllamqqsqIESNatkBoBk09zufMmZMxY8akX79+qa2tzVZbbeVnF9q9ph7n559/fj74wQ+ma9eu6d+/f0466aQsXLiwlaqFprnrrrty8MEHZ8MNN0xVVVWuv/7699zmjjvuyM4775za2tpsueWWueyyy5r8umtEwL/qqqsyduzYjB8/Pg899FAGDhyY4cOH56WXXlrh/HvuuSeHH354jj766Dz88MMZMWJERowYkccee6yVK4dV19Tj/I477sjhhx+e22+/PdOmTUv//v2z//7755///GcrVw6rrqnH+duee+65fP3rX8/QoUNbqVJYfU09zhcvXpz99tsvzz33XK655prMmjUrP/3pT7PRRhu1cuWw6pp6nF9xxRU57bTTMn78+MycOTOXXHJJrrrqqpx++umtXDmsmgULFmTgwIGZNGnSKs1/9tlnc9BBB2XffffNjBkzcuKJJ+aYY47JLbfc0rQXLtYAu+66azFmzJiGj5ctW1ZsuOGGxcSJE1c4/zOf+Uxx0EEHNRobPHhw8d///d8tWie8H009zt9p6dKlxXrrrVdcfvnlLVUivG+rc5wvXbq02H333Yuf/exnxahRo4pPfOITrVAprL6mHucXXXRRsfnmmxeLFy9urRLhfWvqcT5mzJjiIx/5SKOxsWPHFnvssUeL1gnNIUlx3XXXveucU045pfjQhz7UaGzkyJHF8OHDm/RapT+Dv3jx4kyfPj3Dhg1rGKuurs6wYcMybdq0FW4zbdq0RvOTZPjw4SudD21tdY7zd3rzzTezZMmS9OzZs6XKhPdldY/zs88+O3369MnRRx/dGmXC+7I6x/kNN9yQIUOGZMyYMamrq8t2222X7373u1m2bFlrlQ1NsjrH+e67757p06c3vI3/mWeeyc0335wDDzywVWqGltZcGbRTcxbVHr3yyitZtmxZ6urqGo3X1dXlySefXOE29fX1K5xfX1/fYnXC+7E6x/k7nXrqqdlwww2X+8YC7cXqHOd33313LrnkksyYMaMVKoT3b3WO82eeeSa33XZbPve5z+Xmm2/OU089lS996UtZsmRJxo8f3xplQ5OsznH+2c9+Nq+88kr23HPPFEWRpUuX5vjjj/cWfUpjZRl03rx5eeutt9K1a9dV2k/pz+AD7+2cc87JlVdemeuuuy5dunRp63KgWcyfPz9HHHFEfvrTn6ZXr15tXQ60mEqlkj59+uQnP/lJBg0alJEjR+Yb3/hGLr744rYuDZrNHXfcke9+97v58Y9/nIceeijXXnttbrrppnzrW99q69KgXSn9GfxevXqlpqYms2fPbjQ+e/bs9O3bd4Xb9O3bt0nzoa2tznH+tvPOOy/nnHNObr311uywww4tWSa8L009zp9++uk899xzOfjggxvGKpVKkqRTp06ZNWtWtthii5YtGppodb6f9+vXL2uttVZqamoaxrbZZpvU19dn8eLF6dy5c4vWDE21Osf5N7/5zRxxxBE55phjkiTbb799FixYkOOOOy7f+MY3Ul3tvCUd28oyaLdu3Vb57H2yBpzB79y5cwYNGpSpU6c2jFUqlUydOjVDhgxZ4TZDhgxpND9JpkyZstL50NZW5zhPknPPPTff+ta3Mnny5Oyyyy6tUSqstqYe51tvvXUeffTRzJgxo+Hx8Y9/vOHutP3792/N8mGVrM738z322CNPPfVUwy+wkuSvf/1r+vXrJ9zTLq3Ocf7mm28uF+Lf/qXWv+9hBh1bs2XQpt3/r2O68sori9ra2uKyyy4rnnjiieK4444revToUdTX1xdFURRHHHFEcdpppzXM//Of/1x06tSpOO+884qZM2cW48ePL9Zaa63i0UcfbaslwHtq6nF+zjnnFJ07dy6uueaa4sUXX2x4zJ8/v62WAO+pqcf5O7mLPh1BU4/z559/vlhvvfWKE044oZg1a1Zx4403Fn369Cm+/e1vt9US4D019TgfP358sd566xW/+c1vimeeeab44x//WGyxxRbFZz7zmbZaAryr+fPnFw8//HDx8MMPF0mKH/zgB8XDDz9c/P3vfy+KoihOO+204ogjjmiY/8wzzxRrr712cfLJJxczZ84sJk2aVNTU1BSTJ09u0uuuEQG/KIriggsuKDbZZJOic+fOxa677lrce++9Dc/tvffexahRoxrN/+1vf1tstdVWRefOnYsPfehDxU033dTKFUPTNeU4HzBgQJFkucf48eNbv3BogqZ+P/9PAj4dRVOP83vuuacYPHhwUVtbW2y++ebFd77znWLp0qWtXDU0TVOO8yVLlhRnnXVWscUWWxRdunQp+vfvX3zpS18qXn/99dYvHFbB7bffvsKftd8+rkeNGlXsvffey22z4447Fp07dy4233zz4tJLL23y61YVhfe0AAAAQEdX+mvwAQAAYE0g4AMAAEAJCPgAAABQAgI+AAAAlICADwAAACUg4AMAAEAJCPgAAABQAgI+AAAAlICADwAAACUg4AMAAEAJCPgAAABQAgI+AAAAlMD/B3y2RaqzkX38AAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Create figure with two subplots\n", - "import matplotlib.pyplot as plt\n", - "\n", - "fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 12))\n", - "\n", - "# First subplot - histogram of cases per year\n", - "df[\"date\"].dt.year.hist(\n", - " bins=range(df[\"date\"].dt.year.min(), df[\"date\"].dt.year.max() + 2, 1), ax=ax1\n", - ")\n", - "ax1.set_title(\"Rozkład spraw w czasie\")\n", - "ax1.set_xlabel(\"Rok\")\n", - "ax1.set_ylabel(\"Liczba spraw\")\n", - "ax1.grid(True, alpha=0.3)\n", - "\n", - "# Add vertical line for Dziubak judgment\n", - "ax1.axvline(\n", - " x=DZIUBAK_JUDGMENT_DATE.year, color=\"r\", linestyle=\"--\", label=\"Wyrok Dziubak\"\n", - ")\n", - "ax1.legend()\n", - "\n", - "# Second subplot - sprawa_frankowiczów distribution over time\n", - "df_extracted = pd.DataFrame(all_extractions)\n", - "df_extracted[\"date\"] = pd.to_datetime(df_extracted[\"date\"])\n", - "df_extracted[\"year\"] = df_extracted[\"date\"].dt.year\n", - "\n", - "# Group by year and sprawa_frankowiczów and count\n", - "pivot_data = df_extracted.pivot_table(\n", - " index=\"year\",\n", - " columns=\"sprawa_frankowiczów\",\n", - " values=\"signature\",\n", - " aggfunc=\"count\",\n", - " fill_value=0,\n", - ")\n", - "\n", - "pivot_data.plot(kind=\"bar\", stacked=True, ax=ax2)\n", - "ax2.set_title(\"Rozkład spraw frankowych w czasie\")\n", - "ax2.set_xlabel(\"Rok\")\n", - "ax2.set_ylabel(\"Liczba spraw\")\n", - "ax2.grid(True, alpha=0.3)\n", - "\n", - "ax2.axvline(\n", - " x=DZIUBAK_JUDGMENT_DATE.year, color=\"r\", linestyle=\"--\", label=\"Wyrok Dziubak\"\n", - ")\n", - "ax2.legend(title=\"Sprawa frankowa\")\n", - "\n", - "plt.tight_layout()\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 18, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -595,12 +528,13 @@ " 'sprawa_frankowiczów': True}" ] }, - "execution_count": 18, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "# | eval: false\n", "from juddges.prompts.information_extraction import prepare_information_extraction_chain\n", "from juddges.llms import GPT_4o_MINI_2024_07_18, GPT_4o_2024_08_06\n", "from juddges.prompts.information_extraction import SWISS_FRANC_LOAN_SCHEMA\n", @@ -622,7 +556,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -648,6 +582,7 @@ } ], "source": [ + "# | eval: false\n", "from tqdm.notebook import tqdm\n", "\n", "# Process all judgments in batches of 10\n", @@ -683,10 +618,11 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ + "# | eval: false\n", "extractions_df[\"LLM\"] = MODEL_NAME\n", "extractions_df[\"schema\"] = SWISS_FRANC_LOAN_SCHEMA\n", "extractions_df[\"language\"] = LANGUAGE" @@ -694,7 +630,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -703,19 +639,22 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ + "# | eval: false\n", "settings.FRANKOWICZE_DATA_PATH.mkdir(parents=True, exist_ok=True)\n", "\n", "current_date = pd.Timestamp.now().strftime(\"%Y-%m-%d\")\n", - "extractions_df.to_pickle(settings.FRANKOWICZE_DATA_PATH / f\"extractions_df_{current_date}.pkl\")\n" + "extractions_df.to_pickle(\n", + " settings.FRANKOWICZE_DATA_PATH / f\"extractions_df_{current_date}.pkl\"\n", + ")" ] }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -1120,27 +1059,31 @@ "[10 rows x 50 columns]" ] }, - "execution_count": 23, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "# | eval: false\n", "extractions_df.sample(10)" ] }, { "cell_type": "code", - "execution_count": 49, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "from juddges.case_law_trends.visualisations import plot_distributions, plot_distributions_stacked" + "from juddges.case_law_trends.visualisations import (\n", + " plot_distributions,\n", + " plot_distributions_stacked,\n", + ")" ] }, { "cell_type": "code", - "execution_count": 50, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -1154,18 +1097,19 @@ "Name: count, dtype: int64" ] }, - "execution_count": 50, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "# | eval: false\n", "extractions_df.wynik_sprawy.value_counts()" ] }, { "cell_type": "code", - "execution_count": 51, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -1180,12 +1124,13 @@ } ], "source": [ + "# | eval: false\n", "plot_distributions(extractions_df, \"wynik_sprawy\")" ] }, { "cell_type": "code", - "execution_count": 55, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -1200,12 +1145,13 @@ } ], "source": [ + "# | eval: false\n", "plot_distributions_stacked(extractions_df, \"wynik_sprawy\")" ] }, { "cell_type": "code", - "execution_count": 54, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -1220,12 +1166,13 @@ } ], "source": [ + "# | eval: false\n", "plot_distributions(extractions_df, \"wynik_sprawy\")" ] }, { "cell_type": "code", - "execution_count": 48, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -1240,6 +1187,7 @@ } ], "source": [ + "# | eval: false\n", "plot_distributions(extractions_df, \"typ_rozstrzygniecia\")" ] }, @@ -1253,21 +1201,9 @@ ], "metadata": { "kernelspec": { - "display_name": "juddges", + "display_name": "python3", "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.13" } }, "nbformat": 4,