diff --git a/notebooks/llama.ipynb b/notebooks/llama.ipynb index be03097..34e487f 100644 --- a/notebooks/llama.ipynb +++ b/notebooks/llama.ipynb @@ -78,7 +78,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "873704be", "metadata": {}, "outputs": [], @@ -149,7 +149,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 2, "id": "0484cf77", "metadata": {}, "outputs": [], @@ -173,7 +173,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "74ca39ba", "metadata": {}, "outputs": [], @@ -188,7 +188,7 @@ " self._gate = nn.Linear(emb_size, 4 * emb_size)\n", " self._up = nn.Linear(emb_size, 4 * emb_size)\n", " self._down = nn.Linear(4 * emb_size, emb_size)\n", - " self._actvation = SiLU()\n", + " self._activation = SiLU()\n", " self._dropout = nn.Dropout(dropout)\n", "\n", " def forward(self, x: torch.Tensor): # [batch_size × seq_len × emb_size].\n", @@ -202,21 +202,385 @@ " " ] }, + { + "cell_type": "markdown", + "id": "ecd2bcc0", + "metadata": {}, + "source": [ + "# RoPE\n", + "\n", + "Вот мы и добрались до наиболее серьезного изменения в архитектуре: обычные позиционные эмбеддинги в **Llama** были заменены на **Rotary Positional Embeddings (RoPE)**.\n", + "\n", + "**GPT-1** получал информацию о позициях токенов путем сложения эмбеддингов токенов и позиционных эмбеддингов.\n", + "**RoPE** же кодирует позиции токенов с помощью *вращения (rotation)* векторов **запроса (query)** и **ключа (key)** в двумерном пространстве. При этом каждая позиция в последовательности получает уникальный поворот, а угол поворота зависит от расположения токена в последовательности.\n", + "\n", + "Если упрощенно, то выглядит это так:\n", + "\n", + "* Слово на позиции **1**: поворот на 1°\n", + "* Слово на позиции **2**: поворот на 2°\n", + "* Слово на позиции **100**: поворот на 100°\n", + "* Слово на позиции **101**: поворот на 101°\n", + "\n", + "Угол между 1 и 101 словом будет достаточно большим — **100°**, что отражает большую дистанцию между ними.\n", + "А разница между 100 и 101 словом будет такой же как между 1 и 2, тем самым показывая одинаковую дистанцию между ними.\n", + "\n", + "Такое относительное кодирование позволяет модели лучше понимать расстояние между токенами.\n", + "\n", + "

\n", + " \"RoPE\n", + "

\n", + "\n", + "В последующем тензоры **запроса (query)** и **ключа (key)** перемножаются для вычисления **матрицы внимания**.\n", + "А это означает, что теперь вычисление внимания напрямую зависит от относительных позиций слов.\n", + "\n", + "---\n", + "\n", + "## Почему RoPE лучше\n", + "\n", + "* **Устойчивость к сдвигу:** модель не переобучается на конкретных позициях в обучающих данных, так как учитывает относительные расстояния.\n", + "* **Экономия:** интегрируется в ключи (*key*) и запросы (*query*) посредством матричных вычислений, без необходимости создавать и хранить отдельный слой для позиционных эмбеддингов.\n", + "* **Экстраполяция:** модель может работать с последовательностями длиннее, чем видела при обучении — потому что она выучивает закономерности поворотов в зависимости от дистанции.\n" + ] + }, + { + "cell_type": "markdown", + "id": "8ba07b89", + "metadata": {}, + "source": [ + "### Как это работает...\n", + "\n", + "Основная идея: для каждого токена в последовательности его эмбеддинг поворачивается на угол, зависящий от позиции токена и фиксированных частот.\n", + "\n", + "На вход к нам поступают либо тензор ключа (key), либо тензор запроса (query) размерностью `head_size`.\n", + "Обозначим его как *x*.\n", + "\n", + "

\n", + " \"rope_0_1.png\"\n", + "

\n", + "\n", + "Каждая строка в тензоре — это вектор, соответствующий одному токену в последовательности.\n", + "Обозначим вектор как *xₘ*, где *m* — номер позиции токена.\n", + "\n", + "

\n", + " \"rope_0_2.png\"\n", + "

\n", + "\n", + "Вращать вектор мы будем в двумерном пространстве. Но размерность вектора многомерная!\n", + "Чтобы свести вращение к двумерному пространству, вектор разбивают на рядом стоящие пары измерений:\n", + "\n", + "$$\n", + "x_m = [x_{m0}, x_{m1}, x_{m2}, x_{m3}, …, x_{m(d−2)}, x_{m(d−1)}] \\Rightarrow \\text{пары: } (x_{m0}, x_{m1}), (x_{m2}, x_{m3}), …, (x_{m(d−2)}, x_{m(d−1)})\n", + "$$\n", + "\n", + "> Из-за того, что вектор обязательно должен быть разбит на пары, RoPE может работать только для четных `head_size`.\n", + "\n", + "После этого мы можем рассматривать каждую пару\n", + "$(x_{m,2k}; x_{m,2k+1})$\n", + "как вектор в двумерном пространстве:\n", + "\n", + "$$\n", + "\\begin{bmatrix}\n", + "x_{m,2k} \\\n", + "x_{m,2k+1}\n", + "\\end{bmatrix}\n", + "$$\n", + "\n", + "А раз это вектор в двумерном пространстве, то мы можем повернуть его на угол\n", + "$m \\cdot \\theta_k$.\n", + "\n", + "\n" + ] + }, { "cell_type": "markdown", "id": "c386a55c", "metadata": {}, "source": [] }, + { + "cell_type": "markdown", + "id": "450e03ac", + "metadata": {}, + "source": [ + "\n", + "\n", + "Каждая пара измерений вектора поворачивается на угол:\n", + "\n", + "$$\n", + "m \\cdot \\theta_k\n", + "$$\n", + "\n", + "

\n", + " \"rope_0_3.png\"\n", + "

\n", + "\n", + "Здесь\n", + "$ \\theta_k $ — это частота вращения, которая вычисляется по формуле:\n", + "\n", + "$$\n", + "\\theta_k = \\frac{1}{base^{2k/d}}\n", + "$$\n", + "\n", + "где:\n", + "\n", + "* **base** — гиперпараметр (обычно = 10 000),\n", + "* **k** — индекс пары (от 0 до `d/2 - 1`),\n", + "* **d** — размерность вектора (`head_size`) запроса (*query*) в каждой голове, каждого блока внимания.\n", + "\n", + "\n", + "Само вращение выполняется с помощью матрицы:\n", + "\n", + "$$\n", + "R(m, \\theta_k) =\n", + "\\begin{bmatrix}\n", + "\\cos(m \\theta_k) & -\\sin(m \\theta_k) \\\\\n", + "\\sin(m \\theta_k) & \\cos(m \\theta_k)\n", + "\\end{bmatrix}\n", + "$$\n", + "\n", + "Для этого каждая пара\n", + "($x_{m,2k}$; $x_{m,2k+1}$)\n", + "перемножается на матрицу поворота:\n", + "\n", + "\n", + "\n", + "$$\n", + "\\begin{bmatrix} \n", + "x_{m,2k}' \\\\ \n", + "x_{m,2k+1}' \n", + "\\end{bmatrix}\n", + "= \n", + "R(m, \\theta_k) \\cdot \n", + "\\begin{bmatrix} \n", + "x_{m,2k} \\\\ \n", + "x_{m,2k+1} \n", + "\\end{bmatrix}\n", + "$$\n", + "\n", + "$$\n", + "\\begin{bmatrix} \n", + "x_{m,2k}' \\\\ \n", + "x_{m,2k+1}' \n", + "\\end{bmatrix}\n", + "= \n", + "\\begin{bmatrix} \n", + "\\cos(m \\theta_k) & -\\sin(m \\theta_k) \\\\ \n", + "\\sin(m \\theta_k) & \\cos(m \\theta_k) \n", + "\\end{bmatrix} \n", + "\\cdot \n", + "\\begin{bmatrix} \n", + "x_{m,2k} \\\\ \n", + "x_{m,2k+1} \n", + "\\end{bmatrix}\n", + "$$\n", + "\n", + "$$\n", + "\\begin{bmatrix} \n", + "x_{m,2k}' \\\\ \n", + "x_{m,2k+1}' \n", + "\\end{bmatrix}\n", + "= \n", + "\\begin{bmatrix} \n", + "x_{m,2k} \\cdot \\cos(m \\theta_k) - x_{m,2k+1} \\cdot \\sin(m \\theta_k) \\\\ \n", + "x_{m,2k} \\cdot \\sin(m \\theta_k) + x_{m,2k+1} \\cdot \\cos(m \\theta_k) \n", + "\\end{bmatrix}\n", + "$$\n", + "\n", + "Где:\n", + "\n", + "* $R(m, \\theta_k)$ — это стандартная матрица вращения в 2D пространстве. Взята из классической линейной алгебры.\n", + "* $\\theta_k$ — частота вращения для $k$-й пары измерений.\n", + "* $m$ — позиция токена в последовательности.\n", + "* $k$ — индекс пары измерений.\n", + "* $x_{m,2k}$ и $x_{m,2k+1}$ — четное и нечетное измерение вектора.\n", + "* $x_{m,2k}'$ и $x_{m,2k+1}'$ — четное и нечетное измерение вектора после вращения.\n", + "\n", + "И так происходит с каждым вектором ключа (*key*) или запроса (*query*) в каждой голове, каждого блока внимания.\n", + "\n", + "---\n", + "\n", + "**Примечание**\n", + "\n", + "Обратите внимание, что разные вектора и их составляющие вращаются с разной «скоростью».\n", + "Угол поворота зависит от позиции токена $m$, и позиции пары $k$.\n", + "\n", + "$$\n", + "m \\cdot \\theta_k = m \\cdot \\frac{1}{base^{-2k/d}}\n", + "$$\n", + "\n", + "---\n", + "\n", + "Вот для примера сводная таблица для разных значений $m$ и $k$:\n", + "\n", + "| Позиция $m$ | $k=0$ | $k=1$ | $k=2$ | $k=3$ |\n", + "| ----------- | ------- | ------ | ----- | ------ |\n", + "| 0 | 0° | 0° | 0° | 0° |\n", + "| 1 | 1.0° | 0.1° | 0.01° | 0.001° |\n", + "| 10 | 10.0° | 1.0° | 0.1° | 0.01° |\n", + "| 100 | 100.0° | 10.0° | 1.0° | 0.1° |\n", + "| 1000 | 1000.0° | 100.0° | 10.0° | 1.0° |\n", + "\n", + "\n", + "\n", + "- $m$ напрямую и линейно масштабирует угол: чем больше $m$, тем больше угол поворота.\n", + "- $k$ делает наоборот: чем больше $k$, тем меньше угол.\n", + "И уменьшается он экспоненциально с ростом $k$.\n", + "\n", + "Такое неравномерное распределение создает уникальный паттерн для каждого вектора,\n", + "что позволяет модели лучше различать **относительные позиции**." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "02c300f9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cos shape: torch.Size([512, 32])\n", + "sin shape: torch.Size([512, 32])\n" + ] + } + ], + "source": [ + "def create_rotary_embeddings(head_size, max_seq_len, base=10000):\n", + " \"\"\"\n", + " Создает матрицы косинусов и синусов для RoPE.\n", + " \n", + " Returns:\n", + " cos_matrix: [max_seq_len, head_size//2]\n", + " sin_matrix: [max_seq_len, head_size//2]\n", + " \"\"\"\n", + " # Обратные частоты\n", + " freqs = 1.0 / (base ** (2 * torch.arange(head_size // 2) / head_size))\n", + " \n", + " # Позиции\n", + " positions = torch.arange(max_seq_len)\n", + " \n", + " # Матрица частот (внешнее произведение)\n", + " freq_matrix = torch.outer(positions, freqs)\n", + " \n", + " # Матрицы косинусов и синусов\n", + " cos_matrix = torch.cos(freq_matrix)\n", + " sin_matrix = torch.sin(freq_matrix)\n", + " \n", + " return cos_matrix, sin_matrix\n", + "\n", + "# Использование\n", + "head_size = 64\n", + "max_seq_len = 512\n", + "\n", + "cos_m, sin_m = create_rotary_embeddings(head_size, max_seq_len)\n", + "print(f\"cos shape: {cos_m.shape}\") # torch.Size([512, 32])\n", + "print(f\"sin shape: {sin_m.shape}\") # torch.Size([512, 32])" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "ac072b9b", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAGGCAYAAACqvTJ0AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQAAfxFJREFUeJzt3QeYk1X2x/GbZJLpM/ShN+liFxWxi2DHurqyu6jYVsVed+2rYlkFEcWytnXtvXcQG1bsIIgivcP0nuT/3Nf/jAygQn7XJJN8P88zypR735PMMDnc9557fNFoNGoAAAAAAACAOPLH82IAAAAAAACAxaIUAAAAAAAA4o5FKQAAAAAAAMQdi1IAAAAAAACIOxalAAAAAAAAEHcsSgEAAAAAACDuWJQCAAAAAABA3LEoBQAAAAAAgLhjUQoAAAAAAABxx6IUgKTn8/nMFVdckegwkoZ9LuxzAgAA0k/37t3Nsccem+gwksb999/v5UU//fRTokMBEAMWpQBskh9++MGcfPLJpmfPniYrK8sUFBSYIUOGmFtuucVUVVWZVExy7Nt777233uej0ajp0qWL9/kDDzwwpmtce+215tlnn3UQLQAAaM6+/vprc8QRR5hu3bp5OVanTp3MPvvsY2699VaTDN5+++3GvOh///vfBr/G5oT28wMHDozpGrfffruXfwFIH76o/VcVAGyEl156yRx55JEmMzPT/O1vf/MSjtraWm/B5qmnnvLu2t11113Or1tdXW0yMjK8t3iySdFxxx3nJYb2/zZRWjc523PPPb3nY+jQoebFF1/c5Gvk5eV5CeimJGD19fXem40LAAA0fx988IGXU3Tt2tWMGjXKtG/f3ixYsMB8+OGH3g3BOXPmNH5tTU2N8fv9JhgMxjXGhrzH5h/2/y+//HKTz9udSj169PA+v9lmm5lvvvlmk69hc8s2bdp419pY4XDY1NXVefkYO8mB5ie+/8ID0GzNnTvXHH300d7du8mTJ5sOHTo0fu60007zkiW7aPVHSPTiy/7772+eeOIJM2HChCYLYw8//LDZbrvtzMqVK+MSR0VFhcnNzU3IAh0AAPjjXHPNNaawsNB88sknpkWLFk0+t3z58ibv28WXROdFzz//vJf/2AWktfOioqIi07t3b7NmzZq45UWBQMB7A9A8Ub4HYKPccMMNpry83Nxzzz1NFqQa9OrVy5x55pmN79udPP/617+8O2U2ebLnH/zjH//w7u6t7dNPPzXDhw/3kprs7GzvDtvxxx//m2dKNZypZBfC7O4sm7zZRM7uZqqsrFwvNrvF3C4e2flbtWrlLa7Zu48b689//rNZtWqVeeONNxo/ZneIPfnkk+aYY47Z4Jh///vfZueddzatW7f2rmuvb79+3cdlE6oHHnigcTt8wxkRDY9xxowZ3jVatmxpdtlllyafa3Dfffd57997773rlQbaj697JxMAACQXuxtq8803X29BymrXrt1vninVcNzA+++/b8455xzTtm1bb7Hm0EMPNStWrFhvvldeecXsuuuu3tfk5+ebAw44wHz77bcbHeuIESO83M7esFubXZT605/+tMEFIpur7LXXXt5jsWMHDBhgJk2atN7jsnFMnTq1MS/aY489mjxG+7lTTz3Vm6dz584bPFPK3jy1O8kuu+yy9eKzX7fudQEkFotSADbKCy+84J0jZRdaNsYJJ5zgJQPbbrutGTdunNl9993N2LFjvQWhte/8DRs2zEsiLrroIu/MhJEjR3pb1TeGTXzKysq8ee2fbVJy5ZVXrnfn0ZYa2rt2N998sznrrLPMW2+9ZXbbbTdTXFy8UdexSdLgwYPNI4880iShKykpafJ41mbP2Npmm23MVVdd5S0O2Z1NtvRx7d1kDz74oJeY2cTQ/tm+2fO61mbH2IU2O8eJJ564wWvZxTh7ppVNRBsW2+y5FPa5GD16tHdHEwAAJC+7E/2zzz6LqeStwZgxY8yXX35pLr/8cvP3v//dy91OP/30Jl9jcw27CGWPD7j++uvNpZde6t0Asze+Nvag8JycHG9hau28yF7XLij92s06uxBkH6O9QXnTTTd5Z3LaxaXbbrut8WvGjx/vLTT169evMS/65z//2WQeO8bGa3NMmztuiF38sl9n88Pp06d7H1uyZIn3/NjjFk455ZSNepwA4sSeKQUAv6WkpMSePRcdMWLERn39F1984X39CSec0OTj5513nvfxyZMne+8/88wz3vuffPLJb85nv+byyy9vfN/+2X7s+OOPb/J1hx56aLR169aN7//000/RQCAQveaaa5p83ddffx3NyMhY7+Pruu+++xrjmzhxYjQ/Pz9aWVnpfe7II4+M7rnnnt6fu3XrFj3ggAOajG34uga1tbXRgQMHRvfaa68m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0vjsoF6P4iIHW1SlHYrv8+uvtxkdukvjq8IOcpdyLRfNzcyRY0iGvCFSpx/LkSrle+oUDqpK5bI3ezNBR+0cmif91Unw448/Np5v8Nprr5m///3v5owzzvC2mls2obLsnb212fcbPreusWPHeolXw5u9kwgAAJAqyJ8AAECqSOiiVCQSMdtuu6259tprzTbbbGNOOukk7y7fHXfcEfOcF198sSkpKWl8W7BggdOYAQAAEon8CQAApIqElu916NDBDBgwoMnH+vfvb5566invz+3b/1witWzZMu9rG9j3t9566w3OaVstr91uucE/X7/OFOTFvl3X30rrdHbBqPlG1e7PWglh5arFcgyRz1+X58joP1iLYcFMOYZwbZU0PprfNuHley462ERrqvXvZ0DtvqdvgQ8E/Anfhp8MW/kBpId45k9XHnKtdPzB6m2GGcXDVx9uVJe8pOUNg3rq3fdCeXrru5I6rfQtIytPjiHQvlvCy6QiJauk8YU5hXIM/oxQwks6XZTbh8VySheld/UuSgDpngc0awndKWU7x8yaNavJx2bPnm26devWeGinTazeeuutJmccfPTRR2bwYG1hAwAAoDkifwIAAKkioTulzj77bLPzzjt728//9Kc/mY8//tjcdddd3pvl8/nMWWedZa6++mrv3ISGlsYdO3Y0hxxySCJDBwAASAjyJwAAkCoSuig1aNAg88wzz3jnGFx11VVe0mRbGI8cObLxay644AJTUVHhnZdQXFxsdtllF/Pqq6+arKysTbrWsDcyTWATx6ztotuON4ks1bL22ndLafz0L/WSs6VvPi7P0WrIL9/fWPinPinHEKnXOthEclomvvuei24lTrrv+ZKg+548BQA0G3HNn/q1NrmB2MuTvzn2b0YxeMGrRnXMm9pr3fy+PeQYCjr3kedQ+9YFc/WytXDBL+WgsdB77xkTFsv38rP074VP+DvhiovyvVTpvqeKJEEMLlDFiOYqoYtS1oEHHui9/Rp7t88mXPYNAAAA5E8AACA1sL8AAAAAAAAA6bdTKl6+fvkZ4wvE3inj9eXa1u+TRvQ2qsJh2nbj2/L0TiE/XTVbnmPNGTXS+NbfzTOJVpelb4HPFrvWVYkdU6xIZaU8R4ZYvpfpoHzPL8ZA9z0A2LAOzz5v8vILYh7/YmSpdP3Ju48xqlUF20rj66v0UveuW24u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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "cos_m, sin_m = create_rotary_embeddings(64, 100)\n", + "\n", + "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))\n", + "ax1.imshow(cos_m.numpy(), aspect='auto', cmap='RdBu')\n", + "ax1.set_title('Cosine Matrix')\n", + "ax1.set_xlabel('Frequency dimension')\n", + "ax1.set_ylabel('Position')\n", + "\n", + "ax2.imshow(sin_m.numpy(), aspect='auto', cmap='RdBu')\n", + "ax2.set_title('Sine Matrix')\n", + "ax2.set_xlabel('Frequency dimension')\n", + "ax2.set_ylabel('Position')\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "4fe79d02", + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "from torch import nn\n", + "\n", + "class RoPE(nn.Module):\n", + " def __init__(self, head_size: int, max_seq_len: int, base: int = 10_000):\n", + " super().__init__()\n", + " assert head_size % 2 == 0, \"head_size должен быть четным\"\n", + "\n", + " # Обратные частоты\n", + " freqs = 1.0 / (base ** (2 * torch.arange(head_size // 2).float() / head_size))\n", + " \n", + " # Позиции\n", + " positions = torch.arange(max_seq_len).float()\n", + " \n", + " # Матрица частот (внешнее произведение)\n", + " #freq_matrix = torch.outer(positions, freqs)\n", + " freq_matrix = positions.unsqueeze(1) * freqs.unsqueeze(0)\n", + "\n", + " # Матрицы косинусов и синусов\n", + " self.register_buffer('cos_matrix', torch.cos(freq_matrix))\n", + " self.register_buffer('sin_matrix', torch.sin(freq_matrix))\n", + "\n", + "\n", + " def forward(self, x: torch.Tensor): # Получает на вход тензор x (тип float) размером [batch_size × seq_len × head_size]\n", + " seq_len = x.size(1)\n", + " # Берем нужную часть матриц и приводим к типу x\n", + " cos = self.cos_matrix[:seq_len].to(x.dtype) # [seq_len, head_size//2]\n", + " sin = self.sin_matrix[:seq_len].to(x.dtype) # [seq_len, head_size//2]\n", + " \n", + "\n", + " # Разделяем на четные и нечетные\n", + " x_even = x[:, :, 0::2] # [batch_size, seq_len, head_size//2]\n", + " x_odd = x[:, :, 1::2] # [batch_size, seq_len, head_size//2]\n", + "\n", + " # Применяем поворот\n", + " x_rotated_even = x_even * cos - x_odd * sin\n", + " x_rotated_odd = x_even * sin + x_odd * cos\n", + "\n", + "\n", + " # Объединяем обратно\n", + " x_rotated = torch.stack([x_rotated_even, x_rotated_odd], dim=-1)\n", + " x_rotated = x_rotated.flatten(-2) # [batch_size, seq_len, head_size]\n", + "\n", + " return x_rotated" + ] + }, { "cell_type": "markdown", "id": "c9fe652d", "metadata": {}, "source": [] }, + { + "cell_type": "markdown", + "id": "1133b962", + "metadata": {}, + "source": [] + }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 7, "id": "fe1274b1", "metadata": {}, "outputs": [], @@ -247,38 +611,16 @@ " @property\n", " def embedding_dim(self) -> int:\n", " return self._embedding.embedding_dim\n", - "\n", - "\n", - "import torch\n", - "from torch import nn, Tensor\n", - "\n", - "class PositionalEmbeddings(nn.Module):\n", - " def __init__(self, max_seq_len: int, emb_size: int):\n", - " super().__init__()\n", - " self.max_seq_len = max_seq_len\n", - " self.emb_size = emb_size\n", - " self.embedding = nn.Embedding(\n", - " num_embeddings=max_seq_len,\n", - " embedding_dim=emb_size\n", - " )\n", - "\n", - " def forward(self, seq_len: int, start_pos: int = 0) -> Tensor:\n", - " if seq_len < 1 or seq_len > self.max_seq_len:\n", - " raise IndexError(f\"Длина {seq_len} должна быть от 1 до {self.max_seq_len}\")\n", - " if start_pos == 0:\n", - " positions = torch.arange(seq_len, device=self.embedding.weight.device)\n", - " else:\n", - " positions = torch.arange(start=start_pos, end=start_pos + seq_len, device=self.embedding.weight.device)\n", - " return self.embedding(positions)\n", " \n", " \n", "class HeadAttention(nn.Module):\n", "\n", - " def __init__(self, emb_size: int, head_size: int, max_seq_len: int):\n", + " def __init__(self, emb_size: int, head_size: int, max_seq_len: int, rope: RoPE):\n", " super().__init__()\n", " self._emb_size = emb_size\n", " self._head_size = head_size\n", " self._max_seq_len = max_seq_len\n", + " self._rope = rope\n", "\n", " self._k = nn.Linear(emb_size, head_size)\n", " self._q = nn.Linear(emb_size, head_size)\n", @@ -296,6 +638,10 @@ " q = self._q(x) # [B, T, hs]\n", " v = self._v(x) # [B, T, hs]\n", "\n", + " # ✅ Применяем RoPE к Q и K (НЕ к V!)\n", + " q = self._rope(q) # [B, T, hs]\n", + " k = self._rope(k) # [B, T, hs]\n", + "\n", " if cache is not None:\n", " k_cache, v_cache = cache\n", " k = torch.cat([k_cache, k], dim=1) # [B, cache_len + T, hs]\n", @@ -319,14 +665,15 @@ "import math\n", "\n", "class MultiHeadAttention(nn.Module):\n", - " def __init__(self, num_heads: int, emb_size: int, head_size: int, max_seq_len: int, dropout: float = 0.1):\n", + " def __init__(self, num_heads: int, emb_size: int, head_size: int, max_seq_len: int, rope: RoPE, dropout: float = 0.1):\n", "\n", " super().__init__()\n", " self._heads = nn.ModuleList([\n", " HeadAttention(\n", " emb_size=emb_size, \n", " head_size=head_size, \n", - " max_seq_len=max_seq_len\n", + " max_seq_len=max_seq_len,\n", + " rope=rope,\n", " ) for _ in range(num_heads)\n", " ])\n", " self._layer = nn.Linear(head_size * num_heads, emb_size)\n", @@ -366,26 +713,6 @@ " self.sqrt_2_over_pi * (x + 0.044715 * torch.pow(x, 3))\n", " ))\n", "\n", - "class FeedForward(nn.Module):\n", - "\n", - " def __init__(self, emb_size: int, dropout: float = 0.1):\n", - " super().__init__()\n", - " self._layer1 = nn.Linear(emb_size, emb_size * 4)\n", - " self._gelu = GELU()\n", - " self._layer2 = nn.Linear(emb_size * 4, emb_size)\n", - " self._dropout = nn.Dropout(dropout)\n", - "\n", - " def forward(self, x: torch.Tensor):\n", - " input_dtype = x.dtype\n", - " \n", - " if input_dtype != self._layer1.weight.dtype:\n", - " self._layer1 = self._layer1.to(dtype=input_dtype)\n", - " self._layer2 = self._layer2.to(dtype=input_dtype)\n", - " \n", - " x = self._layer1(x)\n", - " x = self._gelu(x)\n", - " x = self._layer2(x)\n", - " return self._dropout(x)\n", " \n", "class Decoder(nn.Module):\n", " def __init__(self, \n", @@ -393,6 +720,7 @@ " emb_size: int,\n", " head_size: int,\n", " max_seq_len: int,\n", + " rope: RoPE,\n", " dropout: float = 0.1\n", " ):\n", " super().__init__()\n", @@ -400,10 +728,11 @@ " num_heads=num_heads, \n", " emb_size=emb_size, \n", " head_size=head_size, \n", - " max_seq_len=max_seq_len, \n", + " max_seq_len=max_seq_len,\n", + " rope=rope,\n", " dropout=dropout\n", " )\n", - " self._ff = FeedForward(emb_size=emb_size, dropout=dropout)\n", + " self._ff = SwiGLU(emb_size=emb_size, dropout=dropout)\n", " self._norm1 = RMSNorm(emb_size)\n", " self._norm2 = RMSNorm(emb_size)\n", "\n", @@ -454,16 +783,21 @@ " vocab_size=vocab_size, \n", " emb_size=emb_size\n", " )\n", - " self._position_embeddings = PositionalEmbeddings(\n", - " max_seq_len=max_seq_len, \n", - " emb_size=emb_size\n", + " self._position_embeddings = RoPE(\n", + " head_size=head_size,\n", + " max_seq_len=max_seq_len\n", " )\n", + " #self._position_embeddings = PositionalEmbeddings(\n", + " # max_seq_len=max_seq_len, \n", + " # emb_size=emb_size\n", + " #)\n", " self._dropout = nn.Dropout(dropout)\n", " self._decoders = nn.ModuleList([Decoder(\n", " num_heads=num_heads,\n", " emb_size=emb_size,\n", " head_size=head_size,\n", " max_seq_len=max_seq_len,\n", + " rope=self._position_embeddings,\n", " dropout=dropout \n", " ) for _ in range(num_layers)])\n", " self._norm = RMSNorm(emb_size)\n", @@ -476,26 +810,26 @@ " \n", " \n", " # Вычисление start_pos из кэша (если кэш передан)\n", - " if cache is not None:\n", - " # При кэше обрабатываем только один токен (последний)\n", - " seq_len = 1\n", - " # Вычисляем start_pos из самого нижнего уровня кэша\n", - " if cache and cache[0] and cache[0][0]:\n", - " key_cache, _ = cache[0][0] # Первый декодер, первая голова\n", - " start_pos = key_cache.size(1) # cache_len\n", - " else:\n", - " start_pos = 0\n", - " else:\n", - " # Без кэша работаем как раньше\n", - " start_pos = 0\n", - " seq_len = x.size(1)\n", + " #if cache is not None:\n", + " # # При кэше обрабатываем только один токен (последний)\n", + " # seq_len = 1\n", + " # # Вычисляем start_pos из самого нижнего уровня кэша\n", + " # if cache and cache[0] and cache[0][0]:\n", + " # key_cache, _ = cache[0][0] # Первый декодер, первая голова\n", + " # start_pos = key_cache.size(1) # cache_len\n", + " # else:\n", + " # start_pos = 0\n", + " #else:\n", + " # # Без кэша работаем как раньше\n", + " # start_pos = 0\n", + " # seq_len = x.size(1)\n", "\n", " # Эмбеддинги токенов и позиций\n", " tok_out = self._token_embeddings(x) # [batch, seq_len, emb_size]\n", - " pos_out = self._position_embeddings(seq_len, start_pos=start_pos) # [seq_len, emb_size]\n", + " #pos_out = self._position_embeddings(x) # [batch, seq_len, emb_size]\n", " \n", " # Комбинирование\n", - " out = self._dropout(tok_out + pos_out.unsqueeze(0)) # [batch, seq_len, emb_size]\n", + " out = self._dropout(tok_out) # [batch, seq_len, emb_size]\n", " \n", " # Стек декодеров с передачей кэша\n", " new_cache = []\n", @@ -632,10 +966,640 @@ " return self._max_seq_len" ] }, + { + "cell_type": "markdown", + "id": "0dd53e32", + "metadata": {}, + "source": [ + "## 2. Обучение LLAMA\n", + "\n", + "LLAMA обучается в два этапа:\n", + "\n", + "- 1️⃣ **Предобучение (Unsupervised Pretraining)** \n", + "- 2️⃣ **Дообучение (Supervised Fine-Tuning)**\n" + ] + }, + { + "cell_type": "markdown", + "id": "4793cef4", + "metadata": {}, + "source": [ + "\n", + "\n", + "### 5.1 Предобучение\n", + "\n", + "На первом этапе модель обучается без разметки: она получает большой корпус текстов и учится **предсказывать следующий токен** по предыдущим.\n", + "\n", + "Функция потерь:\n", + "$$\n", + "L = - \\sum_{t=1}^{T} \\log P(x_t | x_1, x_2, ..., x_{t-1})\n", + "$$\n", + "\n", + "Таким образом, модель учится строить вероятностную модель языка, \"угадывая\" продолжение текста.\n" + ] + }, + { + "cell_type": "markdown", + "id": "5b8bf950", + "metadata": {}, + "source": [ + "Во время **предобучения** LLAMA учится **предсказывать следующий токен** (language modeling task). \n", + "Формально: \n", + "$$ \n", + "P(x_t ,|, x_1, x_2, \\dots, x_{t-1}) \n", + "$$ \n", + "То есть, если на вход подаётся предложение `\"I love deep\"`, модель должна предсказать `\"learning\"`.\n" + ] + }, + { + "cell_type": "markdown", + "id": "96aeecdd", + "metadata": {}, + "source": [ + "### ✅ 5.1.1 Подготовка данных\n", + "\n", + "Создадим **датасет** на основе BPE-токенизатора:" + ] + }, + { + "cell_type": "markdown", + "id": "21bd0b2e", + "metadata": {}, + "source": [ + "**BPE Tokenizator**" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "078ed4ce", + "metadata": {}, + "outputs": [], + "source": [ + "class BPE:\n", + " def __init__(self, vocab_size: int):\n", + " self.vocab_size = vocab_size\n", + " self.id2token = {}\n", + " self.token2id = {}\n", + "\n", + " def fit(self, text: str):\n", + " # 1. Получаем уникальные токены (символы)\n", + " unique_tokens = sorted(set(text))\n", + " tokens = unique_tokens.copy()\n", + "\n", + " # 2. Разбиваем текст на токены-символы\n", + " sequence = list(text)\n", + "\n", + " # 3. Объединяем токены до достижения нужного размера словаря\n", + " while len(tokens) < self.vocab_size:\n", + " #print(f'len={len(tokens)} < {self.vocab_size}')\n", + " # Считаем частоты пар\n", + " pair_freq = {}\n", + " for i in range(len(sequence) - 1):\n", + " pair = (sequence[i], sequence[i + 1])\n", + " #print(f'pair = {pair}')\n", + " if pair not in pair_freq:\n", + " pair_freq[pair] = 0\n", + " pair_freq[pair] += 1\n", + "\n", + "\n", + " #print(f'pair_freq = {pair_freq}') \n", + " if not pair_freq:\n", + " break # нет пар — выходим\n", + "\n", + " #for x in pair_freq.items():\n", + " # self.debug(x, sequence)\n", + "\n", + " # Находим самую частую пару (в случае равенства — та, что встретилась первой)\n", + " most_frequent_pair = max(pair_freq.items(), key=lambda x: (x[1], -self._pair_first_index(sequence, x[0])))[0]\n", + " #print(most_frequent_pair)\n", + " # Создаем новый токен\n", + " new_token = most_frequent_pair[0] + most_frequent_pair[1]\n", + " #print(f\"new token={new_token}\")\n", + " tokens.append(new_token)\n", + " #print(f\"tokens={tokens}\")\n", + "\n", + " i = 0\n", + " new_sequence = []\n", + "\n", + " while i < len(sequence):\n", + " if i < len(sequence) - 1 and (sequence[i], sequence[i + 1]) == most_frequent_pair:\n", + " new_sequence.append(new_token)\n", + " i += 2 # пропускаем два символа — заменённую пару\n", + " else:\n", + " new_sequence.append(sequence[i])\n", + " i += 1\n", + " sequence = new_sequence\n", + " #break\n", + " \n", + " # 4. Создаем словари\n", + " self.vocab = tokens.copy()\n", + " self.token2id = dict(zip(tokens, range(self.vocab_size)))\n", + " self.id2token = dict(zip(range(self.vocab_size), tokens))\n", + "\n", + " def _pair_first_index(self, sequence, pair):\n", + " for i in range(len(sequence) - 1):\n", + " if (sequence[i], sequence[i + 1]) == pair:\n", + " return i\n", + " return float('inf') # если пара не найдена (в теории не должно случиться)\n", + "\n", + "\n", + " def encode(self, text: str):\n", + " # 1. Разбиваем текст на токены-символы\n", + " sequence = list(text)\n", + " # 2. Инициализация пустого списка токенов\n", + " tokens = []\n", + " # 3. Установить i = 0\n", + " i = 0\n", + " while i < len(text):\n", + " # 3.1 Найти все токены в словаре, начинающиеся с text[i]\n", + " start_char = text[i]\n", + " result = [token for token in self.vocab if token.startswith(start_char)]\n", + " # 3.2 Выбрать самый длинный подходящий токен\n", + " find_token = self._find_max_matching_token(text[i:], result)\n", + " if find_token is None:\n", + " # Обработка неизвестного символа\n", + " tokens.append(text[i]) # Добавляем сам символ как токен\n", + " i += 1\n", + " else:\n", + " # 3.3 Добавить токен в результат\n", + " tokens.append(find_token)\n", + " # 3.4 Увеличить i на длину токена\n", + " i += len(find_token)\n", + "\n", + " # 4. Заменить токены на их ID\n", + " return self._tokens_to_ids(tokens)\n", + "\n", + " def _find_max_matching_token(self, text: str, tokens: list):\n", + " \"\"\"Находит самый длинный токен из списка, с которого начинается текст\"\"\"\n", + " matching = [token for token in tokens if text.startswith(token)]\n", + " return max(matching, key=len) if matching else None\n", + "\n", + " def _tokens_to_ids(self, tokens):\n", + " \"\"\"Конвертирует список токенов в их ID с обработкой неизвестных токенов\"\"\"\n", + " ids = []\n", + " for token in tokens:\n", + " if token in self.token2id:\n", + " ids.append(self.token2id[token])\n", + " else:\n", + " ids.append(0) # Специальное значение\n", + " return ids\n", + "\n", + "\n", + " def decode(self, ids: list) -> str:\n", + " return ''.join(self._ids_to_tokens(ids))\n", + "\n", + " def _ids_to_tokens(self, ids: list) -> list:\n", + " \"\"\"Конвертирует список Ids в их tokens\"\"\"\n", + " tokens = []\n", + " for id in ids:\n", + " if id in self.id2token:\n", + " tokens.append(self.id2token[id])\n", + " else:\n", + " tokens.append('') # Специальное значение\n", + " return tokens\n", + "\n", + "\n", + " def save(self, filename):\n", + " with open(filename, 'wb') as f:\n", + " dill.dump(self, f)\n", + " print(f\"Объект сохранён в {filename}\")\n", + "\n", + "\n", + " @classmethod\n", + " def load(cls, filename):\n", + " with open(filename, 'rb') as f:\n", + " obj = dill.load(f)\n", + " \n", + " print(f\"Объект загружен из {filename}\")\n", + " return obj" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "0258c483", + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "from torch.utils.data import Dataset, DataLoader\n", + "\n", + "class GPTDataset(Dataset):\n", + " def __init__(self, text: str, bpe: BPE, block_size: int):\n", + " self.bpe = bpe\n", + " self.block_size = block_size\n", + " self.data = bpe.encode(text)\n", + " \n", + " def __len__(self):\n", + " return len(self.data) - self.block_size\n", + "\n", + " def __getitem__(self, idx):\n", + " x = torch.tensor(self.data[idx:idx+self.block_size], dtype=torch.long)\n", + " y = torch.tensor(self.data[idx+1:idx+self.block_size+1], dtype=torch.long)\n", + " return x, y" + ] + }, + { + "cell_type": "markdown", + "id": "5a7d9a2e", + "metadata": {}, + "source": [ + "### ✅ 5.1.2 Цикл обучения\n", + "\n", + "Для обучения создадим функцию:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "f8f06cf7", + "metadata": {}, + "outputs": [], + "source": [ + "import torch.nn.functional as F\n", + "from torch import optim\n", + "\n", + "def train_llama(model, dataset, epochs=5, batch_size=32, lr=3e-4, device='cpu'):\n", + " dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)\n", + " optimizer = optim.AdamW(model.parameters(), lr=lr)\n", + "\n", + " model.to(device)\n", + " model.train()\n", + "\n", + " for epoch in range(epochs):\n", + " total_loss = 0\n", + " for x, y in dataloader:\n", + " x, y = x.to(device), y.to(device)\n", + "\n", + " # Прямой проход\n", + " logits, _ = model(x, use_cache=False) # [B, T, vocab_size]\n", + "\n", + " # Перестроим выход под CrossEntropy\n", + " loss = F.cross_entropy(logits.view(-1, logits.size(-1)), y.view(-1))\n", + "\n", + " # Обратное распространение\n", + " optimizer.zero_grad()\n", + " loss.backward()\n", + " optimizer.step()\n", + "\n", + " total_loss += loss.item()\n", + "\n", + " avg_loss = total_loss / len(dataloader)\n", + " print(f\"Epoch {epoch+1}/{epochs}, Loss: {avg_loss:.4f}\")\n", + "\n", + " return model" + ] + }, + { + "cell_type": "markdown", + "id": "576cc8f4", + "metadata": {}, + "source": [ + "### ✅ 5.1.3 Пример запуска\n", + "\n", + "\n", + "**🧠 Конфигурация LLAMA Mini**\n", + "\n", + "\n", + "| Параметр | Значение | Описание |\n", + "| --------------- | -------- | --------------------------------------------- |\n", + "| **vocab_size** | `50257` | Размер словаря (BPE токенизатор OpenAI) |\n", + "| **max_seq_len** | `512` | Максимальная длина входной последовательности |\n", + "| **emb_size** | `256` | Размер эмбеддингов (векторное пространство) |\n", + "| **num_heads** | `4` | Количество голов в multi-head attention |\n", + "| **head_size** | `64` | Размерность одной головы внимания (768 / 12) |\n", + "| **num_layers** | `4` | Количество блоков (декодеров) |\n", + "| **dropout** | `0.1` | Вероятность дропаута |\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "0c753d52", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dataset length: 20\n", + "Epoch 1/100, Loss: 3.9063\n", + "Epoch 2/100, Loss: 1.6363\n", + "Epoch 3/100, Loss: 0.6436\n", + "Epoch 4/100, Loss: 0.3222\n", + "Epoch 5/100, Loss: 0.2031\n", + "Epoch 6/100, Loss: 0.1460\n", + "Epoch 7/100, Loss: 0.1119\n", + "Epoch 8/100, Loss: 0.0978\n", + "Epoch 9/100, Loss: 0.0925\n", + "Epoch 10/100, Loss: 0.0757\n", + "Epoch 11/100, Loss: 0.0809\n", + "Epoch 12/100, Loss: 0.0763\n", + "Epoch 13/100, Loss: 0.0671\n", + "Epoch 14/100, Loss: 0.0681\n", + "Epoch 15/100, Loss: 0.0582\n", + "Epoch 16/100, Loss: 0.0655\n", + "Epoch 17/100, Loss: 0.0751\n", + "Epoch 18/100, Loss: 0.0656\n", + "Epoch 19/100, Loss: 0.0625\n", + "Epoch 20/100, Loss: 0.0593\n", + "Epoch 21/100, Loss: 0.0678\n", + "Epoch 22/100, Loss: 0.0652\n", + "Epoch 23/100, Loss: 0.0644\n", + "Epoch 24/100, Loss: 0.0542\n", + "Epoch 25/100, Loss: 0.0627\n", + "Epoch 26/100, Loss: 0.0596\n", + "Epoch 27/100, Loss: 0.0639\n", + "Epoch 28/100, Loss: 0.0536\n", + "Epoch 29/100, Loss: 0.0606\n", + "Epoch 30/100, Loss: 0.0565\n", + "Epoch 31/100, Loss: 0.0622\n", + "Epoch 32/100, Loss: 0.0581\n", + "Epoch 33/100, Loss: 0.0492\n", + "Epoch 34/100, Loss: 0.0553\n", + "Epoch 35/100, Loss: 0.0526\n", + "Epoch 36/100, Loss: 0.0527\n", + "Epoch 37/100, Loss: 0.0570\n", + "Epoch 38/100, Loss: 0.0482\n", + "Epoch 39/100, Loss: 0.0553\n", + "Epoch 40/100, Loss: 0.0444\n", + "Epoch 41/100, Loss: 0.0602\n", + "Epoch 42/100, Loss: 0.0599\n", + "Epoch 43/100, Loss: 0.0598\n", + "Epoch 44/100, Loss: 0.0572\n", + "Epoch 45/100, Loss: 0.0551\n", + "Epoch 46/100, Loss: 0.0577\n", + "Epoch 47/100, Loss: 0.0527\n", + "Epoch 48/100, Loss: 0.0466\n", + "Epoch 49/100, Loss: 0.0551\n", + "Epoch 50/100, Loss: 0.0517\n", + "Epoch 51/100, Loss: 0.0477\n", + "Epoch 52/100, Loss: 0.0539\n", + "Epoch 53/100, Loss: 0.0478\n", + "Epoch 54/100, Loss: 0.0539\n", + "Epoch 55/100, Loss: 0.0435\n", + "Epoch 56/100, Loss: 0.0471\n", + "Epoch 57/100, Loss: 0.0461\n", + "Epoch 58/100, Loss: 0.0452\n", + "Epoch 59/100, Loss: 0.0507\n", + "Epoch 60/100, Loss: 0.0481\n", + "Epoch 61/100, Loss: 0.0398\n", + "Epoch 62/100, Loss: 0.0535\n", + "Epoch 63/100, Loss: 0.0503\n", + "Epoch 64/100, Loss: 0.0504\n", + "Epoch 65/100, Loss: 0.0473\n", + "Epoch 66/100, Loss: 0.0553\n", + "Epoch 67/100, Loss: 0.0514\n", + "Epoch 68/100, Loss: 0.0450\n", + "Epoch 69/100, Loss: 0.0488\n", + "Epoch 70/100, Loss: 0.0414\n", + "Epoch 71/100, Loss: 0.0413\n", + "Epoch 72/100, Loss: 0.0473\n", + "Epoch 73/100, Loss: 0.0530\n", + "Epoch 74/100, Loss: 0.0482\n", + "Epoch 75/100, Loss: 0.0477\n", + "Epoch 76/100, Loss: 0.0483\n", + "Epoch 77/100, Loss: 0.0452\n", + "Epoch 78/100, Loss: 0.0452\n", + "Epoch 79/100, Loss: 0.0474\n", + "Epoch 80/100, Loss: 0.0483\n", + "Epoch 81/100, Loss: 0.0522\n", + "Epoch 82/100, Loss: 0.0453\n", + "Epoch 83/100, Loss: 0.0436\n", + "Epoch 84/100, Loss: 0.0452\n", + "Epoch 85/100, Loss: 0.0523\n", + "Epoch 86/100, Loss: 0.0446\n", + "Epoch 87/100, Loss: 0.0475\n", + "Epoch 88/100, Loss: 0.0503\n", + "Epoch 89/100, Loss: 0.0484\n", + "Epoch 90/100, Loss: 0.0456\n", + "Epoch 91/100, Loss: 0.0433\n", + "Epoch 92/100, Loss: 0.0458\n", + "Epoch 93/100, Loss: 0.0461\n", + "Epoch 94/100, Loss: 0.0448\n", + "Epoch 95/100, Loss: 0.0432\n", + "Epoch 96/100, Loss: 0.0456\n", + "Epoch 97/100, Loss: 0.0470\n", + "Epoch 98/100, Loss: 0.0470\n", + "Epoch 99/100, Loss: 0.0467\n", + "Epoch 100/100, Loss: 0.0471\n" + ] + }, + { + "data": { + "text/plain": [ + "Llama(\n", + " (_token_embeddings): TokenEmbeddings(\n", + " (_embedding): Embedding(100, 256)\n", + " )\n", + " (_position_embeddings): RoPE()\n", + " (_dropout): Dropout(p=0.1, inplace=False)\n", + " (_decoders): ModuleList(\n", + " (0-3): 4 x Decoder(\n", + " (_heads): MultiHeadAttention(\n", + " (_heads): ModuleList(\n", + " (0-3): 4 x HeadAttention(\n", + " (_rope): RoPE()\n", + " (_k): Linear(in_features=256, out_features=64, bias=True)\n", + " (_q): Linear(in_features=256, out_features=64, bias=True)\n", + " (_v): Linear(in_features=256, out_features=64, bias=True)\n", + " )\n", + " )\n", + " (_layer): Linear(in_features=256, out_features=256, bias=True)\n", + " (_dropout): Dropout(p=0.1, inplace=False)\n", + " )\n", + " (_ff): SwiGLU(\n", + " (_gate): Linear(in_features=256, out_features=1024, bias=True)\n", + " (_up): Linear(in_features=256, out_features=1024, bias=True)\n", + " (_down): Linear(in_features=1024, out_features=256, bias=True)\n", + " (_activation): SiLU()\n", + " (_dropout): Dropout(p=0.1, inplace=False)\n", + " )\n", + " (_norm1): RMSNorm()\n", + " (_norm2): RMSNorm()\n", + " )\n", + " )\n", + " (_norm): RMSNorm()\n", + " (_linear): Linear(in_features=256, out_features=100, bias=True)\n", + ")" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 1. Исходный текст\n", + "text = \"Deep learning is amazing. Transformers changed the world. Attention is all you need. GPT models revolutionized NLP.\"\n", + "\n", + "# 2. Обучаем токенизатор\n", + "bpe = BPE(vocab_size=100)\n", + "bpe.fit(text)\n", + "\n", + "# 3. Создаем датасет\n", + "dataset = GPTDataset(text, bpe, block_size=8)\n", + "print(f\"Dataset length: {len(dataset)}\")\n", + "\n", + "# 4. Инициализируем модель\n", + "model = Llama(\n", + " vocab_size=len(bpe.vocab), # размер словаря BPE\n", + " max_seq_len=512, # GPT-2 использует контекст в 512 токена\n", + " emb_size=256, # размер эмбеддингов\n", + " num_heads=4, # количество голов внимания\n", + " head_size=64, # размер каждой головы (256 / 4)\n", + " num_layers=4, # количество блоков Transformer\n", + " dropout=0.1 # стандартный dropout GPT-2\n", + ")\n", + "\n", + "# 5. Обучаем\n", + "train_llama(model, dataset, epochs=100, batch_size=4)" + ] + }, + { + "cell_type": "markdown", + "id": "631fa9c5", + "metadata": {}, + "source": [ + "\n", + "---\n", + "\n", + "### 5.2 Дообучение\n", + "\n", + "После предобучения LLAMA уже знает структуру и грамматику языка. \n", + "На втором этапе она дообучается на конкретных задачах (например, классификация, QA) с помощью размеченных данных.\n", + "\n", + "Технически это почти то же обучение, только:\n", + "\n", + "- Загружаем модель с уже обученными весами.\n", + "- Используем новые данные.\n", + "- Можно уменьшить скорость обучения.\n", + "- Иногда замораживают часть слоёв (например, эмбеддинги).\n" + ] + }, + { + "cell_type": "markdown", + "id": "7bce4bb4", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "8efb1396", + "metadata": {}, + "outputs": [], + "source": [ + "def fine_tune_llama(model, dataset, epochs=3, batch_size=16, lr=1e-5, device='cpu', freeze_embeddings=True):\n", + " if freeze_embeddings:\n", + " for param in model._token_embeddings.parameters():\n", + " param.requires_grad = False\n", + " for param in model._position_embeddings.parameters():\n", + " param.requires_grad = False\n", + "\n", + " dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)\n", + " optimizer = optim.AdamW(filter(lambda p: p.requires_grad, model.parameters()), lr=lr)\n", + "\n", + " model.to(device)\n", + " model.train()\n", + "\n", + " for epoch in range(epochs):\n", + " total_loss = 0\n", + " for x, y in dataloader:\n", + " x, y = x.to(device), y.to(device)\n", + " logits, _ = model(x, use_cache=False)\n", + " loss = F.cross_entropy(logits.view(-1, logits.size(-1)), y.view(-1))\n", + " optimizer.zero_grad()\n", + " loss.backward()\n", + " optimizer.step()\n", + " total_loss += loss.item()\n", + " print(f\"Fine-tune Epoch {epoch+1}/{epochs}, Loss: {total_loss / len(dataloader):.4f}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "b4a1c9d9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Fine-tune Epoch 1/10, Loss: 4.8250\n", + "Fine-tune Epoch 2/10, Loss: 2.6400\n", + "Fine-tune Epoch 3/10, Loss: 1.6920\n", + "Fine-tune Epoch 4/10, Loss: 1.2630\n", + "Fine-tune Epoch 5/10, Loss: 1.0183\n", + "Fine-tune Epoch 6/10, Loss: 0.8237\n", + "Fine-tune Epoch 7/10, Loss: 0.6869\n", + "Fine-tune Epoch 8/10, Loss: 0.5854\n", + "Fine-tune Epoch 9/10, Loss: 0.5155\n", + "Fine-tune Epoch 10/10, Loss: 0.4489\n" + ] + } + ], + "source": [ + "# Например, мы хотим дообучить модель на стиле коротких технических фраз\n", + "fine_tune_text = \"\"\"\n", + "Transformers revolutionize NLP.\n", + "Deep learning enables self-attention.\n", + "GPT generates text autoregressively.\n", + "\"\"\"\n", + "\n", + "dataset = GPTDataset(fine_tune_text, bpe, block_size=8)\n", + "\n", + "\n", + "# Запуск дообучения\n", + "fine_tune_llama(model, dataset, epochs=10, batch_size=4, lr=1e-4)" + ] + }, + { + "cell_type": "markdown", + "id": "cc9106b7", + "metadata": {}, + "source": [ + "## 📝 6. Генерация текста после обучения" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "d77b8ff5", + "metadata": {}, + "outputs": [], + "source": [ + "def generate_text(model, bpe, prompt: str, max_new_tokens=20, device='cpu'):\n", + " model.eval()\n", + " ids = torch.tensor([bpe.encode(prompt)], dtype=torch.long).to(device)\n", + " out = model.generate(ids, max_new_tokens=max_new_tokens, do_sample=True)\n", + " text = bpe.decode(out[0].tolist())\n", + " return text" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "79fea720", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Deep learning ena les selelf les te\n" + ] + } + ], + "source": [ + "print(generate_text(model, bpe, \"Deep learning\", max_new_tokens=20))" + ] + }, { "cell_type": "code", "execution_count": null, - "id": "8efb1396", + "id": "05c4de3d", "metadata": {}, "outputs": [], "source": [] diff --git a/pyproject.toml b/pyproject.toml index bf30674..f0fa689 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,8 @@ dependencies = [ "llm", "tqdm>=4,<5", "ipykernel", + "torch==2.8.0", + "matplotlib==3.10.6", ] [project.optional-dependencies] diff --git a/uv.lock b/uv.lock index ed34823..0330070 100644 --- a/uv.lock +++ b/uv.lock @@ -525,6 +525,163 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" }, ] +[[package]] +name = "contourpy" +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +dependencies = [ + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/a3/da4153ec8fe25d263aa48c1a4cbde7f49b59af86f0b6f7862788c60da737/contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934", size = 268551, upload-time = "2025-04-15T17:34:46.581Z" }, + { url = "https://files.pythonhosted.org/packages/2f/6c/330de89ae1087eb622bfca0177d32a7ece50c3ef07b28002de4757d9d875/contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989", size = 253399, upload-time = "2025-04-15T17:34:51.427Z" }, + { url = "https://files.pythonhosted.org/packages/c1/bd/20c6726b1b7f81a8bee5271bed5c165f0a8e1f572578a9d27e2ccb763cb2/contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d", size = 312061, upload-time = "2025-04-15T17:34:55.961Z" }, + { url = "https://files.pythonhosted.org/packages/22/fc/a9665c88f8a2473f823cf1ec601de9e5375050f1958cbb356cdf06ef1ab6/contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9", size = 351956, upload-time = "2025-04-15T17:35:00.992Z" }, + { url = "https://files.pythonhosted.org/packages/25/eb/9f0a0238f305ad8fb7ef42481020d6e20cf15e46be99a1fcf939546a177e/contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512", size = 320872, upload-time = "2025-04-15T17:35:06.177Z" }, + { url = "https://files.pythonhosted.org/packages/32/5c/1ee32d1c7956923202f00cf8d2a14a62ed7517bdc0ee1e55301227fc273c/contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631", size = 325027, upload-time = "2025-04-15T17:35:11.244Z" }, + { url = "https://files.pythonhosted.org/packages/83/bf/9baed89785ba743ef329c2b07fd0611d12bfecbedbdd3eeecf929d8d3b52/contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f", size = 1306641, upload-time = "2025-04-15T17:35:26.701Z" }, + { url = "https://files.pythonhosted.org/packages/d4/cc/74e5e83d1e35de2d28bd97033426b450bc4fd96e092a1f7a63dc7369b55d/contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2", size = 1374075, upload-time = "2025-04-15T17:35:43.204Z" }, + { url = "https://files.pythonhosted.org/packages/0c/42/17f3b798fd5e033b46a16f8d9fcb39f1aba051307f5ebf441bad1ecf78f8/contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0", size = 177534, upload-time = "2025-04-15T17:35:46.554Z" }, + { url = "https://files.pythonhosted.org/packages/54/ec/5162b8582f2c994721018d0c9ece9dc6ff769d298a8ac6b6a652c307e7df/contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a", size = 221188, upload-time = "2025-04-15T17:35:50.064Z" }, + { url = "https://files.pythonhosted.org/packages/b3/b9/ede788a0b56fc5b071639d06c33cb893f68b1178938f3425debebe2dab78/contourpy-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a37a2fb93d4df3fc4c0e363ea4d16f83195fc09c891bc8ce072b9d084853445", size = 269636, upload-time = "2025-04-15T17:35:54.473Z" }, + { url = "https://files.pythonhosted.org/packages/e6/75/3469f011d64b8bbfa04f709bfc23e1dd71be54d05b1b083be9f5b22750d1/contourpy-1.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b7cd50c38f500bbcc9b6a46643a40e0913673f869315d8e70de0438817cb7773", size = 254636, upload-time = "2025-04-15T17:35:58.283Z" }, + { url = "https://files.pythonhosted.org/packages/8d/2f/95adb8dae08ce0ebca4fd8e7ad653159565d9739128b2d5977806656fcd2/contourpy-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6658ccc7251a4433eebd89ed2672c2ed96fba367fd25ca9512aa92a4b46c4f1", size = 313053, upload-time = "2025-04-15T17:36:03.235Z" }, + { url = "https://files.pythonhosted.org/packages/c3/a6/8ccf97a50f31adfa36917707fe39c9a0cbc24b3bbb58185577f119736cc9/contourpy-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:70771a461aaeb335df14deb6c97439973d253ae70660ca085eec25241137ef43", size = 352985, upload-time = "2025-04-15T17:36:08.275Z" }, + { url = "https://files.pythonhosted.org/packages/1d/b6/7925ab9b77386143f39d9c3243fdd101621b4532eb126743201160ffa7e6/contourpy-1.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65a887a6e8c4cd0897507d814b14c54a8c2e2aa4ac9f7686292f9769fcf9a6ab", size = 323750, upload-time = "2025-04-15T17:36:13.29Z" }, + { url = "https://files.pythonhosted.org/packages/c2/f3/20c5d1ef4f4748e52d60771b8560cf00b69d5c6368b5c2e9311bcfa2a08b/contourpy-1.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3859783aefa2b8355697f16642695a5b9792e7a46ab86da1118a4a23a51a33d7", size = 326246, upload-time = "2025-04-15T17:36:18.329Z" }, + { url = "https://files.pythonhosted.org/packages/8c/e5/9dae809e7e0b2d9d70c52b3d24cba134dd3dad979eb3e5e71f5df22ed1f5/contourpy-1.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eab0f6db315fa4d70f1d8ab514e527f0366ec021ff853d7ed6a2d33605cf4b83", size = 1308728, upload-time = "2025-04-15T17:36:33.878Z" }, + { url = "https://files.pythonhosted.org/packages/e2/4a/0058ba34aeea35c0b442ae61a4f4d4ca84d6df8f91309bc2d43bb8dd248f/contourpy-1.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d91a3ccc7fea94ca0acab82ceb77f396d50a1f67412efe4c526f5d20264e6ecd", size = 1375762, upload-time = "2025-04-15T17:36:51.295Z" }, + { url = "https://files.pythonhosted.org/packages/09/33/7174bdfc8b7767ef2c08ed81244762d93d5c579336fc0b51ca57b33d1b80/contourpy-1.3.2-cp311-cp311-win32.whl", hash = "sha256:1c48188778d4d2f3d48e4643fb15d8608b1d01e4b4d6b0548d9b336c28fc9b6f", size = 178196, upload-time = "2025-04-15T17:36:55.002Z" }, + { url = "https://files.pythonhosted.org/packages/5e/fe/4029038b4e1c4485cef18e480b0e2cd2d755448bb071eb9977caac80b77b/contourpy-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:5ebac872ba09cb8f2131c46b8739a7ff71de28a24c869bcad554477eb089a878", size = 222017, upload-time = "2025-04-15T17:36:58.576Z" }, + { url = "https://files.pythonhosted.org/packages/34/f7/44785876384eff370c251d58fd65f6ad7f39adce4a093c934d4a67a7c6b6/contourpy-1.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4caf2bcd2969402bf77edc4cb6034c7dd7c0803213b3523f111eb7460a51b8d2", size = 271580, upload-time = "2025-04-15T17:37:03.105Z" }, + { url = "https://files.pythonhosted.org/packages/93/3b/0004767622a9826ea3d95f0e9d98cd8729015768075d61f9fea8eeca42a8/contourpy-1.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82199cb78276249796419fe36b7386bd8d2cc3f28b3bc19fe2454fe2e26c4c15", size = 255530, upload-time = "2025-04-15T17:37:07.026Z" }, + { url = "https://files.pythonhosted.org/packages/e7/bb/7bd49e1f4fa805772d9fd130e0d375554ebc771ed7172f48dfcd4ca61549/contourpy-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92", size = 307688, upload-time = "2025-04-15T17:37:11.481Z" }, + { url = "https://files.pythonhosted.org/packages/fc/97/e1d5dbbfa170725ef78357a9a0edc996b09ae4af170927ba8ce977e60a5f/contourpy-1.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d14f12932a8d620e307f715857107b1d1845cc44fdb5da2bc8e850f5ceba9f87", size = 347331, upload-time = "2025-04-15T17:37:18.212Z" }, + { url = "https://files.pythonhosted.org/packages/6f/66/e69e6e904f5ecf6901be3dd16e7e54d41b6ec6ae3405a535286d4418ffb4/contourpy-1.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:532fd26e715560721bb0d5fc7610fce279b3699b018600ab999d1be895b09415", size = 318963, upload-time = "2025-04-15T17:37:22.76Z" }, + { url = "https://files.pythonhosted.org/packages/a8/32/b8a1c8965e4f72482ff2d1ac2cd670ce0b542f203c8e1d34e7c3e6925da7/contourpy-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b383144cf2d2c29f01a1e8170f50dacf0eac02d64139dcd709a8ac4eb3cfe", size = 323681, upload-time = "2025-04-15T17:37:33.001Z" }, + { url = "https://files.pythonhosted.org/packages/30/c6/12a7e6811d08757c7162a541ca4c5c6a34c0f4e98ef2b338791093518e40/contourpy-1.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49f73e61f1f774650a55d221803b101d966ca0c5a2d6d5e4320ec3997489441", size = 1308674, upload-time = "2025-04-15T17:37:48.64Z" }, + { url = "https://files.pythonhosted.org/packages/2a/8a/bebe5a3f68b484d3a2b8ffaf84704b3e343ef1addea528132ef148e22b3b/contourpy-1.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d80b2c0300583228ac98d0a927a1ba6a2ba6b8a742463c564f1d419ee5b211e", size = 1380480, upload-time = "2025-04-15T17:38:06.7Z" }, + { url = "https://files.pythonhosted.org/packages/34/db/fcd325f19b5978fb509a7d55e06d99f5f856294c1991097534360b307cf1/contourpy-1.3.2-cp312-cp312-win32.whl", hash = "sha256:90df94c89a91b7362e1142cbee7568f86514412ab8a2c0d0fca72d7e91b62912", size = 178489, upload-time = "2025-04-15T17:38:10.338Z" }, + { url = "https://files.pythonhosted.org/packages/01/c8/fadd0b92ffa7b5eb5949bf340a63a4a496a6930a6c37a7ba0f12acb076d6/contourpy-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c942a01d9163e2e5cfb05cb66110121b8d07ad438a17f9e766317bcb62abf73", size = 223042, upload-time = "2025-04-15T17:38:14.239Z" }, + { url = "https://files.pythonhosted.org/packages/2e/61/5673f7e364b31e4e7ef6f61a4b5121c5f170f941895912f773d95270f3a2/contourpy-1.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:de39db2604ae755316cb5967728f4bea92685884b1e767b7c24e983ef5f771cb", size = 271630, upload-time = "2025-04-15T17:38:19.142Z" }, + { url = "https://files.pythonhosted.org/packages/ff/66/a40badddd1223822c95798c55292844b7e871e50f6bfd9f158cb25e0bd39/contourpy-1.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3f9e896f447c5c8618f1edb2bafa9a4030f22a575ec418ad70611450720b5b08", size = 255670, upload-time = "2025-04-15T17:38:23.688Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c7/cf9fdee8200805c9bc3b148f49cb9482a4e3ea2719e772602a425c9b09f8/contourpy-1.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71e2bd4a1c4188f5c2b8d274da78faab884b59df20df63c34f74aa1813c4427c", size = 306694, upload-time = "2025-04-15T17:38:28.238Z" }, + { url = "https://files.pythonhosted.org/packages/dd/e7/ccb9bec80e1ba121efbffad7f38021021cda5be87532ec16fd96533bb2e0/contourpy-1.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de425af81b6cea33101ae95ece1f696af39446db9682a0b56daaa48cfc29f38f", size = 345986, upload-time = "2025-04-15T17:38:33.502Z" }, + { url = "https://files.pythonhosted.org/packages/dc/49/ca13bb2da90391fa4219fdb23b078d6065ada886658ac7818e5441448b78/contourpy-1.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:977e98a0e0480d3fe292246417239d2d45435904afd6d7332d8455981c408b85", size = 318060, upload-time = "2025-04-15T17:38:38.672Z" }, + { url = "https://files.pythonhosted.org/packages/c8/65/5245ce8c548a8422236c13ffcdcdada6a2a812c361e9e0c70548bb40b661/contourpy-1.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:434f0adf84911c924519d2b08fc10491dd282b20bdd3fa8f60fd816ea0b48841", size = 322747, upload-time = "2025-04-15T17:38:43.712Z" }, + { url = "https://files.pythonhosted.org/packages/72/30/669b8eb48e0a01c660ead3752a25b44fdb2e5ebc13a55782f639170772f9/contourpy-1.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c66c4906cdbc50e9cba65978823e6e00b45682eb09adbb78c9775b74eb222422", size = 1308895, upload-time = "2025-04-15T17:39:00.224Z" }, + { url = "https://files.pythonhosted.org/packages/05/5a/b569f4250decee6e8d54498be7bdf29021a4c256e77fe8138c8319ef8eb3/contourpy-1.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8b7fc0cd78ba2f4695fd0a6ad81a19e7e3ab825c31b577f384aa9d7817dc3bef", size = 1379098, upload-time = "2025-04-15T17:43:29.649Z" }, + { url = "https://files.pythonhosted.org/packages/19/ba/b227c3886d120e60e41b28740ac3617b2f2b971b9f601c835661194579f1/contourpy-1.3.2-cp313-cp313-win32.whl", hash = "sha256:15ce6ab60957ca74cff444fe66d9045c1fd3e92c8936894ebd1f3eef2fff075f", size = 178535, upload-time = "2025-04-15T17:44:44.532Z" }, + { url = "https://files.pythonhosted.org/packages/12/6e/2fed56cd47ca739b43e892707ae9a13790a486a3173be063681ca67d2262/contourpy-1.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9", size = 223096, upload-time = "2025-04-15T17:44:48.194Z" }, + { url = "https://files.pythonhosted.org/packages/54/4c/e76fe2a03014a7c767d79ea35c86a747e9325537a8b7627e0e5b3ba266b4/contourpy-1.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f", size = 285090, upload-time = "2025-04-15T17:43:34.084Z" }, + { url = "https://files.pythonhosted.org/packages/7b/e2/5aba47debd55d668e00baf9651b721e7733975dc9fc27264a62b0dd26eb8/contourpy-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c85bb486e9be652314bb5b9e2e3b0d1b2e643d5eec4992c0fbe8ac71775da739", size = 268643, upload-time = "2025-04-15T17:43:38.626Z" }, + { url = "https://files.pythonhosted.org/packages/a1/37/cd45f1f051fe6230f751cc5cdd2728bb3a203f5619510ef11e732109593c/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:745b57db7758f3ffc05a10254edd3182a2a83402a89c00957a8e8a22f5582823", size = 310443, upload-time = "2025-04-15T17:43:44.522Z" }, + { url = "https://files.pythonhosted.org/packages/8b/a2/36ea6140c306c9ff6dd38e3bcec80b3b018474ef4d17eb68ceecd26675f4/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:970e9173dbd7eba9b4e01aab19215a48ee5dd3f43cef736eebde064a171f89a5", size = 349865, upload-time = "2025-04-15T17:43:49.545Z" }, + { url = "https://files.pythonhosted.org/packages/95/b7/2fc76bc539693180488f7b6cc518da7acbbb9e3b931fd9280504128bf956/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6c4639a9c22230276b7bffb6a850dfc8258a2521305e1faefe804d006b2e532", size = 321162, upload-time = "2025-04-15T17:43:54.203Z" }, + { url = "https://files.pythonhosted.org/packages/f4/10/76d4f778458b0aa83f96e59d65ece72a060bacb20cfbee46cf6cd5ceba41/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc829960f34ba36aad4302e78eabf3ef16a3a100863f0d4eeddf30e8a485a03b", size = 327355, upload-time = "2025-04-15T17:44:01.025Z" }, + { url = "https://files.pythonhosted.org/packages/43/a3/10cf483ea683f9f8ab096c24bad3cce20e0d1dd9a4baa0e2093c1c962d9d/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d32530b534e986374fc19eaa77fcb87e8a99e5431499949b828312bdcd20ac52", size = 1307935, upload-time = "2025-04-15T17:44:17.322Z" }, + { url = "https://files.pythonhosted.org/packages/78/73/69dd9a024444489e22d86108e7b913f3528f56cfc312b5c5727a44188471/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e298e7e70cf4eb179cc1077be1c725b5fd131ebc81181bf0c03525c8abc297fd", size = 1372168, upload-time = "2025-04-15T17:44:33.43Z" }, + { url = "https://files.pythonhosted.org/packages/0f/1b/96d586ccf1b1a9d2004dd519b25fbf104a11589abfd05484ff12199cca21/contourpy-1.3.2-cp313-cp313t-win32.whl", hash = "sha256:d0e589ae0d55204991450bb5c23f571c64fe43adaa53f93fc902a84c96f52fe1", size = 189550, upload-time = "2025-04-15T17:44:37.092Z" }, + { url = "https://files.pythonhosted.org/packages/b0/e6/6000d0094e8a5e32ad62591c8609e269febb6e4db83a1c75ff8868b42731/contourpy-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:78e9253c3de756b3f6a5174d024c4835acd59eb3f8e2ca13e775dbffe1558f69", size = 238214, upload-time = "2025-04-15T17:44:40.827Z" }, + { url = "https://files.pythonhosted.org/packages/33/05/b26e3c6ecc05f349ee0013f0bb850a761016d89cec528a98193a48c34033/contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c", size = 265681, upload-time = "2025-04-15T17:44:59.314Z" }, + { url = "https://files.pythonhosted.org/packages/2b/25/ac07d6ad12affa7d1ffed11b77417d0a6308170f44ff20fa1d5aa6333f03/contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16", size = 315101, upload-time = "2025-04-15T17:45:04.165Z" }, + { url = "https://files.pythonhosted.org/packages/8f/4d/5bb3192bbe9d3f27e3061a6a8e7733c9120e203cb8515767d30973f71030/contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad", size = 220599, upload-time = "2025-04-15T17:45:08.456Z" }, + { url = "https://files.pythonhosted.org/packages/ff/c0/91f1215d0d9f9f343e4773ba6c9b89e8c0cc7a64a6263f21139da639d848/contourpy-1.3.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5f5964cdad279256c084b69c3f412b7801e15356b16efa9d78aa974041903da0", size = 266807, upload-time = "2025-04-15T17:45:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/d4/79/6be7e90c955c0487e7712660d6cead01fa17bff98e0ea275737cc2bc8e71/contourpy-1.3.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49b65a95d642d4efa8f64ba12558fcb83407e58a2dfba9d796d77b63ccfcaff5", size = 318729, upload-time = "2025-04-15T17:45:20.166Z" }, + { url = "https://files.pythonhosted.org/packages/87/68/7f46fb537958e87427d98a4074bcde4b67a70b04900cfc5ce29bc2f556c1/contourpy-1.3.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8c5acb8dddb0752bf252e01a3035b21443158910ac16a3b0d20e7fed7d534ce5", size = 221791, upload-time = "2025-04-15T17:45:24.794Z" }, +] + +[[package]] +name = "contourpy" +version = "1.3.3" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.14'", + "python_full_version >= '3.12' and python_full_version < '3.14'", + "python_full_version == '3.11.*'", +] +dependencies = [ + { name = "numpy", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/2e/c4390a31919d8a78b90e8ecf87cd4b4c4f05a5b48d05ec17db8e5404c6f4/contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1", size = 288773, upload-time = "2025-07-26T12:01:02.277Z" }, + { url = "https://files.pythonhosted.org/packages/0d/44/c4b0b6095fef4dc9c420e041799591e3b63e9619e3044f7f4f6c21c0ab24/contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381", size = 270149, upload-time = "2025-07-26T12:01:04.072Z" }, + { url = "https://files.pythonhosted.org/packages/30/2e/dd4ced42fefac8470661d7cb7e264808425e6c5d56d175291e93890cce09/contourpy-1.3.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:929ddf8c4c7f348e4c0a5a3a714b5c8542ffaa8c22954862a46ca1813b667ee7", size = 329222, upload-time = "2025-07-26T12:01:05.688Z" }, + { url = "https://files.pythonhosted.org/packages/f2/74/cc6ec2548e3d276c71389ea4802a774b7aa3558223b7bade3f25787fafc2/contourpy-1.3.3-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e999574eddae35f1312c2b4b717b7885d4edd6cb46700e04f7f02db454e67c1", size = 377234, upload-time = "2025-07-26T12:01:07.054Z" }, + { url = "https://files.pythonhosted.org/packages/03/b3/64ef723029f917410f75c09da54254c5f9ea90ef89b143ccadb09df14c15/contourpy-1.3.3-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf67e0e3f482cb69779dd3061b534eb35ac9b17f163d851e2a547d56dba0a3a", size = 380555, upload-time = "2025-07-26T12:01:08.801Z" }, + { url = "https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51e79c1f7470158e838808d4a996fa9bac72c498e93d8ebe5119bc1e6becb0db", size = 355238, upload-time = "2025-07-26T12:01:10.319Z" }, + { url = "https://files.pythonhosted.org/packages/98/56/f914f0dd678480708a04cfd2206e7c382533249bc5001eb9f58aa693e200/contourpy-1.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:598c3aaece21c503615fd59c92a3598b428b2f01bfb4b8ca9c4edeecc2438620", size = 1326218, upload-time = "2025-07-26T12:01:12.659Z" }, + { url = "https://files.pythonhosted.org/packages/fb/d7/4a972334a0c971acd5172389671113ae82aa7527073980c38d5868ff1161/contourpy-1.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:322ab1c99b008dad206d406bb61d014cf0174df491ae9d9d0fac6a6fda4f977f", size = 1392867, upload-time = "2025-07-26T12:01:15.533Z" }, + { url = "https://files.pythonhosted.org/packages/75/3e/f2cc6cd56dc8cff46b1a56232eabc6feea52720083ea71ab15523daab796/contourpy-1.3.3-cp311-cp311-win32.whl", hash = "sha256:fd907ae12cd483cd83e414b12941c632a969171bf90fc937d0c9f268a31cafff", size = 183677, upload-time = "2025-07-26T12:01:17.088Z" }, + { url = "https://files.pythonhosted.org/packages/98/4b/9bd370b004b5c9d8045c6c33cf65bae018b27aca550a3f657cdc99acdbd8/contourpy-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:3519428f6be58431c56581f1694ba8e50626f2dd550af225f82fb5f5814d2a42", size = 225234, upload-time = "2025-07-26T12:01:18.256Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b6/71771e02c2e004450c12b1120a5f488cad2e4d5b590b1af8bad060360fe4/contourpy-1.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:15ff10bfada4bf92ec8b31c62bf7c1834c244019b4a33095a68000d7075df470", size = 193123, upload-time = "2025-07-26T12:01:19.848Z" }, + { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", size = 293419, upload-time = "2025-07-26T12:01:21.16Z" }, + { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", size = 273979, upload-time = "2025-07-26T12:01:22.448Z" }, + { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", size = 332653, upload-time = "2025-07-26T12:01:24.155Z" }, + { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", size = 379536, upload-time = "2025-07-26T12:01:25.91Z" }, + { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", size = 384397, upload-time = "2025-07-26T12:01:27.152Z" }, + { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", size = 362601, upload-time = "2025-07-26T12:01:28.808Z" }, + { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", size = 1331288, upload-time = "2025-07-26T12:01:31.198Z" }, + { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", size = 1403386, upload-time = "2025-07-26T12:01:33.947Z" }, + { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", size = 185018, upload-time = "2025-07-26T12:01:35.64Z" }, + { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", size = 226567, upload-time = "2025-07-26T12:01:36.804Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", size = 193655, upload-time = "2025-07-26T12:01:37.999Z" }, + { url = "https://files.pythonhosted.org/packages/68/35/0167aad910bbdb9599272bd96d01a9ec6852f36b9455cf2ca67bd4cc2d23/contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5", size = 293257, upload-time = "2025-07-26T12:01:39.367Z" }, + { url = "https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1", size = 274034, upload-time = "2025-07-26T12:01:40.645Z" }, + { url = "https://files.pythonhosted.org/packages/73/23/90e31ceeed1de63058a02cb04b12f2de4b40e3bef5e082a7c18d9c8ae281/contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286", size = 334672, upload-time = "2025-07-26T12:01:41.942Z" }, + { url = "https://files.pythonhosted.org/packages/ed/93/b43d8acbe67392e659e1d984700e79eb67e2acb2bd7f62012b583a7f1b55/contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5", size = 381234, upload-time = "2025-07-26T12:01:43.499Z" }, + { url = "https://files.pythonhosted.org/packages/46/3b/bec82a3ea06f66711520f75a40c8fc0b113b2a75edb36aa633eb11c4f50f/contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67", size = 385169, upload-time = "2025-07-26T12:01:45.219Z" }, + { url = "https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9", size = 362859, upload-time = "2025-07-26T12:01:46.519Z" }, + { url = "https://files.pythonhosted.org/packages/33/71/e2a7945b7de4e58af42d708a219f3b2f4cff7386e6b6ab0a0fa0033c49a9/contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659", size = 1332062, upload-time = "2025-07-26T12:01:48.964Z" }, + { url = "https://files.pythonhosted.org/packages/12/fc/4e87ac754220ccc0e807284f88e943d6d43b43843614f0a8afa469801db0/contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7", size = 1403932, upload-time = "2025-07-26T12:01:51.979Z" }, + { url = "https://files.pythonhosted.org/packages/a6/2e/adc197a37443f934594112222ac1aa7dc9a98faf9c3842884df9a9d8751d/contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d", size = 185024, upload-time = "2025-07-26T12:01:53.245Z" }, + { url = "https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263", size = 226578, upload-time = "2025-07-26T12:01:54.422Z" }, + { url = "https://files.pythonhosted.org/packages/8a/9a/2f6024a0c5995243cd63afdeb3651c984f0d2bc727fd98066d40e141ad73/contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9", size = 193524, upload-time = "2025-07-26T12:01:55.73Z" }, + { url = "https://files.pythonhosted.org/packages/c0/b3/f8a1a86bd3298513f500e5b1f5fd92b69896449f6cab6a146a5d52715479/contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d", size = 306730, upload-time = "2025-07-26T12:01:57.051Z" }, + { url = "https://files.pythonhosted.org/packages/3f/11/4780db94ae62fc0c2053909b65dc3246bd7cecfc4f8a20d957ad43aa4ad8/contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216", size = 287897, upload-time = "2025-07-26T12:01:58.663Z" }, + { url = "https://files.pythonhosted.org/packages/ae/15/e59f5f3ffdd6f3d4daa3e47114c53daabcb18574a26c21f03dc9e4e42ff0/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae", size = 326751, upload-time = "2025-07-26T12:02:00.343Z" }, + { url = "https://files.pythonhosted.org/packages/0f/81/03b45cfad088e4770b1dcf72ea78d3802d04200009fb364d18a493857210/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20", size = 375486, upload-time = "2025-07-26T12:02:02.128Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ba/49923366492ffbdd4486e970d421b289a670ae8cf539c1ea9a09822b371a/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99", size = 388106, upload-time = "2025-07-26T12:02:03.615Z" }, + { url = "https://files.pythonhosted.org/packages/9f/52/5b00ea89525f8f143651f9f03a0df371d3cbd2fccd21ca9b768c7a6500c2/contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b", size = 352548, upload-time = "2025-07-26T12:02:05.165Z" }, + { url = "https://files.pythonhosted.org/packages/32/1d/a209ec1a3a3452d490f6b14dd92e72280c99ae3d1e73da74f8277d4ee08f/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a", size = 1322297, upload-time = "2025-07-26T12:02:07.379Z" }, + { url = "https://files.pythonhosted.org/packages/bc/9e/46f0e8ebdd884ca0e8877e46a3f4e633f6c9c8c4f3f6e72be3fe075994aa/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e", size = 1391023, upload-time = "2025-07-26T12:02:10.171Z" }, + { url = "https://files.pythonhosted.org/packages/b9/70/f308384a3ae9cd2209e0849f33c913f658d3326900d0ff5d378d6a1422d2/contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3", size = 196157, upload-time = "2025-07-26T12:02:11.488Z" }, + { url = "https://files.pythonhosted.org/packages/b2/dd/880f890a6663b84d9e34a6f88cded89d78f0091e0045a284427cb6b18521/contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8", size = 240570, upload-time = "2025-07-26T12:02:12.754Z" }, + { url = "https://files.pythonhosted.org/packages/80/99/2adc7d8ffead633234817ef8e9a87115c8a11927a94478f6bb3d3f4d4f7d/contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301", size = 199713, upload-time = "2025-07-26T12:02:14.4Z" }, + { url = "https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a", size = 292189, upload-time = "2025-07-26T12:02:16.095Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77", size = 273251, upload-time = "2025-07-26T12:02:17.524Z" }, + { url = "https://files.pythonhosted.org/packages/b1/71/f93e1e9471d189f79d0ce2497007731c1e6bf9ef6d1d61b911430c3db4e5/contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5", size = 335810, upload-time = "2025-07-26T12:02:18.9Z" }, + { url = "https://files.pythonhosted.org/packages/91/f9/e35f4c1c93f9275d4e38681a80506b5510e9327350c51f8d4a5a724d178c/contourpy-1.3.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4", size = 382871, upload-time = "2025-07-26T12:02:20.418Z" }, + { url = "https://files.pythonhosted.org/packages/b5/71/47b512f936f66a0a900d81c396a7e60d73419868fba959c61efed7a8ab46/contourpy-1.3.3-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36", size = 386264, upload-time = "2025-07-26T12:02:21.916Z" }, + { url = "https://files.pythonhosted.org/packages/04/5f/9ff93450ba96b09c7c2b3f81c94de31c89f92292f1380261bd7195bea4ea/contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3", size = 363819, upload-time = "2025-07-26T12:02:23.759Z" }, + { url = "https://files.pythonhosted.org/packages/3e/a6/0b185d4cc480ee494945cde102cb0149ae830b5fa17bf855b95f2e70ad13/contourpy-1.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b", size = 1333650, upload-time = "2025-07-26T12:02:26.181Z" }, + { url = "https://files.pythonhosted.org/packages/43/d7/afdc95580ca56f30fbcd3060250f66cedbde69b4547028863abd8aa3b47e/contourpy-1.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36", size = 1404833, upload-time = "2025-07-26T12:02:28.782Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e2/366af18a6d386f41132a48f033cbd2102e9b0cf6345d35ff0826cd984566/contourpy-1.3.3-cp314-cp314-win32.whl", hash = "sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d", size = 189692, upload-time = "2025-07-26T12:02:30.128Z" }, + { url = "https://files.pythonhosted.org/packages/7d/c2/57f54b03d0f22d4044b8afb9ca0e184f8b1afd57b4f735c2fa70883dc601/contourpy-1.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd", size = 232424, upload-time = "2025-07-26T12:02:31.395Z" }, + { url = "https://files.pythonhosted.org/packages/18/79/a9416650df9b525737ab521aa181ccc42d56016d2123ddcb7b58e926a42c/contourpy-1.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339", size = 198300, upload-time = "2025-07-26T12:02:32.956Z" }, + { url = "https://files.pythonhosted.org/packages/1f/42/38c159a7d0f2b7b9c04c64ab317042bb6952b713ba875c1681529a2932fe/contourpy-1.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772", size = 306769, upload-time = "2025-07-26T12:02:34.2Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6c/26a8205f24bca10974e77460de68d3d7c63e282e23782f1239f226fcae6f/contourpy-1.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77", size = 287892, upload-time = "2025-07-26T12:02:35.807Z" }, + { url = "https://files.pythonhosted.org/packages/66/06/8a475c8ab718ebfd7925661747dbb3c3ee9c82ac834ccb3570be49d129f4/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13", size = 326748, upload-time = "2025-07-26T12:02:37.193Z" }, + { url = "https://files.pythonhosted.org/packages/b4/a3/c5ca9f010a44c223f098fccd8b158bb1cb287378a31ac141f04730dc49be/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe", size = 375554, upload-time = "2025-07-26T12:02:38.894Z" }, + { url = "https://files.pythonhosted.org/packages/80/5b/68bd33ae63fac658a4145088c1e894405e07584a316738710b636c6d0333/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f", size = 388118, upload-time = "2025-07-26T12:02:40.642Z" }, + { url = "https://files.pythonhosted.org/packages/40/52/4c285a6435940ae25d7410a6c36bda5145839bc3f0beb20c707cda18b9d2/contourpy-1.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0", size = 352555, upload-time = "2025-07-26T12:02:42.25Z" }, + { url = "https://files.pythonhosted.org/packages/24/ee/3e81e1dd174f5c7fefe50e85d0892de05ca4e26ef1c9a59c2a57e43b865a/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4", size = 1322295, upload-time = "2025-07-26T12:02:44.668Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b2/6d913d4d04e14379de429057cd169e5e00f6c2af3bb13e1710bcbdb5da12/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f", size = 1391027, upload-time = "2025-07-26T12:02:47.09Z" }, + { url = "https://files.pythonhosted.org/packages/93/8a/68a4ec5c55a2971213d29a9374913f7e9f18581945a7a31d1a39b5d2dfe5/contourpy-1.3.3-cp314-cp314t-win32.whl", hash = "sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae", size = 202428, upload-time = "2025-07-26T12:02:48.691Z" }, + { url = "https://files.pythonhosted.org/packages/fa/96/fd9f641ffedc4fa3ace923af73b9d07e869496c9cc7a459103e6e978992f/contourpy-1.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc", size = 250331, upload-time = "2025-07-26T12:02:50.137Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8c/469afb6465b853afff216f9528ffda78a915ff880ed58813ba4faf4ba0b6/contourpy-1.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b", size = 203831, upload-time = "2025-07-26T12:02:51.449Z" }, + { url = "https://files.pythonhosted.org/packages/a5/29/8dcfe16f0107943fa92388c23f6e05cff0ba58058c4c95b00280d4c75a14/contourpy-1.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cd5dfcaeb10f7b7f9dc8941717c6c2ade08f587be2226222c12b25f0483ed497", size = 278809, upload-time = "2025-07-26T12:02:52.74Z" }, + { url = "https://files.pythonhosted.org/packages/85/a9/8b37ef4f7dafeb335daee3c8254645ef5725be4d9c6aa70b50ec46ef2f7e/contourpy-1.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0c1fc238306b35f246d61a1d416a627348b5cf0648648a031e14bb8705fcdfe8", size = 261593, upload-time = "2025-07-26T12:02:54.037Z" }, + { url = "https://files.pythonhosted.org/packages/0a/59/ebfb8c677c75605cc27f7122c90313fd2f375ff3c8d19a1694bda74aaa63/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70f9aad7de812d6541d29d2bbf8feb22ff7e1c299523db288004e3157ff4674e", size = 302202, upload-time = "2025-07-26T12:02:55.947Z" }, + { url = "https://files.pythonhosted.org/packages/3c/37/21972a15834d90bfbfb009b9d004779bd5a07a0ec0234e5ba8f64d5736f4/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ed3657edf08512fc3fe81b510e35c2012fbd3081d2e26160f27ca28affec989", size = 329207, upload-time = "2025-07-26T12:02:57.468Z" }, + { url = "https://files.pythonhosted.org/packages/0c/58/bd257695f39d05594ca4ad60df5bcb7e32247f9951fd09a9b8edb82d1daa/contourpy-1.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3d1a3799d62d45c18bafd41c5fa05120b96a28079f2393af559b843d1a966a77", size = 225315, upload-time = "2025-07-26T12:02:58.801Z" }, +] + [[package]] name = "coverage" version = "7.10.7" @@ -629,6 +786,15 @@ toml = [ { name = "tomli", marker = "python_full_version <= '3.11'" }, ] +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, +] + [[package]] name = "datasets" version = "4.1.1" @@ -749,6 +915,63 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d", size = 15988, upload-time = "2025-08-14T16:56:01.633Z" }, ] +[[package]] +name = "fonttools" +version = "4.60.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4b/42/97a13e47a1e51a5a7142475bbcf5107fe3a68fc34aef331c897d5fb98ad0/fonttools-4.60.1.tar.gz", hash = "sha256:ef00af0439ebfee806b25f24c8f92109157ff3fac5731dc7867957812e87b8d9", size = 3559823, upload-time = "2025-09-29T21:13:27.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/70/03e9d89a053caff6ae46053890eba8e4a5665a7c5638279ed4492e6d4b8b/fonttools-4.60.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9a52f254ce051e196b8fe2af4634c2d2f02c981756c6464dc192f1b6050b4e28", size = 2810747, upload-time = "2025-09-29T21:10:59.653Z" }, + { url = "https://files.pythonhosted.org/packages/6f/41/449ad5aff9670ab0df0f61ee593906b67a36d7e0b4d0cd7fa41ac0325bf5/fonttools-4.60.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7420a2696a44650120cdd269a5d2e56a477e2bfa9d95e86229059beb1c19e15", size = 2346909, upload-time = "2025-09-29T21:11:02.882Z" }, + { url = "https://files.pythonhosted.org/packages/9a/18/e5970aa96c8fad1cb19a9479cc3b7602c0c98d250fcdc06a5da994309c50/fonttools-4.60.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee0c0b3b35b34f782afc673d503167157094a16f442ace7c6c5e0ca80b08f50c", size = 4864572, upload-time = "2025-09-29T21:11:05.096Z" }, + { url = "https://files.pythonhosted.org/packages/ce/20/9b2b4051b6ec6689480787d506b5003f72648f50972a92d04527a456192c/fonttools-4.60.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:282dafa55f9659e8999110bd8ed422ebe1c8aecd0dc396550b038e6c9a08b8ea", size = 4794635, upload-time = "2025-09-29T21:11:08.651Z" }, + { url = "https://files.pythonhosted.org/packages/10/52/c791f57347c1be98f8345e3dca4ac483eb97666dd7c47f3059aeffab8b59/fonttools-4.60.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4ba4bd646e86de16160f0fb72e31c3b9b7d0721c3e5b26b9fa2fc931dfdb2652", size = 4843878, upload-time = "2025-09-29T21:11:10.893Z" }, + { url = "https://files.pythonhosted.org/packages/69/e9/35c24a8d01644cee8c090a22fad34d5b61d1e0a8ecbc9945ad785ebf2e9e/fonttools-4.60.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0b0835ed15dd5b40d726bb61c846a688f5b4ce2208ec68779bc81860adb5851a", size = 4954555, upload-time = "2025-09-29T21:11:13.24Z" }, + { url = "https://files.pythonhosted.org/packages/f7/86/fb1e994971be4bdfe3a307de6373ef69a9df83fb66e3faa9c8114893d4cc/fonttools-4.60.1-cp310-cp310-win32.whl", hash = "sha256:1525796c3ffe27bb6268ed2a1bb0dcf214d561dfaf04728abf01489eb5339dce", size = 2232019, upload-time = "2025-09-29T21:11:15.73Z" }, + { url = "https://files.pythonhosted.org/packages/40/84/62a19e2bd56f0e9fb347486a5b26376bade4bf6bbba64dda2c103bd08c94/fonttools-4.60.1-cp310-cp310-win_amd64.whl", hash = "sha256:268ecda8ca6cb5c4f044b1fb9b3b376e8cd1b361cef275082429dc4174907038", size = 2276803, upload-time = "2025-09-29T21:11:18.152Z" }, + { url = "https://files.pythonhosted.org/packages/ea/85/639aa9bface1537e0fb0f643690672dde0695a5bbbc90736bc571b0b1941/fonttools-4.60.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7b4c32e232a71f63a5d00259ca3d88345ce2a43295bb049d21061f338124246f", size = 2831872, upload-time = "2025-09-29T21:11:20.329Z" }, + { url = "https://files.pythonhosted.org/packages/6b/47/3c63158459c95093be9618794acb1067b3f4d30dcc5c3e8114b70e67a092/fonttools-4.60.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3630e86c484263eaac71d117085d509cbcf7b18f677906824e4bace598fb70d2", size = 2356990, upload-time = "2025-09-29T21:11:22.754Z" }, + { url = "https://files.pythonhosted.org/packages/94/dd/1934b537c86fcf99f9761823f1fc37a98fbd54568e8e613f29a90fed95a9/fonttools-4.60.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5c1015318e4fec75dd4943ad5f6a206d9727adf97410d58b7e32ab644a807914", size = 5042189, upload-time = "2025-09-29T21:11:25.061Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d2/9f4e4c4374dd1daa8367784e1bd910f18ba886db1d6b825b12edf6db3edc/fonttools-4.60.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e6c58beb17380f7c2ea181ea11e7db8c0ceb474c9dd45f48e71e2cb577d146a1", size = 4978683, upload-time = "2025-09-29T21:11:27.693Z" }, + { url = "https://files.pythonhosted.org/packages/cc/c4/0fb2dfd1ecbe9a07954cc13414713ed1eab17b1c0214ef07fc93df234a47/fonttools-4.60.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec3681a0cb34c255d76dd9d865a55f260164adb9fa02628415cdc2d43ee2c05d", size = 5021372, upload-time = "2025-09-29T21:11:30.257Z" }, + { url = "https://files.pythonhosted.org/packages/0c/d5/495fc7ae2fab20223cc87179a8f50f40f9a6f821f271ba8301ae12bb580f/fonttools-4.60.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f4b5c37a5f40e4d733d3bbaaef082149bee5a5ea3156a785ff64d949bd1353fa", size = 5132562, upload-time = "2025-09-29T21:11:32.737Z" }, + { url = "https://files.pythonhosted.org/packages/bc/fa/021dab618526323c744e0206b3f5c8596a2e7ae9aa38db5948a131123e83/fonttools-4.60.1-cp311-cp311-win32.whl", hash = "sha256:398447f3d8c0c786cbf1209711e79080a40761eb44b27cdafffb48f52bcec258", size = 2230288, upload-time = "2025-09-29T21:11:35.015Z" }, + { url = "https://files.pythonhosted.org/packages/bb/78/0e1a6d22b427579ea5c8273e1c07def2f325b977faaf60bb7ddc01456cb1/fonttools-4.60.1-cp311-cp311-win_amd64.whl", hash = "sha256:d066ea419f719ed87bc2c99a4a4bfd77c2e5949cb724588b9dd58f3fd90b92bf", size = 2278184, upload-time = "2025-09-29T21:11:37.434Z" }, + { url = "https://files.pythonhosted.org/packages/e3/f7/a10b101b7a6f8836a5adb47f2791f2075d044a6ca123f35985c42edc82d8/fonttools-4.60.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:7b0c6d57ab00dae9529f3faf187f2254ea0aa1e04215cf2f1a8ec277c96661bc", size = 2832953, upload-time = "2025-09-29T21:11:39.616Z" }, + { url = "https://files.pythonhosted.org/packages/ed/fe/7bd094b59c926acf2304d2151354ddbeb74b94812f3dc943c231db09cb41/fonttools-4.60.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:839565cbf14645952d933853e8ade66a463684ed6ed6c9345d0faf1f0e868877", size = 2352706, upload-time = "2025-09-29T21:11:41.826Z" }, + { url = "https://files.pythonhosted.org/packages/c0/ca/4bb48a26ed95a1e7eba175535fe5805887682140ee0a0d10a88e1de84208/fonttools-4.60.1-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8177ec9676ea6e1793c8a084a90b65a9f778771998eb919d05db6d4b1c0b114c", size = 4923716, upload-time = "2025-09-29T21:11:43.893Z" }, + { url = "https://files.pythonhosted.org/packages/b8/9f/2cb82999f686c1d1ddf06f6ae1a9117a880adbec113611cc9d22b2fdd465/fonttools-4.60.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:996a4d1834524adbb423385d5a629b868ef9d774670856c63c9a0408a3063401", size = 4968175, upload-time = "2025-09-29T21:11:46.439Z" }, + { url = "https://files.pythonhosted.org/packages/18/79/be569699e37d166b78e6218f2cde8c550204f2505038cdd83b42edc469b9/fonttools-4.60.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a46b2f450bc79e06ef3b6394f0c68660529ed51692606ad7f953fc2e448bc903", size = 4911031, upload-time = "2025-09-29T21:11:48.977Z" }, + { url = "https://files.pythonhosted.org/packages/cc/9f/89411cc116effaec5260ad519162f64f9c150e5522a27cbb05eb62d0c05b/fonttools-4.60.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6ec722ee589e89a89f5b7574f5c45604030aa6ae24cb2c751e2707193b466fed", size = 5062966, upload-time = "2025-09-29T21:11:54.344Z" }, + { url = "https://files.pythonhosted.org/packages/62/a1/f888221934b5731d46cb9991c7a71f30cb1f97c0ef5fcf37f8da8fce6c8e/fonttools-4.60.1-cp312-cp312-win32.whl", hash = "sha256:b2cf105cee600d2de04ca3cfa1f74f1127f8455b71dbad02b9da6ec266e116d6", size = 2218750, upload-time = "2025-09-29T21:11:56.601Z" }, + { url = "https://files.pythonhosted.org/packages/88/8f/a55b5550cd33cd1028601df41acd057d4be20efa5c958f417b0c0613924d/fonttools-4.60.1-cp312-cp312-win_amd64.whl", hash = "sha256:992775c9fbe2cf794786fa0ffca7f09f564ba3499b8fe9f2f80bd7197db60383", size = 2267026, upload-time = "2025-09-29T21:11:58.852Z" }, + { url = "https://files.pythonhosted.org/packages/7c/5b/cdd2c612277b7ac7ec8c0c9bc41812c43dc7b2d5f2b0897e15fdf5a1f915/fonttools-4.60.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6f68576bb4bbf6060c7ab047b1574a1ebe5c50a17de62830079967b211059ebb", size = 2825777, upload-time = "2025-09-29T21:12:01.22Z" }, + { url = "https://files.pythonhosted.org/packages/d6/8a/de9cc0540f542963ba5e8f3a1f6ad48fa211badc3177783b9d5cadf79b5d/fonttools-4.60.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:eedacb5c5d22b7097482fa834bda0dafa3d914a4e829ec83cdea2a01f8c813c4", size = 2348080, upload-time = "2025-09-29T21:12:03.785Z" }, + { url = "https://files.pythonhosted.org/packages/2d/8b/371ab3cec97ee3fe1126b3406b7abd60c8fec8975fd79a3c75cdea0c3d83/fonttools-4.60.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b33a7884fabd72bdf5f910d0cf46be50dce86a0362a65cfc746a4168c67eb96c", size = 4903082, upload-time = "2025-09-29T21:12:06.382Z" }, + { url = "https://files.pythonhosted.org/packages/04/05/06b1455e4bc653fcb2117ac3ef5fa3a8a14919b93c60742d04440605d058/fonttools-4.60.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2409d5fb7b55fd70f715e6d34e7a6e4f7511b8ad29a49d6df225ee76da76dd77", size = 4960125, upload-time = "2025-09-29T21:12:09.314Z" }, + { url = "https://files.pythonhosted.org/packages/8e/37/f3b840fcb2666f6cb97038793606bdd83488dca2d0b0fc542ccc20afa668/fonttools-4.60.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c8651e0d4b3bdeda6602b85fdc2abbefc1b41e573ecb37b6779c4ca50753a199", size = 4901454, upload-time = "2025-09-29T21:12:11.931Z" }, + { url = "https://files.pythonhosted.org/packages/fd/9e/eb76f77e82f8d4a46420aadff12cec6237751b0fb9ef1de373186dcffb5f/fonttools-4.60.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:145daa14bf24824b677b9357c5e44fd8895c2a8f53596e1b9ea3496081dc692c", size = 5044495, upload-time = "2025-09-29T21:12:15.241Z" }, + { url = "https://files.pythonhosted.org/packages/f8/b3/cede8f8235d42ff7ae891bae8d619d02c8ac9fd0cfc450c5927a6200c70d/fonttools-4.60.1-cp313-cp313-win32.whl", hash = "sha256:2299df884c11162617a66b7c316957d74a18e3758c0274762d2cc87df7bc0272", size = 2217028, upload-time = "2025-09-29T21:12:17.96Z" }, + { url = "https://files.pythonhosted.org/packages/75/4d/b022c1577807ce8b31ffe055306ec13a866f2337ecee96e75b24b9b753ea/fonttools-4.60.1-cp313-cp313-win_amd64.whl", hash = "sha256:a3db56f153bd4c5c2b619ab02c5db5192e222150ce5a1bc10f16164714bc39ac", size = 2266200, upload-time = "2025-09-29T21:12:20.14Z" }, + { url = "https://files.pythonhosted.org/packages/9a/83/752ca11c1aa9a899b793a130f2e466b79ea0cf7279c8d79c178fc954a07b/fonttools-4.60.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:a884aef09d45ba1206712c7dbda5829562d3fea7726935d3289d343232ecb0d3", size = 2822830, upload-time = "2025-09-29T21:12:24.406Z" }, + { url = "https://files.pythonhosted.org/packages/57/17/bbeab391100331950a96ce55cfbbff27d781c1b85ebafb4167eae50d9fe3/fonttools-4.60.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8a44788d9d91df72d1a5eac49b31aeb887a5f4aab761b4cffc4196c74907ea85", size = 2345524, upload-time = "2025-09-29T21:12:26.819Z" }, + { url = "https://files.pythonhosted.org/packages/3d/2e/d4831caa96d85a84dd0da1d9f90d81cec081f551e0ea216df684092c6c97/fonttools-4.60.1-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e852d9dda9f93ad3651ae1e3bb770eac544ec93c3807888798eccddf84596537", size = 4843490, upload-time = "2025-09-29T21:12:29.123Z" }, + { url = "https://files.pythonhosted.org/packages/49/13/5e2ea7c7a101b6fc3941be65307ef8df92cbbfa6ec4804032baf1893b434/fonttools-4.60.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:154cb6ee417e417bf5f7c42fe25858c9140c26f647c7347c06f0cc2d47eff003", size = 4944184, upload-time = "2025-09-29T21:12:31.414Z" }, + { url = "https://files.pythonhosted.org/packages/0c/2b/cf9603551c525b73fc47c52ee0b82a891579a93d9651ed694e4e2cd08bb8/fonttools-4.60.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5664fd1a9ea7f244487ac8f10340c4e37664675e8667d6fee420766e0fb3cf08", size = 4890218, upload-time = "2025-09-29T21:12:33.936Z" }, + { url = "https://files.pythonhosted.org/packages/fd/2f/933d2352422e25f2376aae74f79eaa882a50fb3bfef3c0d4f50501267101/fonttools-4.60.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:583b7f8e3c49486e4d489ad1deacfb8d5be54a8ef34d6df824f6a171f8511d99", size = 4999324, upload-time = "2025-09-29T21:12:36.637Z" }, + { url = "https://files.pythonhosted.org/packages/38/99/234594c0391221f66216bc2c886923513b3399a148defaccf81dc3be6560/fonttools-4.60.1-cp314-cp314-win32.whl", hash = "sha256:66929e2ea2810c6533a5184f938502cfdaea4bc3efb7130d8cc02e1c1b4108d6", size = 2220861, upload-time = "2025-09-29T21:12:39.108Z" }, + { url = "https://files.pythonhosted.org/packages/3e/1d/edb5b23726dde50fc4068e1493e4fc7658eeefcaf75d4c5ffce067d07ae5/fonttools-4.60.1-cp314-cp314-win_amd64.whl", hash = "sha256:f3d5be054c461d6a2268831f04091dc82753176f6ea06dc6047a5e168265a987", size = 2270934, upload-time = "2025-09-29T21:12:41.339Z" }, + { url = "https://files.pythonhosted.org/packages/fb/da/1392aaa2170adc7071fe7f9cfd181a5684a7afcde605aebddf1fb4d76df5/fonttools-4.60.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:b6379e7546ba4ae4b18f8ae2b9bc5960936007a1c0e30b342f662577e8bc3299", size = 2894340, upload-time = "2025-09-29T21:12:43.774Z" }, + { url = "https://files.pythonhosted.org/packages/bf/a7/3b9f16e010d536ce567058b931a20b590d8f3177b2eda09edd92e392375d/fonttools-4.60.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9d0ced62b59e0430b3690dbc5373df1c2aa7585e9a8ce38eff87f0fd993c5b01", size = 2375073, upload-time = "2025-09-29T21:12:46.437Z" }, + { url = "https://files.pythonhosted.org/packages/9b/b5/e9bcf51980f98e59bb5bb7c382a63c6f6cac0eec5f67de6d8f2322382065/fonttools-4.60.1-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:875cb7764708b3132637f6c5fb385b16eeba0f7ac9fa45a69d35e09b47045801", size = 4849758, upload-time = "2025-09-29T21:12:48.694Z" }, + { url = "https://files.pythonhosted.org/packages/e3/dc/1d2cf7d1cba82264b2f8385db3f5960e3d8ce756b4dc65b700d2c496f7e9/fonttools-4.60.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a184b2ea57b13680ab6d5fbde99ccef152c95c06746cb7718c583abd8f945ccc", size = 5085598, upload-time = "2025-09-29T21:12:51.081Z" }, + { url = "https://files.pythonhosted.org/packages/5d/4d/279e28ba87fb20e0c69baf72b60bbf1c4d873af1476806a7b5f2b7fac1ff/fonttools-4.60.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:026290e4ec76583881763fac284aca67365e0be9f13a7fb137257096114cb3bc", size = 4957603, upload-time = "2025-09-29T21:12:53.423Z" }, + { url = "https://files.pythonhosted.org/packages/78/d4/ff19976305e0c05aa3340c805475abb00224c954d3c65e82c0a69633d55d/fonttools-4.60.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f0e8817c7d1a0c2eedebf57ef9a9896f3ea23324769a9a2061a80fe8852705ed", size = 4974184, upload-time = "2025-09-29T21:12:55.962Z" }, + { url = "https://files.pythonhosted.org/packages/63/22/8553ff6166f5cd21cfaa115aaacaa0dc73b91c079a8cfd54a482cbc0f4f5/fonttools-4.60.1-cp314-cp314t-win32.whl", hash = "sha256:1410155d0e764a4615774e5c2c6fc516259fe3eca5882f034eb9bfdbee056259", size = 2282241, upload-time = "2025-09-29T21:12:58.179Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cb/fa7b4d148e11d5a72761a22e595344133e83a9507a4c231df972e657579b/fonttools-4.60.1-cp314-cp314t-win_amd64.whl", hash = "sha256:022beaea4b73a70295b688f817ddc24ed3e3418b5036ffcd5658141184ef0d0c", size = 2345760, upload-time = "2025-09-29T21:13:00.375Z" }, + { url = "https://files.pythonhosted.org/packages/c7/93/0dd45cd283c32dea1545151d8c3637b4b8c53cdb3a625aeb2885b184d74d/fonttools-4.60.1-py3-none-any.whl", hash = "sha256:906306ac7afe2156fcf0042173d6ebbb05416af70f6b370967b47f8f00103bbb", size = 1143175, upload-time = "2025-09-29T21:13:24.134Z" }, +] + [[package]] name = "fqdn" version = "1.5.1" @@ -1374,6 +1597,114 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/43/6a/ca128561b22b60bd5a0c4ea26649e68c8556b82bc70a0c396eebc977fe86/jupyterlab_widgets-3.0.15-py3-none-any.whl", hash = "sha256:d59023d7d7ef71400d51e6fee9a88867f6e65e10a4201605d2d7f3e8f012a31c", size = 216571, upload-time = "2025-05-05T12:32:29.534Z" }, ] +[[package]] +name = "kiwisolver" +version = "1.4.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564, upload-time = "2025-08-10T21:27:49.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/5d/8ce64e36d4e3aac5ca96996457dcf33e34e6051492399a3f1fec5657f30b/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b4d74bda2b8ebf4da5bd42af11d02d04428b2c32846e4c2c93219df8a7987b", size = 124159, upload-time = "2025-08-10T21:25:35.472Z" }, + { url = "https://files.pythonhosted.org/packages/96/1e/22f63ec454874378175a5f435d6ea1363dd33fb2af832c6643e4ccea0dc8/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fb3b8132019ea572f4611d770991000d7f58127560c4889729248eb5852a102f", size = 66578, upload-time = "2025-08-10T21:25:36.73Z" }, + { url = "https://files.pythonhosted.org/packages/41/4c/1925dcfff47a02d465121967b95151c82d11027d5ec5242771e580e731bd/kiwisolver-1.4.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84fd60810829c27ae375114cd379da1fa65e6918e1da405f356a775d49a62bcf", size = 65312, upload-time = "2025-08-10T21:25:37.658Z" }, + { url = "https://files.pythonhosted.org/packages/d4/42/0f333164e6307a0687d1eb9ad256215aae2f4bd5d28f4653d6cd319a3ba3/kiwisolver-1.4.9-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b78efa4c6e804ecdf727e580dbb9cba85624d2e1c6b5cb059c66290063bd99a9", size = 1628458, upload-time = "2025-08-10T21:25:39.067Z" }, + { url = "https://files.pythonhosted.org/packages/86/b6/2dccb977d651943995a90bfe3495c2ab2ba5cd77093d9f2318a20c9a6f59/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4efec7bcf21671db6a3294ff301d2fc861c31faa3c8740d1a94689234d1b415", size = 1225640, upload-time = "2025-08-10T21:25:40.489Z" }, + { url = "https://files.pythonhosted.org/packages/50/2b/362ebd3eec46c850ccf2bfe3e30f2fc4c008750011f38a850f088c56a1c6/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:90f47e70293fc3688b71271100a1a5453aa9944a81d27ff779c108372cf5567b", size = 1244074, upload-time = "2025-08-10T21:25:42.221Z" }, + { url = "https://files.pythonhosted.org/packages/6f/bb/f09a1e66dab8984773d13184a10a29fe67125337649d26bdef547024ed6b/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fdca1def57a2e88ef339de1737a1449d6dbf5fab184c54a1fca01d541317154", size = 1293036, upload-time = "2025-08-10T21:25:43.801Z" }, + { url = "https://files.pythonhosted.org/packages/ea/01/11ecf892f201cafda0f68fa59212edaea93e96c37884b747c181303fccd1/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9cf554f21be770f5111a1690d42313e140355e687e05cf82cb23d0a721a64a48", size = 2175310, upload-time = "2025-08-10T21:25:45.045Z" }, + { url = "https://files.pythonhosted.org/packages/7f/5f/bfe11d5b934f500cc004314819ea92427e6e5462706a498c1d4fc052e08f/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1795ac5cd0510207482c3d1d3ed781143383b8cfd36f5c645f3897ce066220", size = 2270943, upload-time = "2025-08-10T21:25:46.393Z" }, + { url = "https://files.pythonhosted.org/packages/3d/de/259f786bf71f1e03e73d87e2db1a9a3bcab64d7b4fd780167123161630ad/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ccd09f20ccdbbd341b21a67ab50a119b64a403b09288c27481575105283c1586", size = 2440488, upload-time = "2025-08-10T21:25:48.074Z" }, + { url = "https://files.pythonhosted.org/packages/1b/76/c989c278faf037c4d3421ec07a5c452cd3e09545d6dae7f87c15f54e4edf/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:540c7c72324d864406a009d72f5d6856f49693db95d1fbb46cf86febef873634", size = 2246787, upload-time = "2025-08-10T21:25:49.442Z" }, + { url = "https://files.pythonhosted.org/packages/a2/55/c2898d84ca440852e560ca9f2a0d28e6e931ac0849b896d77231929900e7/kiwisolver-1.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:ede8c6d533bc6601a47ad4046080d36b8fc99f81e6f1c17b0ac3c2dc91ac7611", size = 73730, upload-time = "2025-08-10T21:25:51.102Z" }, + { url = "https://files.pythonhosted.org/packages/e8/09/486d6ac523dd33b80b368247f238125d027964cfacb45c654841e88fb2ae/kiwisolver-1.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:7b4da0d01ac866a57dd61ac258c5607b4cd677f63abaec7b148354d2b2cdd536", size = 65036, upload-time = "2025-08-10T21:25:52.063Z" }, + { url = "https://files.pythonhosted.org/packages/6f/ab/c80b0d5a9d8a1a65f4f815f2afff9798b12c3b9f31f1d304dd233dd920e2/kiwisolver-1.4.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eb14a5da6dc7642b0f3a18f13654847cd8b7a2550e2645a5bda677862b03ba16", size = 124167, upload-time = "2025-08-10T21:25:53.403Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c0/27fe1a68a39cf62472a300e2879ffc13c0538546c359b86f149cc19f6ac3/kiwisolver-1.4.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:39a219e1c81ae3b103643d2aedb90f1ef22650deb266ff12a19e7773f3e5f089", size = 66579, upload-time = "2025-08-10T21:25:54.79Z" }, + { url = "https://files.pythonhosted.org/packages/31/a2/a12a503ac1fd4943c50f9822678e8015a790a13b5490354c68afb8489814/kiwisolver-1.4.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2405a7d98604b87f3fc28b1716783534b1b4b8510d8142adca34ee0bc3c87543", size = 65309, upload-time = "2025-08-10T21:25:55.76Z" }, + { url = "https://files.pythonhosted.org/packages/66/e1/e533435c0be77c3f64040d68d7a657771194a63c279f55573188161e81ca/kiwisolver-1.4.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dc1ae486f9abcef254b5618dfb4113dd49f94c68e3e027d03cf0143f3f772b61", size = 1435596, upload-time = "2025-08-10T21:25:56.861Z" }, + { url = "https://files.pythonhosted.org/packages/67/1e/51b73c7347f9aabdc7215aa79e8b15299097dc2f8e67dee2b095faca9cb0/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a1f570ce4d62d718dce3f179ee78dac3b545ac16c0c04bb363b7607a949c0d1", size = 1246548, upload-time = "2025-08-10T21:25:58.246Z" }, + { url = "https://files.pythonhosted.org/packages/21/aa/72a1c5d1e430294f2d32adb9542719cfb441b5da368d09d268c7757af46c/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb27e7b78d716c591e88e0a09a2139c6577865d7f2e152488c2cc6257f460872", size = 1263618, upload-time = "2025-08-10T21:25:59.857Z" }, + { url = "https://files.pythonhosted.org/packages/a3/af/db1509a9e79dbf4c260ce0cfa3903ea8945f6240e9e59d1e4deb731b1a40/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:15163165efc2f627eb9687ea5f3a28137217d217ac4024893d753f46bce9de26", size = 1317437, upload-time = "2025-08-10T21:26:01.105Z" }, + { url = "https://files.pythonhosted.org/packages/e0/f2/3ea5ee5d52abacdd12013a94130436e19969fa183faa1e7c7fbc89e9a42f/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bdee92c56a71d2b24c33a7d4c2856bd6419d017e08caa7802d2963870e315028", size = 2195742, upload-time = "2025-08-10T21:26:02.675Z" }, + { url = "https://files.pythonhosted.org/packages/6f/9b/1efdd3013c2d9a2566aa6a337e9923a00590c516add9a1e89a768a3eb2fc/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:412f287c55a6f54b0650bd9b6dce5aceddb95864a1a90c87af16979d37c89771", size = 2290810, upload-time = "2025-08-10T21:26:04.009Z" }, + { url = "https://files.pythonhosted.org/packages/fb/e5/cfdc36109ae4e67361f9bc5b41323648cb24a01b9ade18784657e022e65f/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2c93f00dcba2eea70af2be5f11a830a742fe6b579a1d4e00f47760ef13be247a", size = 2461579, upload-time = "2025-08-10T21:26:05.317Z" }, + { url = "https://files.pythonhosted.org/packages/62/86/b589e5e86c7610842213994cdea5add00960076bef4ae290c5fa68589cac/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f117e1a089d9411663a3207ba874f31be9ac8eaa5b533787024dc07aeb74f464", size = 2268071, upload-time = "2025-08-10T21:26:06.686Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c6/f8df8509fd1eee6c622febe54384a96cfaf4d43bf2ccec7a0cc17e4715c9/kiwisolver-1.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:be6a04e6c79819c9a8c2373317d19a96048e5a3f90bec587787e86a1153883c2", size = 73840, upload-time = "2025-08-10T21:26:07.94Z" }, + { url = "https://files.pythonhosted.org/packages/e2/2d/16e0581daafd147bc11ac53f032a2b45eabac897f42a338d0a13c1e5c436/kiwisolver-1.4.9-cp311-cp311-win_arm64.whl", hash = "sha256:0ae37737256ba2de764ddc12aed4956460277f00c4996d51a197e72f62f5eec7", size = 65159, upload-time = "2025-08-10T21:26:09.048Z" }, + { url = "https://files.pythonhosted.org/packages/86/c9/13573a747838aeb1c76e3267620daa054f4152444d1f3d1a2324b78255b5/kiwisolver-1.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ac5a486ac389dddcc5bef4f365b6ae3ffff2c433324fb38dd35e3fab7c957999", size = 123686, upload-time = "2025-08-10T21:26:10.034Z" }, + { url = "https://files.pythonhosted.org/packages/51/ea/2ecf727927f103ffd1739271ca19c424d0e65ea473fbaeea1c014aea93f6/kiwisolver-1.4.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2ba92255faa7309d06fe44c3a4a97efe1c8d640c2a79a5ef728b685762a6fd2", size = 66460, upload-time = "2025-08-10T21:26:11.083Z" }, + { url = "https://files.pythonhosted.org/packages/5b/5a/51f5464373ce2aeb5194508298a508b6f21d3867f499556263c64c621914/kiwisolver-1.4.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a2899935e724dd1074cb568ce7ac0dce28b2cd6ab539c8e001a8578eb106d14", size = 64952, upload-time = "2025-08-10T21:26:12.058Z" }, + { url = "https://files.pythonhosted.org/packages/70/90/6d240beb0f24b74371762873e9b7f499f1e02166a2d9c5801f4dbf8fa12e/kiwisolver-1.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f6008a4919fdbc0b0097089f67a1eb55d950ed7e90ce2cc3e640abadd2757a04", size = 1474756, upload-time = "2025-08-10T21:26:13.096Z" }, + { url = "https://files.pythonhosted.org/packages/12/42/f36816eaf465220f683fb711efdd1bbf7a7005a2473d0e4ed421389bd26c/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:67bb8b474b4181770f926f7b7d2f8c0248cbcb78b660fdd41a47054b28d2a752", size = 1276404, upload-time = "2025-08-10T21:26:14.457Z" }, + { url = "https://files.pythonhosted.org/packages/2e/64/bc2de94800adc830c476dce44e9b40fd0809cddeef1fde9fcf0f73da301f/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2327a4a30d3ee07d2fbe2e7933e8a37c591663b96ce42a00bc67461a87d7df77", size = 1294410, upload-time = "2025-08-10T21:26:15.73Z" }, + { url = "https://files.pythonhosted.org/packages/5f/42/2dc82330a70aa8e55b6d395b11018045e58d0bb00834502bf11509f79091/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a08b491ec91b1d5053ac177afe5290adacf1f0f6307d771ccac5de30592d198", size = 1343631, upload-time = "2025-08-10T21:26:17.045Z" }, + { url = "https://files.pythonhosted.org/packages/22/fd/f4c67a6ed1aab149ec5a8a401c323cee7a1cbe364381bb6c9c0d564e0e20/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8fc5c867c22b828001b6a38d2eaeb88160bf5783c6cb4a5e440efc981ce286d", size = 2224963, upload-time = "2025-08-10T21:26:18.737Z" }, + { url = "https://files.pythonhosted.org/packages/45/aa/76720bd4cb3713314677d9ec94dcc21ced3f1baf4830adde5bb9b2430a5f/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3b3115b2581ea35bb6d1f24a4c90af37e5d9b49dcff267eeed14c3893c5b86ab", size = 2321295, upload-time = "2025-08-10T21:26:20.11Z" }, + { url = "https://files.pythonhosted.org/packages/80/19/d3ec0d9ab711242f56ae0dc2fc5d70e298bb4a1f9dfab44c027668c673a1/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858e4c22fb075920b96a291928cb7dea5644e94c0ee4fcd5af7e865655e4ccf2", size = 2487987, upload-time = "2025-08-10T21:26:21.49Z" }, + { url = "https://files.pythonhosted.org/packages/39/e9/61e4813b2c97e86b6fdbd4dd824bf72d28bcd8d4849b8084a357bc0dd64d/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ed0fecd28cc62c54b262e3736f8bb2512d8dcfdc2bcf08be5f47f96bf405b145", size = 2291817, upload-time = "2025-08-10T21:26:22.812Z" }, + { url = "https://files.pythonhosted.org/packages/a0/41/85d82b0291db7504da3c2defe35c9a8a5c9803a730f297bd823d11d5fb77/kiwisolver-1.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:f68208a520c3d86ea51acf688a3e3002615a7f0238002cccc17affecc86a8a54", size = 73895, upload-time = "2025-08-10T21:26:24.37Z" }, + { url = "https://files.pythonhosted.org/packages/e2/92/5f3068cf15ee5cb624a0c7596e67e2a0bb2adee33f71c379054a491d07da/kiwisolver-1.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:2c1a4f57df73965f3f14df20b80ee29e6a7930a57d2d9e8491a25f676e197c60", size = 64992, upload-time = "2025-08-10T21:26:25.732Z" }, + { url = "https://files.pythonhosted.org/packages/31/c1/c2686cda909742ab66c7388e9a1a8521a59eb89f8bcfbee28fc980d07e24/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5d0432ccf1c7ab14f9949eec60c5d1f924f17c037e9f8b33352fa05799359b8", size = 123681, upload-time = "2025-08-10T21:26:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/ca/f0/f44f50c9f5b1a1860261092e3bc91ecdc9acda848a8b8c6abfda4a24dd5c/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efb3a45b35622bb6c16dbfab491a8f5a391fe0e9d45ef32f4df85658232ca0e2", size = 66464, upload-time = "2025-08-10T21:26:27.733Z" }, + { url = "https://files.pythonhosted.org/packages/2d/7a/9d90a151f558e29c3936b8a47ac770235f436f2120aca41a6d5f3d62ae8d/kiwisolver-1.4.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a12cf6398e8a0a001a059747a1cbf24705e18fe413bc22de7b3d15c67cffe3f", size = 64961, upload-time = "2025-08-10T21:26:28.729Z" }, + { url = "https://files.pythonhosted.org/packages/e9/e9/f218a2cb3a9ffbe324ca29a9e399fa2d2866d7f348ec3a88df87fc248fc5/kiwisolver-1.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b67e6efbf68e077dd71d1a6b37e43e1a99d0bff1a3d51867d45ee8908b931098", size = 1474607, upload-time = "2025-08-10T21:26:29.798Z" }, + { url = "https://files.pythonhosted.org/packages/d9/28/aac26d4c882f14de59041636292bc838db8961373825df23b8eeb807e198/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5656aa670507437af0207645273ccdfee4f14bacd7f7c67a4306d0dcaeaf6eed", size = 1276546, upload-time = "2025-08-10T21:26:31.401Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ad/8bfc1c93d4cc565e5069162f610ba2f48ff39b7de4b5b8d93f69f30c4bed/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bfc08add558155345129c7803b3671cf195e6a56e7a12f3dde7c57d9b417f525", size = 1294482, upload-time = "2025-08-10T21:26:32.721Z" }, + { url = "https://files.pythonhosted.org/packages/da/f1/6aca55ff798901d8ce403206d00e033191f63d82dd708a186e0ed2067e9c/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:40092754720b174e6ccf9e845d0d8c7d8e12c3d71e7fc35f55f3813e96376f78", size = 1343720, upload-time = "2025-08-10T21:26:34.032Z" }, + { url = "https://files.pythonhosted.org/packages/d1/91/eed031876c595c81d90d0f6fc681ece250e14bf6998c3d7c419466b523b7/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:497d05f29a1300d14e02e6441cf0f5ee81c1ff5a304b0d9fb77423974684e08b", size = 2224907, upload-time = "2025-08-10T21:26:35.824Z" }, + { url = "https://files.pythonhosted.org/packages/e9/ec/4d1925f2e49617b9cca9c34bfa11adefad49d00db038e692a559454dfb2e/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdd1a81a1860476eb41ac4bc1e07b3f07259e6d55bbf739b79c8aaedcf512799", size = 2321334, upload-time = "2025-08-10T21:26:37.534Z" }, + { url = "https://files.pythonhosted.org/packages/43/cb/450cd4499356f68802750c6ddc18647b8ea01ffa28f50d20598e0befe6e9/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e6b93f13371d341afee3be9f7c5964e3fe61d5fa30f6a30eb49856935dfe4fc3", size = 2488313, upload-time = "2025-08-10T21:26:39.191Z" }, + { url = "https://files.pythonhosted.org/packages/71/67/fc76242bd99f885651128a5d4fa6083e5524694b7c88b489b1b55fdc491d/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d75aa530ccfaa593da12834b86a0724f58bff12706659baa9227c2ccaa06264c", size = 2291970, upload-time = "2025-08-10T21:26:40.828Z" }, + { url = "https://files.pythonhosted.org/packages/75/bd/f1a5d894000941739f2ae1b65a32892349423ad49c2e6d0771d0bad3fae4/kiwisolver-1.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:dd0a578400839256df88c16abddf9ba14813ec5f21362e1fe65022e00c883d4d", size = 73894, upload-time = "2025-08-10T21:26:42.33Z" }, + { url = "https://files.pythonhosted.org/packages/95/38/dce480814d25b99a391abbddadc78f7c117c6da34be68ca8b02d5848b424/kiwisolver-1.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:d4188e73af84ca82468f09cadc5ac4db578109e52acb4518d8154698d3a87ca2", size = 64995, upload-time = "2025-08-10T21:26:43.889Z" }, + { url = "https://files.pythonhosted.org/packages/e2/37/7d218ce5d92dadc5ebdd9070d903e0c7cf7edfe03f179433ac4d13ce659c/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:5a0f2724dfd4e3b3ac5a82436a8e6fd16baa7d507117e4279b660fe8ca38a3a1", size = 126510, upload-time = "2025-08-10T21:26:44.915Z" }, + { url = "https://files.pythonhosted.org/packages/23/b0/e85a2b48233daef4b648fb657ebbb6f8367696a2d9548a00b4ee0eb67803/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1b11d6a633e4ed84fc0ddafd4ebfd8ea49b3f25082c04ad12b8315c11d504dc1", size = 67903, upload-time = "2025-08-10T21:26:45.934Z" }, + { url = "https://files.pythonhosted.org/packages/44/98/f2425bc0113ad7de24da6bb4dae1343476e95e1d738be7c04d31a5d037fd/kiwisolver-1.4.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61874cdb0a36016354853593cffc38e56fc9ca5aa97d2c05d3dcf6922cd55a11", size = 66402, upload-time = "2025-08-10T21:26:47.101Z" }, + { url = "https://files.pythonhosted.org/packages/98/d8/594657886df9f34c4177cc353cc28ca7e6e5eb562d37ccc233bff43bbe2a/kiwisolver-1.4.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:60c439763a969a6af93b4881db0eed8fadf93ee98e18cbc35bc8da868d0c4f0c", size = 1582135, upload-time = "2025-08-10T21:26:48.665Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c6/38a115b7170f8b306fc929e166340c24958347308ea3012c2b44e7e295db/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92a2f997387a1b79a75e7803aa7ded2cfbe2823852ccf1ba3bcf613b62ae3197", size = 1389409, upload-time = "2025-08-10T21:26:50.335Z" }, + { url = "https://files.pythonhosted.org/packages/bf/3b/e04883dace81f24a568bcee6eb3001da4ba05114afa622ec9b6fafdc1f5e/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31d512c812daea6d8b3be3b2bfcbeb091dbb09177706569bcfc6240dcf8b41c", size = 1401763, upload-time = "2025-08-10T21:26:51.867Z" }, + { url = "https://files.pythonhosted.org/packages/9f/80/20ace48e33408947af49d7d15c341eaee69e4e0304aab4b7660e234d6288/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:52a15b0f35dad39862d376df10c5230155243a2c1a436e39eb55623ccbd68185", size = 1453643, upload-time = "2025-08-10T21:26:53.592Z" }, + { url = "https://files.pythonhosted.org/packages/64/31/6ce4380a4cd1f515bdda976a1e90e547ccd47b67a1546d63884463c92ca9/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a30fd6fdef1430fd9e1ba7b3398b5ee4e2887783917a687d86ba69985fb08748", size = 2330818, upload-time = "2025-08-10T21:26:55.051Z" }, + { url = "https://files.pythonhosted.org/packages/fa/e9/3f3fcba3bcc7432c795b82646306e822f3fd74df0ee81f0fa067a1f95668/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cc9617b46837c6468197b5945e196ee9ca43057bb7d9d1ae688101e4e1dddf64", size = 2419963, upload-time = "2025-08-10T21:26:56.421Z" }, + { url = "https://files.pythonhosted.org/packages/99/43/7320c50e4133575c66e9f7dadead35ab22d7c012a3b09bb35647792b2a6d/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:0ab74e19f6a2b027ea4f845a78827969af45ce790e6cb3e1ebab71bdf9f215ff", size = 2594639, upload-time = "2025-08-10T21:26:57.882Z" }, + { url = "https://files.pythonhosted.org/packages/65/d6/17ae4a270d4a987ef8a385b906d2bdfc9fce502d6dc0d3aea865b47f548c/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dba5ee5d3981160c28d5490f0d1b7ed730c22470ff7f6cc26cfcfaacb9896a07", size = 2391741, upload-time = "2025-08-10T21:26:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/2a/8f/8f6f491d595a9e5912971f3f863d81baddccc8a4d0c3749d6a0dd9ffc9df/kiwisolver-1.4.9-cp313-cp313t-win_arm64.whl", hash = "sha256:0749fd8f4218ad2e851e11cc4dc05c7cbc0cbc4267bdfdb31782e65aace4ee9c", size = 68646, upload-time = "2025-08-10T21:27:00.52Z" }, + { url = "https://files.pythonhosted.org/packages/6b/32/6cc0fbc9c54d06c2969faa9c1d29f5751a2e51809dd55c69055e62d9b426/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9928fe1eb816d11ae170885a74d074f57af3a0d65777ca47e9aeb854a1fba386", size = 123806, upload-time = "2025-08-10T21:27:01.537Z" }, + { url = "https://files.pythonhosted.org/packages/b2/dd/2bfb1d4a4823d92e8cbb420fe024b8d2167f72079b3bb941207c42570bdf/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d0005b053977e7b43388ddec89fa567f43d4f6d5c2c0affe57de5ebf290dc552", size = 66605, upload-time = "2025-08-10T21:27:03.335Z" }, + { url = "https://files.pythonhosted.org/packages/f7/69/00aafdb4e4509c2ca6064646cba9cd4b37933898f426756adb2cb92ebbed/kiwisolver-1.4.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2635d352d67458b66fd0667c14cb1d4145e9560d503219034a18a87e971ce4f3", size = 64925, upload-time = "2025-08-10T21:27:04.339Z" }, + { url = "https://files.pythonhosted.org/packages/43/dc/51acc6791aa14e5cb6d8a2e28cefb0dc2886d8862795449d021334c0df20/kiwisolver-1.4.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:767c23ad1c58c9e827b649a9ab7809fd5fd9db266a9cf02b0e926ddc2c680d58", size = 1472414, upload-time = "2025-08-10T21:27:05.437Z" }, + { url = "https://files.pythonhosted.org/packages/3d/bb/93fa64a81db304ac8a246f834d5094fae4b13baf53c839d6bb6e81177129/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72d0eb9fba308b8311685c2268cf7d0a0639a6cd027d8128659f72bdd8a024b4", size = 1281272, upload-time = "2025-08-10T21:27:07.063Z" }, + { url = "https://files.pythonhosted.org/packages/70/e6/6df102916960fb8d05069d4bd92d6d9a8202d5a3e2444494e7cd50f65b7a/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f68e4f3eeca8fb22cc3d731f9715a13b652795ef657a13df1ad0c7dc0e9731df", size = 1298578, upload-time = "2025-08-10T21:27:08.452Z" }, + { url = "https://files.pythonhosted.org/packages/7c/47/e142aaa612f5343736b087864dbaebc53ea8831453fb47e7521fa8658f30/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d84cd4061ae292d8ac367b2c3fa3aad11cb8625a95d135fe93f286f914f3f5a6", size = 1345607, upload-time = "2025-08-10T21:27:10.125Z" }, + { url = "https://files.pythonhosted.org/packages/54/89/d641a746194a0f4d1a3670fb900d0dbaa786fb98341056814bc3f058fa52/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a60ea74330b91bd22a29638940d115df9dc00af5035a9a2a6ad9399ffb4ceca5", size = 2230150, upload-time = "2025-08-10T21:27:11.484Z" }, + { url = "https://files.pythonhosted.org/packages/aa/6b/5ee1207198febdf16ac11f78c5ae40861b809cbe0e6d2a8d5b0b3044b199/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ce6a3a4e106cf35c2d9c4fa17c05ce0b180db622736845d4315519397a77beaf", size = 2325979, upload-time = "2025-08-10T21:27:12.917Z" }, + { url = "https://files.pythonhosted.org/packages/fc/ff/b269eefd90f4ae14dcc74973d5a0f6d28d3b9bb1afd8c0340513afe6b39a/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:77937e5e2a38a7b48eef0585114fe7930346993a88060d0bf886086d2aa49ef5", size = 2491456, upload-time = "2025-08-10T21:27:14.353Z" }, + { url = "https://files.pythonhosted.org/packages/fc/d4/10303190bd4d30de547534601e259a4fbf014eed94aae3e5521129215086/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:24c175051354f4a28c5d6a31c93906dc653e2bf234e8a4bbfb964892078898ce", size = 2294621, upload-time = "2025-08-10T21:27:15.808Z" }, + { url = "https://files.pythonhosted.org/packages/28/e0/a9a90416fce5c0be25742729c2ea52105d62eda6c4be4d803c2a7be1fa50/kiwisolver-1.4.9-cp314-cp314-win_amd64.whl", hash = "sha256:0763515d4df10edf6d06a3c19734e2566368980d21ebec439f33f9eb936c07b7", size = 75417, upload-time = "2025-08-10T21:27:17.436Z" }, + { url = "https://files.pythonhosted.org/packages/1f/10/6949958215b7a9a264299a7db195564e87900f709db9245e4ebdd3c70779/kiwisolver-1.4.9-cp314-cp314-win_arm64.whl", hash = "sha256:0e4e2bf29574a6a7b7f6cb5fa69293b9f96c928949ac4a53ba3f525dffb87f9c", size = 66582, upload-time = "2025-08-10T21:27:18.436Z" }, + { url = "https://files.pythonhosted.org/packages/ec/79/60e53067903d3bc5469b369fe0dfc6b3482e2133e85dae9daa9527535991/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d976bbb382b202f71c67f77b0ac11244021cfa3f7dfd9e562eefcea2df711548", size = 126514, upload-time = "2025-08-10T21:27:19.465Z" }, + { url = "https://files.pythonhosted.org/packages/25/d1/4843d3e8d46b072c12a38c97c57fab4608d36e13fe47d47ee96b4d61ba6f/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2489e4e5d7ef9a1c300a5e0196e43d9c739f066ef23270607d45aba368b91f2d", size = 67905, upload-time = "2025-08-10T21:27:20.51Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ae/29ffcbd239aea8b93108de1278271ae764dfc0d803a5693914975f200596/kiwisolver-1.4.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e2ea9f7ab7fbf18fffb1b5434ce7c69a07582f7acc7717720f1d69f3e806f90c", size = 66399, upload-time = "2025-08-10T21:27:21.496Z" }, + { url = "https://files.pythonhosted.org/packages/a1/ae/d7ba902aa604152c2ceba5d352d7b62106bedbccc8e95c3934d94472bfa3/kiwisolver-1.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b34e51affded8faee0dfdb705416153819d8ea9250bbbf7ea1b249bdeb5f1122", size = 1582197, upload-time = "2025-08-10T21:27:22.604Z" }, + { url = "https://files.pythonhosted.org/packages/f2/41/27c70d427eddb8bc7e4f16420a20fefc6f480312122a59a959fdfe0445ad/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8aacd3d4b33b772542b2e01beb50187536967b514b00003bdda7589722d2a64", size = 1390125, upload-time = "2025-08-10T21:27:24.036Z" }, + { url = "https://files.pythonhosted.org/packages/41/42/b3799a12bafc76d962ad69083f8b43b12bf4fe78b097b12e105d75c9b8f1/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7cf974dd4e35fa315563ac99d6287a1024e4dc2077b8a7d7cd3d2fb65d283134", size = 1402612, upload-time = "2025-08-10T21:27:25.773Z" }, + { url = "https://files.pythonhosted.org/packages/d2/b5/a210ea073ea1cfaca1bb5c55a62307d8252f531beb364e18aa1e0888b5a0/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:85bd218b5ecfbee8c8a82e121802dcb519a86044c9c3b2e4aef02fa05c6da370", size = 1453990, upload-time = "2025-08-10T21:27:27.089Z" }, + { url = "https://files.pythonhosted.org/packages/5f/ce/a829eb8c033e977d7ea03ed32fb3c1781b4fa0433fbadfff29e39c676f32/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0856e241c2d3df4efef7c04a1e46b1936b6120c9bcf36dd216e3acd84bc4fb21", size = 2331601, upload-time = "2025-08-10T21:27:29.343Z" }, + { url = "https://files.pythonhosted.org/packages/e0/4b/b5e97eb142eb9cd0072dacfcdcd31b1c66dc7352b0f7c7255d339c0edf00/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9af39d6551f97d31a4deebeac6f45b156f9755ddc59c07b402c148f5dbb6482a", size = 2422041, upload-time = "2025-08-10T21:27:30.754Z" }, + { url = "https://files.pythonhosted.org/packages/40/be/8eb4cd53e1b85ba4edc3a9321666f12b83113a178845593307a3e7891f44/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:bb4ae2b57fc1d8cbd1cf7b1d9913803681ffa903e7488012be5b76dedf49297f", size = 2594897, upload-time = "2025-08-10T21:27:32.803Z" }, + { url = "https://files.pythonhosted.org/packages/99/dd/841e9a66c4715477ea0abc78da039832fbb09dac5c35c58dc4c41a407b8a/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:aedff62918805fb62d43a4aa2ecd4482c380dc76cd31bd7c8878588a61bd0369", size = 2391835, upload-time = "2025-08-10T21:27:34.23Z" }, + { url = "https://files.pythonhosted.org/packages/0c/28/4b2e5c47a0da96896fdfdb006340ade064afa1e63675d01ea5ac222b6d52/kiwisolver-1.4.9-cp314-cp314t-win_amd64.whl", hash = "sha256:1fa333e8b2ce4d9660f2cda9c0e1b6bafcfb2457a9d259faa82289e73ec24891", size = 79988, upload-time = "2025-08-10T21:27:35.587Z" }, + { url = "https://files.pythonhosted.org/packages/80/be/3578e8afd18c88cdf9cb4cffde75a96d2be38c5a903f1ed0ceec061bd09e/kiwisolver-1.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:4a48a2ce79d65d363597ef7b567ce3d14d68783d2b2263d98db3d9477805ba32", size = 70260, upload-time = "2025-08-10T21:27:36.606Z" }, + { url = "https://files.pythonhosted.org/packages/a2/63/fde392691690f55b38d5dd7b3710f5353bf7a8e52de93a22968801ab8978/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4d1d9e582ad4d63062d34077a9a1e9f3c34088a2ec5135b1f7190c07cf366527", size = 60183, upload-time = "2025-08-10T21:27:37.669Z" }, + { url = "https://files.pythonhosted.org/packages/27/b1/6aad34edfdb7cced27f371866f211332bba215bfd918ad3322a58f480d8b/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:deed0c7258ceb4c44ad5ec7d9918f9f14fd05b2be86378d86cf50e63d1e7b771", size = 58675, upload-time = "2025-08-10T21:27:39.031Z" }, + { url = "https://files.pythonhosted.org/packages/9d/1a/23d855a702bb35a76faed5ae2ba3de57d323f48b1f6b17ee2176c4849463/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a590506f303f512dff6b7f75fd2fd18e16943efee932008fe7140e5fa91d80e", size = 80277, upload-time = "2025-08-10T21:27:40.129Z" }, + { url = "https://files.pythonhosted.org/packages/5a/5b/5239e3c2b8fb5afa1e8508f721bb77325f740ab6994d963e61b2b7abcc1e/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e09c2279a4d01f099f52d5c4b3d9e208e91edcbd1a175c9662a8b16e000fece9", size = 77994, upload-time = "2025-08-10T21:27:41.181Z" }, + { url = "https://files.pythonhosted.org/packages/f9/1c/5d4d468fb16f8410e596ed0eac02d2c68752aa7dc92997fe9d60a7147665/kiwisolver-1.4.9-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c9e7cdf45d594ee04d5be1b24dd9d49f3d1590959b2271fb30b5ca2b262c00fb", size = 73744, upload-time = "2025-08-10T21:27:42.254Z" }, + { url = "https://files.pythonhosted.org/packages/a3/0f/36d89194b5a32c054ce93e586d4049b6c2c22887b0eb229c61c68afd3078/kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:720e05574713db64c356e86732c0f3c5252818d05f9df320f0ad8380641acea5", size = 60104, upload-time = "2025-08-10T21:27:43.287Z" }, + { url = "https://files.pythonhosted.org/packages/52/ba/4ed75f59e4658fd21fe7dde1fee0ac397c678ec3befba3fe6482d987af87/kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:17680d737d5335b552994a2008fab4c851bcd7de33094a82067ef3a576ff02fa", size = 58592, upload-time = "2025-08-10T21:27:44.314Z" }, + { url = "https://files.pythonhosted.org/packages/33/01/a8ea7c5ea32a9b45ceeaee051a04c8ed4320f5add3c51bfa20879b765b70/kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:85b5352f94e490c028926ea567fc569c52ec79ce131dadb968d3853e809518c2", size = 80281, upload-time = "2025-08-10T21:27:45.369Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/dbd2ecdce306f1d07a1aaf324817ee993aab7aee9db47ceac757deabafbe/kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:464415881e4801295659462c49461a24fb107c140de781d55518c4b80cb6790f", size = 78009, upload-time = "2025-08-10T21:27:46.376Z" }, + { url = "https://files.pythonhosted.org/packages/da/e9/0d4add7873a73e462aeb45c036a2dead2562b825aa46ba326727b3f31016/kiwisolver-1.4.9-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:fb940820c63a9590d31d88b815e7a3aa5915cad3ce735ab45f0c730b39547de1", size = 73929, upload-time = "2025-08-10T21:27:48.236Z" }, +] + [[package]] name = "lark" version = "1.3.0" @@ -1419,6 +1750,8 @@ dependencies = [ { name = "hf-proxy" }, { name = "ipykernel" }, { name = "llm" }, + { name = "matplotlib" }, + { name = "torch" }, { name = "tqdm" }, ] @@ -1426,6 +1759,7 @@ dependencies = [ dev = [ { name = "black" }, { name = "jupyter" }, + { name = "matplotlib" }, { name = "mypy" }, { name = "pytest" }, { name = "ruff" }, @@ -1443,11 +1777,14 @@ requires-dist = [ { name = "ipykernel" }, { name = "jupyter", marker = "extra == 'dev'", specifier = ">=1.0.0" }, { name = "llm", editable = "llm" }, + { name = "matplotlib" }, + { name = "matplotlib", marker = "extra == 'dev'", specifier = ">=1.0.0" }, { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.8.0" }, { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0.0" }, { name = "pytest", marker = "extra == 'test'", specifier = ">=8.0.0" }, { name = "pytest-cov", marker = "extra == 'test'", specifier = ">=4.1.0" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.3.0" }, + { name = "torch", specifier = "==2.8.0" }, { name = "tqdm", specifier = ">=4,<5" }, ] provides-extras = ["dev", "test"] @@ -1537,6 +1874,81 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, ] +[[package]] +name = "matplotlib" +version = "3.10.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy", version = "1.3.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "contourpy", version = "1.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a0/59/c3e6453a9676ffba145309a73c462bb407f4400de7de3f2b41af70720a3c/matplotlib-3.10.6.tar.gz", hash = "sha256:ec01b645840dd1996df21ee37f208cd8ba57644779fa20464010638013d3203c", size = 34804264, upload-time = "2025-08-30T00:14:25.137Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/dc/ab89f7a5efd0cbaaebf2c3cf1881f4cba20c8925bb43f64511059df76895/matplotlib-3.10.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:bc7316c306d97463a9866b89d5cc217824e799fa0de346c8f68f4f3d27c8693d", size = 8247159, upload-time = "2025-08-30T00:12:30.507Z" }, + { url = "https://files.pythonhosted.org/packages/30/a5/ddaee1a383ab28174093644fff7438eddb87bf8dbd58f7b85f5cdd6b2485/matplotlib-3.10.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d00932b0d160ef03f59f9c0e16d1e3ac89646f7785165ce6ad40c842db16cc2e", size = 8108011, upload-time = "2025-08-30T00:12:32.771Z" }, + { url = "https://files.pythonhosted.org/packages/75/5b/a53f69bb0522db352b1135bb57cd9fe00fd7252072409392d991d3a755d0/matplotlib-3.10.6-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8fa4c43d6bfdbfec09c733bca8667de11bfa4970e8324c471f3a3632a0301c15", size = 8680518, upload-time = "2025-08-30T00:12:34.387Z" }, + { url = "https://files.pythonhosted.org/packages/5f/31/e059ddce95f68819b005a2d6820b2d6ed0307827a04598891f00649bed2d/matplotlib-3.10.6-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ea117a9c1627acaa04dbf36265691921b999cbf515a015298e54e1a12c3af837", size = 9514997, upload-time = "2025-08-30T00:12:36.272Z" }, + { url = "https://files.pythonhosted.org/packages/66/d5/28b408a7c0f07b41577ee27e4454fe329e78ca21fe46ae7a27d279165fb5/matplotlib-3.10.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08fc803293b4e1694ee325896030de97f74c141ccff0be886bb5915269247676", size = 9566440, upload-time = "2025-08-30T00:12:41.675Z" }, + { url = "https://files.pythonhosted.org/packages/2d/99/8325b3386b479b1d182ab1a7fd588fd393ff00a99dc04b7cf7d06668cf0f/matplotlib-3.10.6-cp310-cp310-win_amd64.whl", hash = "sha256:2adf92d9b7527fbfb8818e050260f0ebaa460f79d61546374ce73506c9421d09", size = 8108186, upload-time = "2025-08-30T00:12:43.621Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/5d3665aa44c49005aaacaa68ddea6fcb27345961cd538a98bb0177934ede/matplotlib-3.10.6-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:905b60d1cb0ee604ce65b297b61cf8be9f4e6cfecf95a3fe1c388b5266bc8f4f", size = 8257527, upload-time = "2025-08-30T00:12:45.31Z" }, + { url = "https://files.pythonhosted.org/packages/8c/af/30ddefe19ca67eebd70047dabf50f899eaff6f3c5e6a1a7edaecaf63f794/matplotlib-3.10.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7bac38d816637343e53d7185d0c66677ff30ffb131044a81898b5792c956ba76", size = 8119583, upload-time = "2025-08-30T00:12:47.236Z" }, + { url = "https://files.pythonhosted.org/packages/d3/29/4a8650a3dcae97fa4f375d46efcb25920d67b512186f8a6788b896062a81/matplotlib-3.10.6-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:942a8de2b5bfff1de31d95722f702e2966b8a7e31f4e68f7cd963c7cd8861cf6", size = 8692682, upload-time = "2025-08-30T00:12:48.781Z" }, + { url = "https://files.pythonhosted.org/packages/aa/d3/b793b9cb061cfd5d42ff0f69d1822f8d5dbc94e004618e48a97a8373179a/matplotlib-3.10.6-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a3276c85370bc0dfca051ec65c5817d1e0f8f5ce1b7787528ec8ed2d524bbc2f", size = 9521065, upload-time = "2025-08-30T00:12:50.602Z" }, + { url = "https://files.pythonhosted.org/packages/f7/c5/53de5629f223c1c66668d46ac2621961970d21916a4bc3862b174eb2a88f/matplotlib-3.10.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9df5851b219225731f564e4b9e7f2ac1e13c9e6481f941b5631a0f8e2d9387ce", size = 9576888, upload-time = "2025-08-30T00:12:52.92Z" }, + { url = "https://files.pythonhosted.org/packages/fc/8e/0a18d6d7d2d0a2e66585032a760d13662e5250c784d53ad50434e9560991/matplotlib-3.10.6-cp311-cp311-win_amd64.whl", hash = "sha256:abb5d9478625dd9c9eb51a06d39aae71eda749ae9b3138afb23eb38824026c7e", size = 8115158, upload-time = "2025-08-30T00:12:54.863Z" }, + { url = "https://files.pythonhosted.org/packages/07/b3/1a5107bb66c261e23b9338070702597a2d374e5aa7004b7adfc754fbed02/matplotlib-3.10.6-cp311-cp311-win_arm64.whl", hash = "sha256:886f989ccfae63659183173bb3fced7fd65e9eb793c3cc21c273add368536951", size = 7992444, upload-time = "2025-08-30T00:12:57.067Z" }, + { url = "https://files.pythonhosted.org/packages/ea/1a/7042f7430055d567cc3257ac409fcf608599ab27459457f13772c2d9778b/matplotlib-3.10.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:31ca662df6a80bd426f871105fdd69db7543e28e73a9f2afe80de7e531eb2347", size = 8272404, upload-time = "2025-08-30T00:12:59.112Z" }, + { url = "https://files.pythonhosted.org/packages/a9/5d/1d5f33f5b43f4f9e69e6a5fe1fb9090936ae7bc8e2ff6158e7a76542633b/matplotlib-3.10.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1678bb61d897bb4ac4757b5ecfb02bfb3fddf7f808000fb81e09c510712fda75", size = 8128262, upload-time = "2025-08-30T00:13:01.141Z" }, + { url = "https://files.pythonhosted.org/packages/67/c3/135fdbbbf84e0979712df58e5e22b4f257b3f5e52a3c4aacf1b8abec0d09/matplotlib-3.10.6-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:56cd2d20842f58c03d2d6e6c1f1cf5548ad6f66b91e1e48f814e4fb5abd1cb95", size = 8697008, upload-time = "2025-08-30T00:13:03.24Z" }, + { url = "https://files.pythonhosted.org/packages/9c/be/c443ea428fb2488a3ea7608714b1bd85a82738c45da21b447dc49e2f8e5d/matplotlib-3.10.6-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:662df55604a2f9a45435566d6e2660e41efe83cd94f4288dfbf1e6d1eae4b0bb", size = 9530166, upload-time = "2025-08-30T00:13:05.951Z" }, + { url = "https://files.pythonhosted.org/packages/a9/35/48441422b044d74034aea2a3e0d1a49023f12150ebc58f16600132b9bbaf/matplotlib-3.10.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:08f141d55148cd1fc870c3387d70ca4df16dee10e909b3b038782bd4bda6ea07", size = 9593105, upload-time = "2025-08-30T00:13:08.356Z" }, + { url = "https://files.pythonhosted.org/packages/45/c3/994ef20eb4154ab84cc08d033834555319e4af970165e6c8894050af0b3c/matplotlib-3.10.6-cp312-cp312-win_amd64.whl", hash = "sha256:590f5925c2d650b5c9d813c5b3b5fc53f2929c3f8ef463e4ecfa7e052044fb2b", size = 8122784, upload-time = "2025-08-30T00:13:10.367Z" }, + { url = "https://files.pythonhosted.org/packages/57/b8/5c85d9ae0e40f04e71bedb053aada5d6bab1f9b5399a0937afb5d6b02d98/matplotlib-3.10.6-cp312-cp312-win_arm64.whl", hash = "sha256:f44c8d264a71609c79a78d50349e724f5d5fc3684ead7c2a473665ee63d868aa", size = 7992823, upload-time = "2025-08-30T00:13:12.24Z" }, + { url = "https://files.pythonhosted.org/packages/a0/db/18380e788bb837e724358287b08e223b32bc8dccb3b0c12fa8ca20bc7f3b/matplotlib-3.10.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:819e409653c1106c8deaf62e6de6b8611449c2cd9939acb0d7d4e57a3d95cc7a", size = 8273231, upload-time = "2025-08-30T00:13:13.881Z" }, + { url = "https://files.pythonhosted.org/packages/d3/0f/38dd49445b297e0d4f12a322c30779df0d43cb5873c7847df8a82e82ec67/matplotlib-3.10.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:59c8ac8382fefb9cb71308dde16a7c487432f5255d8f1fd32473523abecfecdf", size = 8128730, upload-time = "2025-08-30T00:13:15.556Z" }, + { url = "https://files.pythonhosted.org/packages/e5/b8/9eea6630198cb303d131d95d285a024b3b8645b1763a2916fddb44ca8760/matplotlib-3.10.6-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:84e82d9e0fd70c70bc55739defbd8055c54300750cbacf4740c9673a24d6933a", size = 8698539, upload-time = "2025-08-30T00:13:17.297Z" }, + { url = "https://files.pythonhosted.org/packages/71/34/44c7b1f075e1ea398f88aeabcc2907c01b9cc99e2afd560c1d49845a1227/matplotlib-3.10.6-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25f7a3eb42d6c1c56e89eacd495661fc815ffc08d9da750bca766771c0fd9110", size = 9529702, upload-time = "2025-08-30T00:13:19.248Z" }, + { url = "https://files.pythonhosted.org/packages/b5/7f/e5c2dc9950c7facaf8b461858d1b92c09dd0cf174fe14e21953b3dda06f7/matplotlib-3.10.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f9c862d91ec0b7842920a4cfdaaec29662195301914ea54c33e01f1a28d014b2", size = 9593742, upload-time = "2025-08-30T00:13:21.181Z" }, + { url = "https://files.pythonhosted.org/packages/ff/1d/70c28528794f6410ee2856cd729fa1f1756498b8d3126443b0a94e1a8695/matplotlib-3.10.6-cp313-cp313-win_amd64.whl", hash = "sha256:1b53bd6337eba483e2e7d29c5ab10eee644bc3a2491ec67cc55f7b44583ffb18", size = 8122753, upload-time = "2025-08-30T00:13:23.44Z" }, + { url = "https://files.pythonhosted.org/packages/e8/74/0e1670501fc7d02d981564caf7c4df42974464625935424ca9654040077c/matplotlib-3.10.6-cp313-cp313-win_arm64.whl", hash = "sha256:cbd5eb50b7058b2892ce45c2f4e92557f395c9991f5c886d1bb74a1582e70fd6", size = 7992973, upload-time = "2025-08-30T00:13:26.632Z" }, + { url = "https://files.pythonhosted.org/packages/b1/4e/60780e631d73b6b02bd7239f89c451a72970e5e7ec34f621eda55cd9a445/matplotlib-3.10.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:acc86dd6e0e695c095001a7fccff158c49e45e0758fdf5dcdbb0103318b59c9f", size = 8316869, upload-time = "2025-08-30T00:13:28.262Z" }, + { url = "https://files.pythonhosted.org/packages/f8/15/baa662374a579413210fc2115d40c503b7360a08e9cc254aa0d97d34b0c1/matplotlib-3.10.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e228cd2ffb8f88b7d0b29e37f68ca9aaf83e33821f24a5ccc4f082dd8396bc27", size = 8178240, upload-time = "2025-08-30T00:13:30.007Z" }, + { url = "https://files.pythonhosted.org/packages/c6/3f/3c38e78d2aafdb8829fcd0857d25aaf9e7dd2dfcf7ec742765b585774931/matplotlib-3.10.6-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:658bc91894adeab669cf4bb4a186d049948262987e80f0857216387d7435d833", size = 8711719, upload-time = "2025-08-30T00:13:31.72Z" }, + { url = "https://files.pythonhosted.org/packages/96/4b/2ec2bbf8cefaa53207cc56118d1fa8a0f9b80642713ea9390235d331ede4/matplotlib-3.10.6-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8913b7474f6dd83ac444c9459c91f7f0f2859e839f41d642691b104e0af056aa", size = 9541422, upload-time = "2025-08-30T00:13:33.611Z" }, + { url = "https://files.pythonhosted.org/packages/83/7d/40255e89b3ef11c7871020563b2dd85f6cb1b4eff17c0f62b6eb14c8fa80/matplotlib-3.10.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:091cea22e059b89f6d7d1a18e2c33a7376c26eee60e401d92a4d6726c4e12706", size = 9594068, upload-time = "2025-08-30T00:13:35.833Z" }, + { url = "https://files.pythonhosted.org/packages/f0/a9/0213748d69dc842537a113493e1c27daf9f96bd7cc316f933dc8ec4de985/matplotlib-3.10.6-cp313-cp313t-win_amd64.whl", hash = "sha256:491e25e02a23d7207629d942c666924a6b61e007a48177fdd231a0097b7f507e", size = 8200100, upload-time = "2025-08-30T00:13:37.668Z" }, + { url = "https://files.pythonhosted.org/packages/be/15/79f9988066ce40b8a6f1759a934ea0cde8dc4adc2262255ee1bc98de6ad0/matplotlib-3.10.6-cp313-cp313t-win_arm64.whl", hash = "sha256:3d80d60d4e54cda462e2cd9a086d85cd9f20943ead92f575ce86885a43a565d5", size = 8042142, upload-time = "2025-08-30T00:13:39.426Z" }, + { url = "https://files.pythonhosted.org/packages/7c/58/e7b6d292beae6fb4283ca6fb7fa47d7c944a68062d6238c07b497dd35493/matplotlib-3.10.6-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:70aaf890ce1d0efd482df969b28a5b30ea0b891224bb315810a3940f67182899", size = 8273802, upload-time = "2025-08-30T00:13:41.006Z" }, + { url = "https://files.pythonhosted.org/packages/9f/f6/7882d05aba16a8cdd594fb9a03a9d3cca751dbb6816adf7b102945522ee9/matplotlib-3.10.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1565aae810ab79cb72e402b22facfa6501365e73ebab70a0fdfb98488d2c3c0c", size = 8131365, upload-time = "2025-08-30T00:13:42.664Z" }, + { url = "https://files.pythonhosted.org/packages/94/bf/ff32f6ed76e78514e98775a53715eca4804b12bdcf35902cdd1cf759d324/matplotlib-3.10.6-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3b23315a01981689aa4e1a179dbf6ef9fbd17143c3eea77548c2ecfb0499438", size = 9533961, upload-time = "2025-08-30T00:13:44.372Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c3/6bf88c2fc2da7708a2ff8d2eeb5d68943130f50e636d5d3dcf9d4252e971/matplotlib-3.10.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:30fdd37edf41a4e6785f9b37969de57aea770696cb637d9946eb37470c94a453", size = 9804262, upload-time = "2025-08-30T00:13:46.614Z" }, + { url = "https://files.pythonhosted.org/packages/0f/7a/e05e6d9446d2d577b459427ad060cd2de5742d0e435db3191fea4fcc7e8b/matplotlib-3.10.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bc31e693da1c08012c764b053e702c1855378e04102238e6a5ee6a7117c53a47", size = 9595508, upload-time = "2025-08-30T00:13:48.731Z" }, + { url = "https://files.pythonhosted.org/packages/39/fb/af09c463ced80b801629fd73b96f726c9f6124c3603aa2e480a061d6705b/matplotlib-3.10.6-cp314-cp314-win_amd64.whl", hash = "sha256:05be9bdaa8b242bc6ff96330d18c52f1fc59c6fb3a4dd411d953d67e7e1baf98", size = 8252742, upload-time = "2025-08-30T00:13:50.539Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f9/b682f6db9396d9ab8f050c0a3bfbb5f14fb0f6518f08507c04cc02f8f229/matplotlib-3.10.6-cp314-cp314-win_arm64.whl", hash = "sha256:f56a0d1ab05d34c628592435781d185cd99630bdfd76822cd686fb5a0aecd43a", size = 8124237, upload-time = "2025-08-30T00:13:54.3Z" }, + { url = "https://files.pythonhosted.org/packages/b5/d2/b69b4a0923a3c05ab90527c60fdec899ee21ca23ede7f0fb818e6620d6f2/matplotlib-3.10.6-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:94f0b4cacb23763b64b5dace50d5b7bfe98710fed5f0cef5c08135a03399d98b", size = 8316956, upload-time = "2025-08-30T00:13:55.932Z" }, + { url = "https://files.pythonhosted.org/packages/28/e9/dc427b6f16457ffaeecb2fc4abf91e5adb8827861b869c7a7a6d1836fa73/matplotlib-3.10.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cc332891306b9fb39462673d8225d1b824c89783fee82840a709f96714f17a5c", size = 8178260, upload-time = "2025-08-30T00:14:00.942Z" }, + { url = "https://files.pythonhosted.org/packages/c4/89/1fbd5ad611802c34d1c7ad04607e64a1350b7fb9c567c4ec2c19e066ed35/matplotlib-3.10.6-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee1d607b3fb1590deb04b69f02ea1d53ed0b0bf75b2b1a5745f269afcbd3cdd3", size = 9541422, upload-time = "2025-08-30T00:14:02.664Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3b/65fec8716025b22c1d72d5a82ea079934c76a547696eaa55be6866bc89b1/matplotlib-3.10.6-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:376a624a218116461696b27b2bbf7a8945053e6d799f6502fc03226d077807bf", size = 9803678, upload-time = "2025-08-30T00:14:04.741Z" }, + { url = "https://files.pythonhosted.org/packages/c7/b0/40fb2b3a1ab9381bb39a952e8390357c8be3bdadcf6d5055d9c31e1b35ae/matplotlib-3.10.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:83847b47f6524c34b4f2d3ce726bb0541c48c8e7692729865c3df75bfa0f495a", size = 9594077, upload-time = "2025-08-30T00:14:07.012Z" }, + { url = "https://files.pythonhosted.org/packages/76/34/c4b71b69edf5b06e635eee1ed10bfc73cf8df058b66e63e30e6a55e231d5/matplotlib-3.10.6-cp314-cp314t-win_amd64.whl", hash = "sha256:c7e0518e0d223683532a07f4b512e2e0729b62674f1b3a1a69869f98e6b1c7e3", size = 8342822, upload-time = "2025-08-30T00:14:09.041Z" }, + { url = "https://files.pythonhosted.org/packages/e8/62/aeabeef1a842b6226a30d49dd13e8a7a1e81e9ec98212c0b5169f0a12d83/matplotlib-3.10.6-cp314-cp314t-win_arm64.whl", hash = "sha256:4dd83e029f5b4801eeb87c64efd80e732452781c16a9cf7415b7b63ec8f374d7", size = 8172588, upload-time = "2025-08-30T00:14:11.166Z" }, + { url = "https://files.pythonhosted.org/packages/17/6f/2551e45bea2938e0363ccdd54fa08dae7605ce782d4332497d31a7b97672/matplotlib-3.10.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:13fcd07ccf17e354398358e0307a1f53f5325dca22982556ddb9c52837b5af41", size = 8241220, upload-time = "2025-08-30T00:14:12.888Z" }, + { url = "https://files.pythonhosted.org/packages/54/7e/0f4c6e8b98105fdb162a4efde011af204ca47d7c05d735aff480ebfead1b/matplotlib-3.10.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:470fc846d59d1406e34fa4c32ba371039cd12c2fe86801159a965956f2575bd1", size = 8104624, upload-time = "2025-08-30T00:14:14.511Z" }, + { url = "https://files.pythonhosted.org/packages/27/27/c29696702b9317a6ade1ba6f8861e02d7423f18501729203d7a80b686f23/matplotlib-3.10.6-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f7173f8551b88f4ef810a94adae3128c2530e0d07529f7141be7f8d8c365f051", size = 8682271, upload-time = "2025-08-30T00:14:17.273Z" }, + { url = "https://files.pythonhosted.org/packages/12/bb/02c35a51484aae5f49bd29f091286e7af5f3f677a9736c58a92b3c78baeb/matplotlib-3.10.6-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f2d684c3204fa62421bbf770ddfebc6b50130f9cad65531eeba19236d73bb488", size = 8252296, upload-time = "2025-08-30T00:14:19.49Z" }, + { url = "https://files.pythonhosted.org/packages/7d/85/41701e3092005aee9a2445f5ee3904d9dbd4a7df7a45905ffef29b7ef098/matplotlib-3.10.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:6f4a69196e663a41d12a728fab8751177215357906436804217d6d9cf0d4d6cf", size = 8116749, upload-time = "2025-08-30T00:14:21.344Z" }, + { url = "https://files.pythonhosted.org/packages/16/53/8d8fa0ea32a8c8239e04d022f6c059ee5e1b77517769feccd50f1df43d6d/matplotlib-3.10.6-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d6ca6ef03dfd269f4ead566ec6f3fb9becf8dab146fb999022ed85ee9f6b3eb", size = 8693933, upload-time = "2025-08-30T00:14:22.942Z" }, +] + [[package]] name = "matplotlib-inline" version = "0.1.7" @@ -2258,6 +2670,108 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, ] +[[package]] +name = "pillow" +version = "11.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/d0d6dea55cd152ce3d6767bb38a8fc10e33796ba4ba210cbab9354b6d238/pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523", size = 47113069, upload-time = "2025-07-01T09:16:30.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/5d/45a3553a253ac8763f3561371432a90bdbe6000fbdcf1397ffe502aa206c/pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860", size = 5316554, upload-time = "2025-07-01T09:13:39.342Z" }, + { url = "https://files.pythonhosted.org/packages/7c/c8/67c12ab069ef586a25a4a79ced553586748fad100c77c0ce59bb4983ac98/pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad", size = 4686548, upload-time = "2025-07-01T09:13:41.835Z" }, + { url = "https://files.pythonhosted.org/packages/2f/bd/6741ebd56263390b382ae4c5de02979af7f8bd9807346d068700dd6d5cf9/pillow-11.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0", size = 5859742, upload-time = "2025-07-03T13:09:47.439Z" }, + { url = "https://files.pythonhosted.org/packages/ca/0b/c412a9e27e1e6a829e6ab6c2dca52dd563efbedf4c9c6aa453d9a9b77359/pillow-11.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b", size = 7633087, upload-time = "2025-07-03T13:09:51.796Z" }, + { url = "https://files.pythonhosted.org/packages/59/9d/9b7076aaf30f5dd17e5e5589b2d2f5a5d7e30ff67a171eb686e4eecc2adf/pillow-11.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50", size = 5963350, upload-time = "2025-07-01T09:13:43.865Z" }, + { url = "https://files.pythonhosted.org/packages/f0/16/1a6bf01fb622fb9cf5c91683823f073f053005c849b1f52ed613afcf8dae/pillow-11.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae", size = 6631840, upload-time = "2025-07-01T09:13:46.161Z" }, + { url = "https://files.pythonhosted.org/packages/7b/e6/6ff7077077eb47fde78739e7d570bdcd7c10495666b6afcd23ab56b19a43/pillow-11.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9", size = 6074005, upload-time = "2025-07-01T09:13:47.829Z" }, + { url = "https://files.pythonhosted.org/packages/c3/3a/b13f36832ea6d279a697231658199e0a03cd87ef12048016bdcc84131601/pillow-11.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e", size = 6708372, upload-time = "2025-07-01T09:13:52.145Z" }, + { url = "https://files.pythonhosted.org/packages/6c/e4/61b2e1a7528740efbc70b3d581f33937e38e98ef3d50b05007267a55bcb2/pillow-11.3.0-cp310-cp310-win32.whl", hash = "sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6", size = 6277090, upload-time = "2025-07-01T09:13:53.915Z" }, + { url = "https://files.pythonhosted.org/packages/a9/d3/60c781c83a785d6afbd6a326ed4d759d141de43aa7365725cbcd65ce5e54/pillow-11.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f", size = 6985988, upload-time = "2025-07-01T09:13:55.699Z" }, + { url = "https://files.pythonhosted.org/packages/9f/28/4f4a0203165eefb3763939c6789ba31013a2e90adffb456610f30f613850/pillow-11.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f", size = 2422899, upload-time = "2025-07-01T09:13:57.497Z" }, + { url = "https://files.pythonhosted.org/packages/db/26/77f8ed17ca4ffd60e1dcd220a6ec6d71210ba398cfa33a13a1cd614c5613/pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722", size = 5316531, upload-time = "2025-07-01T09:13:59.203Z" }, + { url = "https://files.pythonhosted.org/packages/cb/39/ee475903197ce709322a17a866892efb560f57900d9af2e55f86db51b0a5/pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288", size = 4686560, upload-time = "2025-07-01T09:14:01.101Z" }, + { url = "https://files.pythonhosted.org/packages/d5/90/442068a160fd179938ba55ec8c97050a612426fae5ec0a764e345839f76d/pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d", size = 5870978, upload-time = "2025-07-03T13:09:55.638Z" }, + { url = "https://files.pythonhosted.org/packages/13/92/dcdd147ab02daf405387f0218dcf792dc6dd5b14d2573d40b4caeef01059/pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494", size = 7641168, upload-time = "2025-07-03T13:10:00.37Z" }, + { url = "https://files.pythonhosted.org/packages/6e/db/839d6ba7fd38b51af641aa904e2960e7a5644d60ec754c046b7d2aee00e5/pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58", size = 5973053, upload-time = "2025-07-01T09:14:04.491Z" }, + { url = "https://files.pythonhosted.org/packages/f2/2f/d7675ecae6c43e9f12aa8d58b6012683b20b6edfbdac7abcb4e6af7a3784/pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f", size = 6640273, upload-time = "2025-07-01T09:14:06.235Z" }, + { url = "https://files.pythonhosted.org/packages/45/ad/931694675ede172e15b2ff03c8144a0ddaea1d87adb72bb07655eaffb654/pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e", size = 6082043, upload-time = "2025-07-01T09:14:07.978Z" }, + { url = "https://files.pythonhosted.org/packages/3a/04/ba8f2b11fc80d2dd462d7abec16351b45ec99cbbaea4387648a44190351a/pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94", size = 6715516, upload-time = "2025-07-01T09:14:10.233Z" }, + { url = "https://files.pythonhosted.org/packages/48/59/8cd06d7f3944cc7d892e8533c56b0acb68399f640786313275faec1e3b6f/pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0", size = 6274768, upload-time = "2025-07-01T09:14:11.921Z" }, + { url = "https://files.pythonhosted.org/packages/f1/cc/29c0f5d64ab8eae20f3232da8f8571660aa0ab4b8f1331da5c2f5f9a938e/pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac", size = 6986055, upload-time = "2025-07-01T09:14:13.623Z" }, + { url = "https://files.pythonhosted.org/packages/c6/df/90bd886fabd544c25addd63e5ca6932c86f2b701d5da6c7839387a076b4a/pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd", size = 2423079, upload-time = "2025-07-01T09:14:15.268Z" }, + { url = "https://files.pythonhosted.org/packages/40/fe/1bc9b3ee13f68487a99ac9529968035cca2f0a51ec36892060edcc51d06a/pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4", size = 5278800, upload-time = "2025-07-01T09:14:17.648Z" }, + { url = "https://files.pythonhosted.org/packages/2c/32/7e2ac19b5713657384cec55f89065fb306b06af008cfd87e572035b27119/pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69", size = 4686296, upload-time = "2025-07-01T09:14:19.828Z" }, + { url = "https://files.pythonhosted.org/packages/8e/1e/b9e12bbe6e4c2220effebc09ea0923a07a6da1e1f1bfbc8d7d29a01ce32b/pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d", size = 5871726, upload-time = "2025-07-03T13:10:04.448Z" }, + { url = "https://files.pythonhosted.org/packages/8d/33/e9200d2bd7ba00dc3ddb78df1198a6e80d7669cce6c2bdbeb2530a74ec58/pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6", size = 7644652, upload-time = "2025-07-03T13:10:10.391Z" }, + { url = "https://files.pythonhosted.org/packages/41/f1/6f2427a26fc683e00d985bc391bdd76d8dd4e92fac33d841127eb8fb2313/pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7", size = 5977787, upload-time = "2025-07-01T09:14:21.63Z" }, + { url = "https://files.pythonhosted.org/packages/e4/c9/06dd4a38974e24f932ff5f98ea3c546ce3f8c995d3f0985f8e5ba48bba19/pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024", size = 6645236, upload-time = "2025-07-01T09:14:23.321Z" }, + { url = "https://files.pythonhosted.org/packages/40/e7/848f69fb79843b3d91241bad658e9c14f39a32f71a301bcd1d139416d1be/pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809", size = 6086950, upload-time = "2025-07-01T09:14:25.237Z" }, + { url = "https://files.pythonhosted.org/packages/0b/1a/7cff92e695a2a29ac1958c2a0fe4c0b2393b60aac13b04a4fe2735cad52d/pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d", size = 6723358, upload-time = "2025-07-01T09:14:27.053Z" }, + { url = "https://files.pythonhosted.org/packages/26/7d/73699ad77895f69edff76b0f332acc3d497f22f5d75e5360f78cbcaff248/pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149", size = 6275079, upload-time = "2025-07-01T09:14:30.104Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ce/e7dfc873bdd9828f3b6e5c2bbb74e47a98ec23cc5c74fc4e54462f0d9204/pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d", size = 6986324, upload-time = "2025-07-01T09:14:31.899Z" }, + { url = "https://files.pythonhosted.org/packages/16/8f/b13447d1bf0b1f7467ce7d86f6e6edf66c0ad7cf44cf5c87a37f9bed9936/pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542", size = 2423067, upload-time = "2025-07-01T09:14:33.709Z" }, + { url = "https://files.pythonhosted.org/packages/1e/93/0952f2ed8db3a5a4c7a11f91965d6184ebc8cd7cbb7941a260d5f018cd2d/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd", size = 2128328, upload-time = "2025-07-01T09:14:35.276Z" }, + { url = "https://files.pythonhosted.org/packages/4b/e8/100c3d114b1a0bf4042f27e0f87d2f25e857e838034e98ca98fe7b8c0a9c/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8", size = 2170652, upload-time = "2025-07-01T09:14:37.203Z" }, + { url = "https://files.pythonhosted.org/packages/aa/86/3f758a28a6e381758545f7cdb4942e1cb79abd271bea932998fc0db93cb6/pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f", size = 2227443, upload-time = "2025-07-01T09:14:39.344Z" }, + { url = "https://files.pythonhosted.org/packages/01/f4/91d5b3ffa718df2f53b0dc109877993e511f4fd055d7e9508682e8aba092/pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c", size = 5278474, upload-time = "2025-07-01T09:14:41.843Z" }, + { url = "https://files.pythonhosted.org/packages/f9/0e/37d7d3eca6c879fbd9dba21268427dffda1ab00d4eb05b32923d4fbe3b12/pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd", size = 4686038, upload-time = "2025-07-01T09:14:44.008Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b0/3426e5c7f6565e752d81221af9d3676fdbb4f352317ceafd42899aaf5d8a/pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e", size = 5864407, upload-time = "2025-07-03T13:10:15.628Z" }, + { url = "https://files.pythonhosted.org/packages/fc/c1/c6c423134229f2a221ee53f838d4be9d82bab86f7e2f8e75e47b6bf6cd77/pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1", size = 7639094, upload-time = "2025-07-03T13:10:21.857Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c9/09e6746630fe6372c67c648ff9deae52a2bc20897d51fa293571977ceb5d/pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805", size = 5973503, upload-time = "2025-07-01T09:14:45.698Z" }, + { url = "https://files.pythonhosted.org/packages/d5/1c/a2a29649c0b1983d3ef57ee87a66487fdeb45132df66ab30dd37f7dbe162/pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8", size = 6642574, upload-time = "2025-07-01T09:14:47.415Z" }, + { url = "https://files.pythonhosted.org/packages/36/de/d5cc31cc4b055b6c6fd990e3e7f0f8aaf36229a2698501bcb0cdf67c7146/pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2", size = 6084060, upload-time = "2025-07-01T09:14:49.636Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ea/502d938cbaeec836ac28a9b730193716f0114c41325db428e6b280513f09/pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b", size = 6721407, upload-time = "2025-07-01T09:14:51.962Z" }, + { url = "https://files.pythonhosted.org/packages/45/9c/9c5e2a73f125f6cbc59cc7087c8f2d649a7ae453f83bd0362ff7c9e2aee2/pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3", size = 6273841, upload-time = "2025-07-01T09:14:54.142Z" }, + { url = "https://files.pythonhosted.org/packages/23/85/397c73524e0cd212067e0c969aa245b01d50183439550d24d9f55781b776/pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51", size = 6978450, upload-time = "2025-07-01T09:14:56.436Z" }, + { url = "https://files.pythonhosted.org/packages/17/d2/622f4547f69cd173955194b78e4d19ca4935a1b0f03a302d655c9f6aae65/pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580", size = 2423055, upload-time = "2025-07-01T09:14:58.072Z" }, + { url = "https://files.pythonhosted.org/packages/dd/80/a8a2ac21dda2e82480852978416cfacd439a4b490a501a288ecf4fe2532d/pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e", size = 5281110, upload-time = "2025-07-01T09:14:59.79Z" }, + { url = "https://files.pythonhosted.org/packages/44/d6/b79754ca790f315918732e18f82a8146d33bcd7f4494380457ea89eb883d/pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d", size = 4689547, upload-time = "2025-07-01T09:15:01.648Z" }, + { url = "https://files.pythonhosted.org/packages/49/20/716b8717d331150cb00f7fdd78169c01e8e0c219732a78b0e59b6bdb2fd6/pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced", size = 5901554, upload-time = "2025-07-03T13:10:27.018Z" }, + { url = "https://files.pythonhosted.org/packages/74/cf/a9f3a2514a65bb071075063a96f0a5cf949c2f2fce683c15ccc83b1c1cab/pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c", size = 7669132, upload-time = "2025-07-03T13:10:33.01Z" }, + { url = "https://files.pythonhosted.org/packages/98/3c/da78805cbdbee9cb43efe8261dd7cc0b4b93f2ac79b676c03159e9db2187/pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8", size = 6005001, upload-time = "2025-07-01T09:15:03.365Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fa/ce044b91faecf30e635321351bba32bab5a7e034c60187fe9698191aef4f/pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59", size = 6668814, upload-time = "2025-07-01T09:15:05.655Z" }, + { url = "https://files.pythonhosted.org/packages/7b/51/90f9291406d09bf93686434f9183aba27b831c10c87746ff49f127ee80cb/pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe", size = 6113124, upload-time = "2025-07-01T09:15:07.358Z" }, + { url = "https://files.pythonhosted.org/packages/cd/5a/6fec59b1dfb619234f7636d4157d11fb4e196caeee220232a8d2ec48488d/pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c", size = 6747186, upload-time = "2025-07-01T09:15:09.317Z" }, + { url = "https://files.pythonhosted.org/packages/49/6b/00187a044f98255225f172de653941e61da37104a9ea60e4f6887717e2b5/pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788", size = 6277546, upload-time = "2025-07-01T09:15:11.311Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5c/6caaba7e261c0d75bab23be79f1d06b5ad2a2ae49f028ccec801b0e853d6/pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31", size = 6985102, upload-time = "2025-07-01T09:15:13.164Z" }, + { url = "https://files.pythonhosted.org/packages/f3/7e/b623008460c09a0cb38263c93b828c666493caee2eb34ff67f778b87e58c/pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e", size = 2424803, upload-time = "2025-07-01T09:15:15.695Z" }, + { url = "https://files.pythonhosted.org/packages/73/f4/04905af42837292ed86cb1b1dabe03dce1edc008ef14c473c5c7e1443c5d/pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12", size = 5278520, upload-time = "2025-07-01T09:15:17.429Z" }, + { url = "https://files.pythonhosted.org/packages/41/b0/33d79e377a336247df6348a54e6d2a2b85d644ca202555e3faa0cf811ecc/pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a", size = 4686116, upload-time = "2025-07-01T09:15:19.423Z" }, + { url = "https://files.pythonhosted.org/packages/49/2d/ed8bc0ab219ae8768f529597d9509d184fe8a6c4741a6864fea334d25f3f/pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632", size = 5864597, upload-time = "2025-07-03T13:10:38.404Z" }, + { url = "https://files.pythonhosted.org/packages/b5/3d/b932bb4225c80b58dfadaca9d42d08d0b7064d2d1791b6a237f87f661834/pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673", size = 7638246, upload-time = "2025-07-03T13:10:44.987Z" }, + { url = "https://files.pythonhosted.org/packages/09/b5/0487044b7c096f1b48f0d7ad416472c02e0e4bf6919541b111efd3cae690/pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027", size = 5973336, upload-time = "2025-07-01T09:15:21.237Z" }, + { url = "https://files.pythonhosted.org/packages/a8/2d/524f9318f6cbfcc79fbc004801ea6b607ec3f843977652fdee4857a7568b/pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77", size = 6642699, upload-time = "2025-07-01T09:15:23.186Z" }, + { url = "https://files.pythonhosted.org/packages/6f/d2/a9a4f280c6aefedce1e8f615baaa5474e0701d86dd6f1dede66726462bbd/pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874", size = 6083789, upload-time = "2025-07-01T09:15:25.1Z" }, + { url = "https://files.pythonhosted.org/packages/fe/54/86b0cd9dbb683a9d5e960b66c7379e821a19be4ac5810e2e5a715c09a0c0/pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a", size = 6720386, upload-time = "2025-07-01T09:15:27.378Z" }, + { url = "https://files.pythonhosted.org/packages/e7/95/88efcaf384c3588e24259c4203b909cbe3e3c2d887af9e938c2022c9dd48/pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214", size = 6370911, upload-time = "2025-07-01T09:15:29.294Z" }, + { url = "https://files.pythonhosted.org/packages/2e/cc/934e5820850ec5eb107e7b1a72dd278140731c669f396110ebc326f2a503/pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635", size = 7117383, upload-time = "2025-07-01T09:15:31.128Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e9/9c0a616a71da2a5d163aa37405e8aced9a906d574b4a214bede134e731bc/pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6", size = 2511385, upload-time = "2025-07-01T09:15:33.328Z" }, + { url = "https://files.pythonhosted.org/packages/1a/33/c88376898aff369658b225262cd4f2659b13e8178e7534df9e6e1fa289f6/pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae", size = 5281129, upload-time = "2025-07-01T09:15:35.194Z" }, + { url = "https://files.pythonhosted.org/packages/1f/70/d376247fb36f1844b42910911c83a02d5544ebd2a8bad9efcc0f707ea774/pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653", size = 4689580, upload-time = "2025-07-01T09:15:37.114Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/537e930496149fbac69efd2fc4329035bbe2e5475b4165439e3be9cb183b/pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6", size = 5902860, upload-time = "2025-07-03T13:10:50.248Z" }, + { url = "https://files.pythonhosted.org/packages/bd/57/80f53264954dcefeebcf9dae6e3eb1daea1b488f0be8b8fef12f79a3eb10/pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36", size = 7670694, upload-time = "2025-07-03T13:10:56.432Z" }, + { url = "https://files.pythonhosted.org/packages/70/ff/4727d3b71a8578b4587d9c276e90efad2d6fe0335fd76742a6da08132e8c/pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b", size = 6005888, upload-time = "2025-07-01T09:15:39.436Z" }, + { url = "https://files.pythonhosted.org/packages/05/ae/716592277934f85d3be51d7256f3636672d7b1abfafdc42cf3f8cbd4b4c8/pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477", size = 6670330, upload-time = "2025-07-01T09:15:41.269Z" }, + { url = "https://files.pythonhosted.org/packages/e7/bb/7fe6cddcc8827b01b1a9766f5fdeb7418680744f9082035bdbabecf1d57f/pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50", size = 6114089, upload-time = "2025-07-01T09:15:43.13Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f5/06bfaa444c8e80f1a8e4bff98da9c83b37b5be3b1deaa43d27a0db37ef84/pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b", size = 6748206, upload-time = "2025-07-01T09:15:44.937Z" }, + { url = "https://files.pythonhosted.org/packages/f0/77/bc6f92a3e8e6e46c0ca78abfffec0037845800ea38c73483760362804c41/pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12", size = 6377370, upload-time = "2025-07-01T09:15:46.673Z" }, + { url = "https://files.pythonhosted.org/packages/4a/82/3a721f7d69dca802befb8af08b7c79ebcab461007ce1c18bd91a5d5896f9/pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db", size = 7121500, upload-time = "2025-07-01T09:15:48.512Z" }, + { url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835, upload-time = "2025-07-01T09:15:50.399Z" }, + { url = "https://files.pythonhosted.org/packages/6f/8b/209bd6b62ce8367f47e68a218bffac88888fdf2c9fcf1ecadc6c3ec1ebc7/pillow-11.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967", size = 5270556, upload-time = "2025-07-01T09:16:09.961Z" }, + { url = "https://files.pythonhosted.org/packages/2e/e6/231a0b76070c2cfd9e260a7a5b504fb72da0a95279410fa7afd99d9751d6/pillow-11.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe", size = 4654625, upload-time = "2025-07-01T09:16:11.913Z" }, + { url = "https://files.pythonhosted.org/packages/13/f4/10cf94fda33cb12765f2397fc285fa6d8eb9c29de7f3185165b702fc7386/pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c", size = 4874207, upload-time = "2025-07-03T13:11:10.201Z" }, + { url = "https://files.pythonhosted.org/packages/72/c9/583821097dc691880c92892e8e2d41fe0a5a3d6021f4963371d2f6d57250/pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25", size = 6583939, upload-time = "2025-07-03T13:11:15.68Z" }, + { url = "https://files.pythonhosted.org/packages/3b/8e/5c9d410f9217b12320efc7c413e72693f48468979a013ad17fd690397b9a/pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27", size = 4957166, upload-time = "2025-07-01T09:16:13.74Z" }, + { url = "https://files.pythonhosted.org/packages/62/bb/78347dbe13219991877ffb3a91bf09da8317fbfcd4b5f9140aeae020ad71/pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a", size = 5581482, upload-time = "2025-07-01T09:16:16.107Z" }, + { url = "https://files.pythonhosted.org/packages/d9/28/1000353d5e61498aaeaaf7f1e4b49ddb05f2c6575f9d4f9f914a3538b6e1/pillow-11.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f", size = 6984596, upload-time = "2025-07-01T09:16:18.07Z" }, + { url = "https://files.pythonhosted.org/packages/9e/e3/6fa84033758276fb31da12e5fb66ad747ae83b93c67af17f8c6ff4cc8f34/pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6", size = 5270566, upload-time = "2025-07-01T09:16:19.801Z" }, + { url = "https://files.pythonhosted.org/packages/5b/ee/e8d2e1ab4892970b561e1ba96cbd59c0d28cf66737fc44abb2aec3795a4e/pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438", size = 4654618, upload-time = "2025-07-01T09:16:21.818Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6d/17f80f4e1f0761f02160fc433abd4109fa1548dcfdca46cfdadaf9efa565/pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3", size = 4874248, upload-time = "2025-07-03T13:11:20.738Z" }, + { url = "https://files.pythonhosted.org/packages/de/5f/c22340acd61cef960130585bbe2120e2fd8434c214802f07e8c03596b17e/pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c", size = 6583963, upload-time = "2025-07-03T13:11:26.283Z" }, + { url = "https://files.pythonhosted.org/packages/31/5e/03966aedfbfcbb4d5f8aa042452d3361f325b963ebbadddac05b122e47dd/pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361", size = 4957170, upload-time = "2025-07-01T09:16:23.762Z" }, + { url = "https://files.pythonhosted.org/packages/cc/2d/e082982aacc927fc2cab48e1e731bdb1643a1406acace8bed0900a61464e/pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7", size = 5581505, upload-time = "2025-07-01T09:16:25.593Z" }, + { url = "https://files.pythonhosted.org/packages/34/e7/ae39f538fd6844e982063c3a5e4598b8ced43b9633baa3a85ef33af8c05c/pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8", size = 6984598, upload-time = "2025-07-01T09:16:27.732Z" }, +] + [[package]] name = "platformdirs" version = "4.4.0" @@ -2481,6 +2995,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] +[[package]] +name = "pyparsing" +version = "3.2.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/a5/181488fc2b9d093e3972d2a472855aae8a03f000592dbfce716a512b3359/pyparsing-3.2.5.tar.gz", hash = "sha256:2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6", size = 1099274, upload-time = "2025-09-21T04:11:06.277Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl", hash = "sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e", size = 113890, upload-time = "2025-09-21T04:11:04.117Z" }, +] + [[package]] name = "pytest" version = "8.4.2"