Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c78797f
change: replace `pandas` with `polars`, laid ground works for hea int…
huangziwei Jun 9, 2026
2f3aefa
change: use `hea.io` to load built-in data for tidy verbs; update: no…
huangziwei Jun 9, 2026
1a79733
change: consolidated LC/CCRegression onto `hea.lm` via `harmonic()` b…
huangziwei Jun 9, 2026
e9c0391
add: gam for LC/CCRegression
huangziwei Jun 9, 2026
5314efa
fix: ccregression in t4 notebook
huangziwei Jun 10, 2026
53b80e7
fix: ccreg/plot with se
huangziwei Jun 10, 2026
48d0260
change: distributions/prepare regression compatability for vonmises
huangziwei Jun 10, 2026
afa7368
change: regression/wire the regression ready vonmises into CLRegression
huangziwei Jun 10, 2026
0a6c920
change: pin hea to the dev version for synchronized work
huangziwei Jun 10, 2026
ce03717
add: distributions/links function for regression
huangziwei Jun 10, 2026
b99e212
add: distributions/projectednormal; change: distributions/more regres…
huangziwei Jun 10, 2026
4b6ec7f
add: regression/wire gam into CLRegression
huangziwei Jun 10, 2026
25ead49
change: regression/CLRegression.plot() style
huangziwei Jun 10, 2026
c8e86da
change: regression/CLRegression unified formula style between fisher-…
huangziwei Jun 10, 2026
e69ece6
change: regression/CLRegression.predict() input data format
huangziwei Jun 10, 2026
cc234ab
update: example/T4
huangziwei Jun 10, 2026
8e542cd
update: deps/hea==0.1.4
huangziwei Jun 10, 2026
8123a0b
fix: distributions/various numerica bugs
huangziwei Jun 10, 2026
3178d6c
update: example/t3
huangziwei Jun 10, 2026
0ca7ca4
change: lift some more distributions to be regression ready
huangziwei Jun 11, 2026
a2bcb4f
wip: distributions/bug fix in progress
huangziwei Jun 11, 2026
6f420ca
fix: distributions/jp performance
huangziwei Jun 11, 2026
17aab79
fix: distributions/various .rvs() hang or crashed
huangziwei Jun 11, 2026
5803c9a
fix: distributions/JP-clan cdf/ppf depth gate
huangziwei Jun 11, 2026
11d28f5
fix: distributions/stabler _logpdf everywhere
huangziwei Jun 11, 2026
bfa249b
fix: distributions/wrapstable degenerate case warning in test
huangziwei Jun 11, 2026
a6d90c9
change: distributions/closed-form trig_moment for 9 distributions
huangziwei Jun 11, 2026
c70cace
change: distributions/closed-form trig_moment for JP too
huangziwei Jun 11, 2026
1d0fbe1
change: distributions/close-form cdf and ppf for various distrs
huangziwei Jun 11, 2026
0d10c4a
fix: distributions/align .fit() for all distributions
huangziwei Jun 11, 2026
8647b34
fix: distributions/mostly cosmetics
huangziwei Jun 11, 2026
910ec58
fix: distributions/some wrong bounds and some cosmetics
huangziwei Jun 11, 2026
5435602
add: regression/cl(kj).shape_inference(); fix: docstring here and there
huangziwei Jun 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 23 additions & 14 deletions examples/B1-Fisher-1993.ipynb

Large diffs are not rendered by default.

104 changes: 52 additions & 52 deletions examples/B2-Zar-2010.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@
}
],
"source": [
"d1 = load_data(\"D1\", source=\"zar\")[\"θ\"].values[:]\n",
"d1 = load_data(\"D1\", source=\"zar\")[\"θ\"].to_numpy()[:]\n",
"c1 = Circular(data=d1)\n",
"\n",
"# Figure 26.2\n",
Expand Down Expand Up @@ -176,7 +176,7 @@
],
"source": [
"d2 = load_data(\"D2\", source=\"zar\")\n",
"c2 = Circular(data=d2[\"θ\"].values[:], w=d2[\"w\"].values[:])\n",
"c2 = Circular(data=d2[\"θ\"].to_numpy()[:], w=d2[\"w\"].to_numpy()[:])\n",
"\n",
"# figure 26.4\n",
"c2.plot(\n",
Expand Down Expand Up @@ -238,7 +238,7 @@
"\n",
"from pycircstat2.utils import data2rad\n",
"\n",
"d1 = load_data(\"D1\", source=\"zar\")[\"θ\"].values[:]\n",
"d1 = load_data(\"D1\", source=\"zar\")[\"θ\"].to_numpy()[:]\n",
"n = len(d1)\n",
"alpha = data2rad(d1, k=360)\n",
"\n",
Expand Down Expand Up @@ -335,8 +335,8 @@
],
"source": [
"d2 = load_data(\"D2\", source=\"zar\")\n",
"alpha = np.asarray(data2rad(d2[\"θ\"].values[:], k=360))\n",
"w = d2[\"w\"].values[:]\n",
"alpha = np.asarray(data2rad(d2[\"θ\"].to_numpy()[:], k=360))\n",
"w = d2[\"w\"].to_numpy()[:]\n",
"select = w != 0\n",
"alpha = alpha[select]\n",
"w = w[select]\n",
Expand All @@ -350,7 +350,7 @@
"\n",
"frame = pl.DataFrame(\n",
" {\n",
" \"α\": d2[\"θ\"].values[select],\n",
" \"α\": d2[\"θ\"].to_numpy()[select],\n",
" \"f\": w,\n",
" \"sin(α)\": sina,\n",
" \"f * sin(α)\": fsina,\n",
Expand Down Expand Up @@ -404,7 +404,7 @@
"source": [
"from scipy.stats import chi2\n",
"\n",
"d1 = load_data(\"D1\", source=\"zar\")[\"θ\"].values[:]\n",
"d1 = load_data(\"D1\", source=\"zar\")[\"θ\"].to_numpy()[:]\n",
"n = len(d1)\n",
"alpha = np.asarray(data2rad(d1, k=360))\n",
"\n",
Expand Down Expand Up @@ -491,7 +491,7 @@
}
],
"source": [
"d3 = load_data(\"D3\", source=\"zar\")[\"θ\"].values[:]\n",
"d3 = load_data(\"D3\", source=\"zar\")[\"θ\"].to_numpy()[:]\n",
"alpha = np.asarray(data2rad(d3, k=360))\n",
"alpha2 = 2 * alpha % (2 * np.pi)\n",
"sin2a = np.sin(alpha2)\n",
Expand Down Expand Up @@ -569,13 +569,13 @@
"│ --- ┆ --- ┆ --- ┆ --- ┆ --- │\n",
"│ i64 ┆ i64 ┆ f64 ┆ f64 ┆ f64 │\n",
"╞════════╪═════╪════════╪═══════════╪═══════════╡\n",
"│ 1 ┆ 160 ┆ 0.8954 ┆ -0.841401 ┆ 0.306245 │\n",
"│ 2 ┆ 169 ┆ 0.7747 ┆ -0.760467 ┆ 0.14782 │\n",
"│ 3 ┆ 117 ┆ 0.4696 ┆ -0.213194 ┆ 0.418417 │\n",
"│ 4 ┆ 140 ┆ 0.8794 ┆ -0.673659 ┆ 0.565267 │\n",
"│ 5 ┆ 186 ┆ 0.3922 ┆ -0.390051 ┆ -0.040996 │\n",
"│ 6 ┆ 134 ┆ 0.6952 ┆ -0.482926 ┆ 0.500085 │\n",
"│ 7 ┆ 171 ┆ 0.3338 ┆ -0.32969 ┆ 0.052218 │\n",
"│ 0 ┆ 160 ┆ 0.8954 ┆ -0.841401 ┆ 0.306245 │\n",
"│ 1 ┆ 169 ┆ 0.7747 ┆ -0.760467 ┆ 0.14782 │\n",
"│ 2 ┆ 117 ┆ 0.4696 ┆ -0.213194 ┆ 0.418417 │\n",
"│ 3 ┆ 140 ┆ 0.8794 ┆ -0.673659 ┆ 0.565267 │\n",
"│ 4 ┆ 186 ┆ 0.3922 ┆ -0.390051 ┆ -0.040996 │\n",
"│ 5 ┆ 134 ┆ 0.6952 ┆ -0.482926 ┆ 0.500085 │\n",
"│ 6 ┆ 171 ┆ 0.3338 ┆ -0.32969 ┆ 0.052218 │\n",
"└────────┴─────┴────────┴───────────┴───────────┘\n",
"k = 7; n = 10\n",
"∑X = -3.69139; ∑Y = 1.94906\n",
Expand All @@ -598,16 +598,16 @@
],
"source": [
"d4 = load_data(\"D4\", source=\"zar\")\n",
"ms = np.asarray(data2rad(d4[\"mean\"].values[:], k=360))\n",
"rs = d4[\"r\"].values[:]\n",
"ms = np.asarray(data2rad(d4[\"mean\"].to_numpy()[:], k=360))\n",
"rs = d4[\"r\"].to_numpy()[:]\n",
"X = rs * np.cos(ms)\n",
"Y = rs * np.sin(ms)\n",
"i = d4.index.values[:]\n",
"i = np.arange(len(d4))\n",
"\n",
"frame = pl.DataFrame(\n",
" {\n",
" \"Sample\": i,\n",
" \"μ\": d4[\"mean\"].values,\n",
" \"μ\": d4[\"mean\"].to_numpy(),\n",
" \"r\": rs,\n",
" \"X\": X,\n",
" \"Y\": Y,\n",
Expand Down Expand Up @@ -676,7 +676,7 @@
}
],
"source": [
"d1 = load_data(\"D1\", source=\"zar\")[\"θ\"].values[:]\n",
"d1 = load_data(\"D1\", source=\"zar\")[\"θ\"].to_numpy()[:]\n",
"c1 = Circular(data=d1)\n",
"\n",
"n = c1.n\n",
Expand Down Expand Up @@ -735,7 +735,7 @@
}
],
"source": [
"d7 = load_data(\"D7\", source=\"zar\")[\"θ\"].values[:]\n",
"d7 = load_data(\"D7\", source=\"zar\")[\"θ\"].to_numpy()[:]\n",
"c7 = Circular(data=d7)\n",
"\n",
"n = c7.n\n",
Expand Down Expand Up @@ -790,7 +790,7 @@
}
],
"source": [
"d7 = load_data(\"D7\", source=\"zar\")[\"θ\"].values[:]\n",
"d7 = load_data(\"D7\", source=\"zar\")[\"θ\"].to_numpy()[:]\n",
"c7 = Circular(data=d7)\n",
"\n",
"if c7.mean_lb < np.deg2rad(90) < c7.mean_ub:\n",
Expand Down Expand Up @@ -837,7 +837,7 @@
}
],
"source": [
"d8 = load_data(\"D8\", source=\"zar\")[\"θ\"].values[:]\n",
"d8 = load_data(\"D8\", source=\"zar\")[\"θ\"].to_numpy()[:]\n",
"c8 = Circular(data=d8)\n",
"alpha = c8.alpha\n",
"n = len(alpha)\n",
Expand Down Expand Up @@ -918,7 +918,7 @@
{
"data": {
"text/plain": [
"[<matplotlib.lines.Line2D at 0x11d56ee90>]"
"[<matplotlib.lines.Line2D at 0x119d45450>]"
]
},
"execution_count": 19,
Expand All @@ -937,7 +937,7 @@
}
],
"source": [
"d8 = load_data(\"D8\", source=\"zar\")[\"θ\"].values[:]\n",
"d8 = load_data(\"D8\", source=\"zar\")[\"θ\"].to_numpy()[:]\n",
"c8 = Circular(data=d8)\n",
"alpha = c8.alpha\n",
"n = len(alpha)\n",
Expand Down Expand Up @@ -987,7 +987,7 @@
"metadata": {},
"outputs": [],
"source": [
"d9 = load_data(\"D9\", source=\"zar\")[\"θ\"].values[:]\n",
"d9 = load_data(\"D9\", source=\"zar\")[\"θ\"].to_numpy()[:]\n",
"c9 = Circular(data=d9)\n",
"\n",
"med = c9.median\n",
Expand Down Expand Up @@ -1033,8 +1033,8 @@
],
"source": [
"d10 = load_data(\"D10\", source=\"zar\")\n",
"s1 = d10[d10[\"sample\"] == 1][\"θ\"].values[:]\n",
"s2 = d10[d10[\"sample\"] == 2][\"θ\"].values[:]\n",
"s1 = d10.filter(pl.col(\"sample\") == 1)[\"θ\"].to_numpy()[:]\n",
"s2 = d10.filter(pl.col(\"sample\") == 2)[\"θ\"].to_numpy()[:]\n",
"\n",
"c10_s1 = Circular(s1)\n",
"c10_s2 = Circular(s2)\n",
Expand Down Expand Up @@ -1079,9 +1079,9 @@
],
"source": [
"d11 = load_data(\"D11\", source=\"zar\")\n",
"s1 = d11[d11[\"sample\"] == 1][\"θ\"].values[:]\n",
"s2 = d11[d11[\"sample\"] == 2][\"θ\"].values[:]\n",
"s3 = d11[d11[\"sample\"] == 3][\"θ\"].values[:]\n",
"s1 = d11.filter(pl.col(\"sample\") == 1)[\"θ\"].to_numpy()[:]\n",
"s2 = d11.filter(pl.col(\"sample\") == 2)[\"θ\"].to_numpy()[:]\n",
"s3 = d11.filter(pl.col(\"sample\") == 3)[\"θ\"].to_numpy()[:]\n",
"\n",
"c11_s1 = Circular(s1)\n",
"c11_s2 = Circular(s2)\n",
Expand Down Expand Up @@ -1130,8 +1130,8 @@
"\n",
"\n",
"d12 = load_data(\"D12\", source=\"zar\")\n",
"s1 = d12[d12[\"sample\"] == 1][\"θ\"].values[:]\n",
"s2 = d12[d12[\"sample\"] == 2][\"θ\"].values[:]\n",
"s1 = d12.filter(pl.col(\"sample\") == 1)[\"θ\"].to_numpy()[:]\n",
"s2 = d12.filter(pl.col(\"sample\") == 2)[\"θ\"].to_numpy()[:]\n",
"\n",
"c12_s1 = Circular(s1)\n",
"c12_s2 = Circular(s2)\n",
Expand Down Expand Up @@ -1163,10 +1163,10 @@
"\n",
"\n",
"d13 = load_data(\"D13\", source=\"zar\")\n",
"s1 = d13[d13[\"sample\"] == 1][\"θ\"].values[:]\n",
"w1 = d13[d13[\"sample\"] == 1][\"w\"].values[:]\n",
"s2 = d13[d13[\"sample\"] == 2][\"θ\"].values[:]\n",
"w2 = d13[d13[\"sample\"] == 2][\"w\"].values[:]\n",
"s1 = d13.filter(pl.col(\"sample\") == 1)[\"θ\"].to_numpy()[:]\n",
"w1 = d13.filter(pl.col(\"sample\") == 1)[\"w\"].to_numpy()[:]\n",
"s2 = d13.filter(pl.col(\"sample\") == 2)[\"θ\"].to_numpy()[:]\n",
"w2 = d13.filter(pl.col(\"sample\") == 2)[\"w\"].to_numpy()[:]\n",
"\n",
"c13_s1 = Circular(data=s1, w=w1)\n",
"c13_s2 = Circular(data=s2, w=w2)\n",
Expand Down Expand Up @@ -1208,8 +1208,8 @@
],
"source": [
"d12 = load_data(\"D12\", source=\"zar\")\n",
"c12_s1 = Circular(data=d12[d12[\"sample\"] == 1][\"θ\"].values[:])\n",
"c12_s2 = Circular(data=d12[d12[\"sample\"] == 2][\"θ\"].values[:])\n",
"c12_s1 = Circular(data=d12.filter(pl.col(\"sample\") == 1)[\"θ\"].to_numpy()[:])\n",
"c12_s2 = Circular(data=d12.filter(pl.col(\"sample\") == 2)[\"θ\"].to_numpy()[:])\n",
"\n",
"from pycircstat2.hypothesis import wheeler_watson_test\n",
"\n",
Expand Down Expand Up @@ -1244,8 +1244,8 @@
],
"source": [
"d14 = load_data(\"D14\", source=\"zar\")\n",
"c14_s1 = Circular(data=d14[d14[\"sex\"] == \"male\"][\"θ\"].values[:])\n",
"c14_s2 = Circular(data=d14[d14[\"sex\"] == \"female\"][\"θ\"].values[:])\n",
"c14_s1 = Circular(data=d14.filter(pl.col(\"sex\") == \"male\")[\"θ\"].to_numpy()[:])\n",
"c14_s2 = Circular(data=d14.filter(pl.col(\"sex\") == \"female\")[\"θ\"].to_numpy()[:])\n",
"\n",
"from pycircstat2.hypothesis import wallraff_test\n",
"\n",
Expand Down Expand Up @@ -1281,8 +1281,8 @@
],
"source": [
"d15 = load_data(\"D15\", source=\"zar\")\n",
"s1 = time2float(d15[d15[\"sex\"] == \"male\"][\"time\"].values[:])\n",
"s2 = time2float(d15[d15[\"sex\"] == \"female\"][\"time\"].values[:])\n",
"s1 = time2float(d15.filter(pl.col(\"sex\") == \"male\")[\"time\"].to_numpy()[:])\n",
"s2 = time2float(d15.filter(pl.col(\"sex\") == \"female\")[\"time\"].to_numpy()[:])\n",
"\n",
"c15_s1 = Circular(data=s1)\n",
"c15_s2 = Circular(data=s2)\n",
Expand Down Expand Up @@ -1323,8 +1323,8 @@
"\n",
"d20 = load_data(\"D20\", source=\"zar\")\n",
"\n",
"a = Circular(data=d20[\"Insect\"].values[:])\n",
"b = Circular(data=d20[\"Light\"].values[:])\n",
"a = Circular(data=d20[\"Insect\"].to_numpy()[:])\n",
"b = Circular(data=d20[\"Light\"].to_numpy()[:])\n",
"\n",
"from pycircstat2.correlation import circ_corrcc\n",
"\n",
Expand Down Expand Up @@ -1358,8 +1358,8 @@
"source": [
"d21 = load_data(\"D21\", source=\"zar\")\n",
"\n",
"a = Circular(data=d21[\"θ\"].values[:]).alpha\n",
"x = d21[\"X\"].values[:]\n",
"a = Circular(data=d21[\"θ\"].to_numpy()[:]).alpha\n",
"x = d21[\"X\"].to_numpy()[:]\n",
"\n",
"from pycircstat2.correlation import circ_corrcl\n",
"\n",
Expand Down Expand Up @@ -1396,8 +1396,8 @@
],
"source": [
"d22 = load_data(\"D22\", source=\"zar\")\n",
"a = Circular(data=d22[\"evening\"].values[:])\n",
"b = Circular(data=d22[\"morning\"].values[:])\n",
"a = Circular(data=d22[\"evening\"].to_numpy()[:])\n",
"b = Circular(data=d22[\"morning\"].to_numpy()[:])\n",
"res = circ_corrcc(a, b, test=True, method=\"nonparametric\")\n",
"\n",
"print(f\"r = {res.r:.5f}, reject? = {res.reject_null}\")"
Expand Down Expand Up @@ -1430,7 +1430,7 @@
],
"source": [
"d2 = load_data(\"D2\", source=\"zar\")\n",
"c2 = Circular(data=d2[\"θ\"].values[:], w=d2[\"w\"].values[:])\n",
"c2 = Circular(data=d2[\"θ\"].to_numpy()[:], w=d2[\"w\"].to_numpy()[:])\n",
"\n",
"from pycircstat2.hypothesis import chisquare_test\n",
"\n",
Expand Down Expand Up @@ -1462,7 +1462,7 @@
}
],
"source": [
"d1 = load_data(\"D1\", source=\"zar\")[\"θ\"].values[:]\n",
"d1 = load_data(\"D1\", source=\"zar\")[\"θ\"].to_numpy()[:]\n",
"c1 = Circular(data=d1)\n",
"\n",
"from pycircstat2.hypothesis import watson_test\n",
Expand All @@ -1480,7 +1480,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Last updated: 2026-06-08 17:36:42 CEST\n",
"Last updated: 2026-06-09 13:17:14 CEST\n",
"\n",
"Python implementation: CPython\n",
"Python version : 3.13.11\n",
Expand Down
21 changes: 11 additions & 10 deletions examples/B3-Pewsey-2014.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
"cells": [
{
"cell_type": "code",
"execution_count": null,
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import polars as pl\n",
"import matplotlib.pyplot as plt\n",
"\n",
"from pycircstat2 import Circular, load_data"
Expand Down Expand Up @@ -53,7 +54,7 @@
}
],
"source": [
"d21 = load_data('wind', source='pewsey')['x'].values[:]\n",
"d21 = load_data('wind', source='pewsey')['x'].to_numpy()[:]\n",
"c21 = Circular(data=d21, unit='radian')\n",
"\n",
"fig, ax = plt.subplot_mosaic(mosaic=\"ab\", figsize=(12, 6), per_subplot_kw={'b': {'projection': 'polar'}})\n",
Expand Down Expand Up @@ -109,9 +110,9 @@
"source": [
"d22 = load_data('B10', source='fisher')\n",
"\n",
"c22s1 = Circular(data=d22[d22['set'] == 1]['θ'], unit='degree', )\n",
"c22s2 = Circular(data=d22[d22['set'] == 2]['θ'], unit='degree')\n",
"c22s3 = Circular(data=d22[d22['set'] == 3]['θ'], unit='degree')\n",
"c22s1 = Circular(data=d22.filter(pl.col(\"set\") == 1)['θ'], unit='degree', )\n",
"c22s2 = Circular(data=d22.filter(pl.col(\"set\") == 2)['θ'], unit='degree')\n",
"c22s3 = Circular(data=d22.filter(pl.col(\"set\") == 3)['θ'], unit='degree')\n",
"\n",
"fig, ax = plt.subplots(figsize=(5, 5), subplot_kw={'projection': 'polar'})\n",
"\n",
Expand Down Expand Up @@ -232,7 +233,7 @@
}
],
"source": [
"d21 = load_data('wind', source='pewsey')['x'].values[:]\n",
"d21 = load_data('wind', source='pewsey')['x'].to_numpy()[:]\n",
"c21 = Circular(data=d21, unit='radian')\n",
"\n",
"fig, ax = plt.subplot_mosaic(mosaic=\"ab\", figsize=(12, 6), subplot_kw={'projection': 'polar'})\n",
Expand Down Expand Up @@ -315,7 +316,7 @@
}
],
"source": [
"b11 = load_data('B11', source='fisher')[\"θ\"].values[:]\n",
"b11 = load_data('B11', source='fisher')[\"θ\"].to_numpy()[:]\n",
"c11_1 = Circular(data=b11, unit='degree', kwargs_mean_ci={\"method\": \"approximate\"})\n",
"c11_2 = Circular(data=b11*2, unit='degree', kwargs_mean_ci={\"method\": \"approximate\"})\n",
"c11_3 = Circular(data=b11*3, unit='degree', kwargs_mean_ci={\"method\": \"approximate\"})\n",
Expand Down Expand Up @@ -791,7 +792,7 @@
{
"data": {
"text/plain": [
"<matplotlib.legend.Legend at 0x11998a490>"
"<matplotlib.legend.Legend at 0x1186c4cd0>"
]
},
"execution_count": 18,
Expand Down Expand Up @@ -1125,7 +1126,7 @@
],
"source": [
"from pycircstat2.utils import time2float\n",
"d1 = time2float(load_data(\"B1\", 'fisher')['time'].values[:])\n",
"d1 = time2float(load_data(\"B1\", 'fisher')['time'].to_numpy()[:])\n",
"c1 = Circular(data=d1, unit='hour')\n",
"c1.plot(\n",
" config={\n",
Expand Down Expand Up @@ -1210,7 +1211,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Last updated: 2026-06-08 17:37:11 CEST\n",
"Last updated: 2026-06-09 13:18:33 CEST\n",
"\n",
"Python implementation: CPython\n",
"Python version : 3.13.11\n",
Expand Down
Loading
Loading