diff --git a/lectures/debugging.md b/lectures/debugging.md
new file mode 100644
index 0000000..456dd10
--- /dev/null
+++ b/lectures/debugging.md
@@ -0,0 +1,560 @@
+---
+jupytext:
+ text_representation:
+ extension: .md
+ format_name: myst
+kernelspec:
+ display_name: Python 3
+ language: python
+ name: python3
+heading-map:
+ overview: مرور کلی
+ debugging: اشکالزدایی
+ the-debug-magic: دستور جادویی `debug`
+ setting-a-break-point: تنظیم یک نقطه توقف
+ other-useful-magics: دستورات جادویی مفید دیگر
+ handling-errors: مدیریت خطاها
+ errors-in-python: خطاها در Python
+ assertions: ادعاها
+ handling-errors-during-runtime: مدیریت خطاها در حین اجرا
+ catching-exceptions: گرفتن استثناها
+ exercises: تمرینها
+---
+
+(debugging)=
+```{raw} jupyter
+
+```
+
+# اشکالزدایی و مدیریت خطاها
+
+```{index} single: Debugging
+```
+
+```{epigraph}
+"اشکالزدایی دو برابر سختتر از نوشتن کد در مرحله اول است.
+بنابراین، اگر کد را تا حد ممکن هوشمندانه بنویسید، طبق تعریف،
+به اندازه کافی باهوش نیستید که آن را اشکالزدایی کنید." -- Brian Kernighan
+```
+
+## مرور کلی
+
+آیا شما یکی از آن برنامهنویسهایی هستید که هنگام تلاش برای اشکالزدایی برنامههای خود، کد خود را پر از دستورات `print` میکنند؟
+
+هی، همه ما قبلاً این کار را میکردیم.
+
+(خوب، گاهی اوقات هنوز این کار را انجام میدهیم...)
+
+اما هنگامی که شروع به نوشتن برنامههای بزرگتر میکنید، به یک سیستم بهتر نیاز خواهید داشت.
+
+همچنین ممکن است بخواهید خطاهای احتمالی در کد خود را همانطور که رخ میدهند مدیریت کنید.
+
+در این سخنرانی، درباره چگونگی اشکالزدایی برنامههای خود و بهبود مدیریت خطاها بحث خواهیم کرد.
+
+## اشکالزدایی
+
+```{index} single: Debugging
+```
+
+ابزارهای اشکالزدایی برای Python در پلتفرمها، IDEها و ویرایشگرها متفاوت است.
+
+به عنوان مثال، یک [اشکالزدای بصری](https://jupyterlab.readthedocs.io/en/stable/user/debugger.html) در JupyterLab موجود است.
+
+در اینجا بر Jupyter Notebook تمرکز خواهیم کرد و شما را وا میگذاریم تا تنظیمات دیگر را کشف کنید.
+
+به importهای زیر نیاز خواهیم داشت
+
+```{code-cell} ipython
+import numpy as np
+import matplotlib.pyplot as plt
+```
+
+(debug_magic)=
+### دستور جادویی `debug`
+
+بیایید یک مثال ساده (و نسبتاً ساختگی) را در نظر بگیریم
+
+```{code-cell} ipython
+---
+tags: [raises-exception]
+---
+def plot_log():
+ fig, ax = plt.subplots(2, 1)
+ x = np.linspace(1, 2, 10)
+ ax.plot(x, np.log(x))
+ plt.show()
+
+plot_log() # Call the function, generate plot
+```
+
+این کد قصد دارد تابع `log` را در بازه $[1, 2]$ رسم کند.
+
+اما اینجا یک خطا وجود دارد: `plt.subplots(2, 1)` باید فقط `plt.subplots()` باشد.
+
+(فراخوانی `plt.subplots(2, 1)` یک آرایه NumPy حاوی دو شیء محور برمیگرداند که برای داشتن دو نمودار فرعی در یک شکل مناسب است)
+
+ردیابی نشان میدهد که خطا در فراخوانی متد `ax.plot(x, np.log(x))` رخ میدهد.
+
+خطا به این دلیل رخ میدهد که ما به اشتباه `ax` را یک آرایه NumPy کردهایم و یک آرایه NumPy هیچ متد `plot` ندارد.
+
+اما بیایید وانمود کنیم که در این لحظه این موضوع را نمیفهمیم.
+
+ممکن است مشکوک باشیم که مشکلی با `ax` وجود دارد اما وقتی سعی میکنیم این شیء را بررسی کنیم، استثنای زیر را دریافت میکنیم:
+
+```{code-cell} python3
+---
+tags: [raises-exception]
+---
+ax
+```
+
+مشکل این است که `ax` در داخل `plot_log()` تعریف شده است و نام
+به محض پایان یافتن آن تابع از دست میرود.
+
+بیایید آن را به روشی متفاوت امتحان کنیم.
+
+بلوک سلول اول را دوباره اجرا میکنیم و همان خطا تولید میشود
+
+```{code-cell} python3
+---
+tags: [raises-exception]
+---
+def plot_log():
+ fig, ax = plt.subplots(2, 1)
+ x = np.linspace(1, 2, 10)
+ ax.plot(x, np.log(x))
+ plt.show()
+
+plot_log() # Call the function, generate plot
+```
+
+اما این بار در بلوک سلول زیر تایپ میکنیم
+
+```{code-block} ipython
+:class: no-execute
+%debug
+```
+
+شما باید به یک پرامپت جدید منتقل شوید که چیزی شبیه این به نظر میرسد
+
+```{code-block} ipython
+:class: no-execute
+ipdb>
+```
+
+(ممکن است به جای آن pdb> ببینید)
+
+اکنون میتوانیم مقدار متغیرهای خود را در این نقطه از برنامه بررسی کنیم، از طریق کد به جلو حرکت کنیم و غیره.
+
+به عنوان مثال، در اینجا ما به سادگی نام `ax` را تایپ میکنیم تا ببینیم با
+این شیء چه اتفاقی میافتد:
+
+```{code-block} ipython
+:class: no-execute
+ipdb> ax
+array([,
+ ], dtype=object)
+```
+
+اکنون کاملاً واضح است که `ax` یک آرایه است که منبع
+مشکل را روشن میکند.
+
+برای اینکه بفهمید از داخل `ipdb` (یا `pdb`) چه کارهای دیگری میتوانید انجام دهید، از
+راهنمای آنلاین استفاده کنید
+
+```{code-block} ipython
+:class: no-execute
+ipdb> h
+
+Documented commands (type help ):
+========================================
+EOF bt cont enable jump pdef r tbreak w
+a c continue exit l pdoc restart u whatis
+alias cl d h list pinfo return unalias where
+args clear debug help n pp run unt
+b commands disable ignore next q s until
+break condition down j p quit step up
+
+Miscellaneous help topics:
+==========================
+exec pdb
+
+Undocumented commands:
+======================
+retval rv
+
+ipdb> h c
+c(ont(inue))
+Continue execution, only stop when a breakpoint is encountered.
+```
+
+### تنظیم یک نقطه توقف
+
+رویکرد قبلی مفید است اما گاهی ناکافی است.
+
+نسخه اصلاحشده زیر از تابع بالا را در نظر بگیرید
+
+```{code-cell} python3
+---
+tags: [raises-exception]
+---
+def plot_log():
+ fig, ax = plt.subplots()
+ x = np.logspace(1, 2, 10)
+ ax.plot(x, np.log(x))
+ plt.show()
+
+plot_log()
+```
+
+در اینجا مشکل اصلی برطرف شده است، اما ما به طور تصادفی
+`np.logspace(1, 2, 10)` را به جای `np.linspace(1, 2, 10)` نوشتهایم.
+
+اکنون هیچ استثنایی وجود نخواهد داشت، اما نمودار درست به نظر نمیرسد.
+
+برای بررسی، اگر بتوانیم متغیرهایی مانند `x` را در حین اجرای تابع بررسی کنیم مفید خواهد بود.
+
+برای این منظور، با قرار دادن `breakpoint()` در داخل بلوک کد تابع یک "نقطه توقف" اضافه میکنیم
+
+```{code-block} python3
+:class: no-execute
+def plot_log():
+ breakpoint()
+ fig, ax = plt.subplots()
+ x = np.logspace(1, 2, 10)
+ ax.plot(x, np.log(x))
+ plt.show()
+
+plot_log()
+```
+
+اکنون بیایید اسکریپت را اجرا کنیم و از طریق اشکالزدا بررسی کنیم
+
+```{code-block} ipython
+:class: no-execute
+> (6)plot_log()
+-> fig, ax = plt.subplots()
+(Pdb) n
+> (7)plot_log()
+-> x = np.logspace(1, 2, 10)
+(Pdb) n
+> (8)plot_log()
+-> ax.plot(x, np.log(x))
+(Pdb) x
+array([ 10. , 12.91549665, 16.68100537, 21.5443469 ,
+ 27.82559402, 35.93813664, 46.41588834, 59.94842503,
+ 77.42636827, 100. ])
+```
+
+ما دو بار از `n` برای حرکت به جلو از طریق کد (یک خط در هر زمان) استفاده کردیم.
+
+سپس مقدار `x` را چاپ کردیم تا ببینیم با آن متغیر چه اتفاقی میافتد.
+
+برای خروج از اشکالزدا، از `q` استفاده کنید.
+
+### دستورات جادویی مفید دیگر
+
+در این سخنرانی، از دستور جادویی IPython به نام `%debug` استفاده کردیم.
+
+بسیاری از دستورات جادویی مفید دیگر وجود دارند:
+
+* `%precision 4` دقت چاپ برای اعداد اعشاری را به 4 رقم اعشار تنظیم میکند
+* `%whos` فهرستی از متغیرها و مقادیر آنها را ارائه میدهد
+* `%quickref` فهرستی از دستورات جادویی را ارائه میدهد
+
+فهرست کامل دستورات جادویی [اینجا](https://ipython.readthedocs.io/en/stable/interactive/magics.html) است.
+
+
+## مدیریت خطاها
+
+```{index} single: Python; Handling Errors
+```
+
+گاهی اوقات ممکن است هنگام نوشتن کد، باگها و خطاها را پیشبینی کنیم.
+
+به عنوان مثال، واریانس نمونه بیطرفانه نمونه $y_1, \ldots, y_n$
+به صورت زیر تعریف میشود
+
+$$
+s^2 := \frac{1}{n-1} \sum_{i=1}^n (y_i - \bar y)^2
+\qquad \bar y = \text{ میانگین نمونه}
+$$
+
+این میتواند با استفاده از `np.var` در NumPy محاسبه شود.
+
+اما اگر تابعی برای انجام چنین محاسبهای مینوشتید، ممکن است
+یک خطای تقسیم بر صفر را هنگامی که اندازه نمونه یک است، پیشبینی کنید.
+
+یک اقدام ممکن این است که کاری نکنید --- برنامه فقط سقوط میکند و یک پیام خطا نمایش میدهد.
+
+اما گاهی اوقات ارزش دارد که کد خود را به گونهای بنویسید که خطاهای زمان اجرا را که فکر میکنید ممکن است رخ دهند، پیشبینی کرده و با آنها برخورد کند.
+
+چرا؟
+
+* زیرا اطلاعات اشکالزدایی ارائه شده توسط مفسر اغلب کمتر مفید از آن چیزی است که میتواند توسط یک پیام خطای خوب نوشته شده ارائه شود.
+* زیرا خطاهایی که باعث توقف اجرا میشوند، جریانهای کاری را قطع میکنند.
+* زیرا اعتماد به کد شما را از طرف کاربران (اگر برای دیگران مینویسید) کاهش میدهد.
+
+
+در این بخش، انواع مختلف خطاها در Python و تکنیکهایی برای مدیریت خطاهای احتمالی در برنامههای خود را بحث خواهیم کرد.
+
+### خطاها در Python
+
+ما `AttributeError` و `NameError` را در {any}`مثالهای قبلی خود ` دیدهایم.
+
+در Python، دو نوع خطا وجود دارد -- خطاهای نحوی و استثناها.
+
+```{index} single: Python; Exceptions
+```
+
+در اینجا مثالی از یک نوع خطای رایج آورده شده است
+
+```{code-cell} python3
+---
+tags: [raises-exception]
+---
+def f:
+```
+
+از آنجایی که نحو غیرقانونی نمیتواند اجرا شود، یک خطای نحوی اجرای برنامه را خاتمه میدهد.
+
+در اینجا نوع متفاوتی از خطا وجود دارد که به نحو مربوط نمیشود
+
+```{code-cell} python3
+---
+tags: [raises-exception]
+---
+1 / 0
+```
+
+در اینجا یکی دیگر است
+
+```{code-cell} python3
+---
+tags: [raises-exception]
+---
+x1 = y1
+```
+
+و دیگری
+
+```{code-cell} python3
+---
+tags: [raises-exception]
+---
+'foo' + 6
+```
+
+و دیگری
+
+```{code-cell} python3
+---
+tags: [raises-exception]
+---
+X = []
+x = X[0]
+```
+
+در هر مورد، مفسر ما را از نوع خطا آگاه میکند
+
+* `NameError`، `TypeError`، `IndexError`، `ZeroDivisionError` و غیره.
+
+در Python، این خطاها *استثناها* نامیده میشوند.
+
+### ادعاها
+
+```{index} single: Python; Assertions
+```
+
+گاهی اوقات خطاها را میتوان با بررسی اینکه آیا برنامه شما همانطور که انتظار میرود اجرا میشود، از آنها جلوگیری کرد.
+
+یک روش نسبتاً آسان برای مدیریت بررسیها با کلمه کلیدی `assert` است.
+
+به عنوان مثال، برای یک لحظه وانمود کنید که تابع `np.var` وجود
+ندارد و ما باید خودمان آن را بنویسیم
+
+```{code-cell} python3
+def var(y):
+ n = len(y)
+ assert n > 1, 'Sample size must be greater than one.'
+ return np.sum((y - y.mean())**2) / float(n-1)
+```
+
+اگر این را با یک آرایه با طول یک اجرا کنیم، برنامه خاتمه مییابد و
+پیام خطای ما را چاپ میکند
+
+```{code-cell} python3
+---
+tags: [raises-exception]
+---
+var([1])
+```
+
+مزیت این است که میتوانیم
+
+* زودتر شکست بخوریم، به محض اینکه میدانیم مشکلی وجود دارد
+* اطلاعات خاصی در مورد اینکه چرا یک برنامه در حال شکست است ارائه دهیم
+
+### مدیریت خطاها در حین اجرا
+
+```{index} single: Python; Runtime Errors
+```
+
+رویکرد استفاده شده در بالا کمی محدود است، زیرا همیشه منجر به
+خاتمه میشود.
+
+گاهی اوقات میتوانیم خطاها را با ظرافت بیشتری، با رفتار با موارد خاص، مدیریت کنیم.
+
+بیایید ببینیم چگونه این کار انجام میشود.
+
+#### گرفتن استثناها
+
+میتوانیم استثناها را با استفاده از بلوکهای `try` -- `except` بگیریم و با آنها برخورد کنیم.
+
+در اینجا یک مثال ساده است
+
+```{code-cell} python3
+def f(x):
+ try:
+ return 1.0 / x
+ except ZeroDivisionError:
+ print('Error: division by zero. Returned None')
+ return None
+```
+
+وقتی `f` را فراخوانی میکنیم خروجی زیر را دریافت میکنیم
+
+```{code-cell} python3
+f(2)
+```
+
+```{code-cell} python3
+f(0)
+```
+
+```{code-cell} python3
+f(0.0)
+```
+
+خطا گرفته میشود و اجرای برنامه خاتمه نمییابد.
+
+توجه کنید که انواع خطاهای دیگر گرفته نمیشوند.
+
+اگر نگران هستیم که کاربر ممکن است یک رشته را پاس دهد، میتوانیم آن خطا را نیز بگیریم
+
+```{code-cell} python3
+def f(x):
+ try:
+ return 1.0 / x
+ except ZeroDivisionError:
+ print('Error: Division by zero. Returned None')
+ except TypeError:
+ print(f'Error: x cannot be of type {type(x)}. Returned None')
+ return None
+```
+
+در اینجا اتفاقی که میافتد
+
+```{code-cell} python3
+f(2)
+```
+
+```{code-cell} python3
+f(0)
+```
+
+```{code-cell} python3
+f('foo')
+```
+
+اگر احساس تنبلی میکنیم میتوانیم این خطاها را با هم بگیریم
+
+```{code-cell} python3
+def f(x):
+ try:
+ return 1.0 / x
+ except:
+ print(f'Error. An issue has occurred with x = {x} of type: {type(x)}')
+ return None
+```
+
+در اینجا اتفاقی که میافتد
+
+```{code-cell} python3
+f(2)
+```
+
+```{code-cell} python3
+f(0)
+```
+
+```{code-cell} python3
+f('foo')
+```
+
+به طور کلی بهتر است خاص باشید.
+
+
+## تمرینها
+
+```{exercise-start}
+:label: debug_ex1
+```
+
+فرض کنید ما یک فایل متنی `numbers.txt` داریم که شامل خطوط زیر است
+
+```{code-block} none
+:class: no-execute
+
+prices
+3
+8
+
+7
+21
+```
+
+با استفاده از `try` -- `except`، برنامهای بنویسید که محتویات فایل را بخواند و اعداد را جمع کند، خطوط بدون عدد را نادیده بگیرید.
+
+میتوانید از تابع `open()` که {any}`قبلاً` یاد گرفتیم برای باز کردن `numbers.txt` استفاده کنید.
+```{exercise-end}
+```
+
+
+```{solution-start} debug_ex1
+:class: dropdown
+```
+
+بیایید ابتدا داده را ذخیره کنیم
+
+```{code-cell} python3
+%%file numbers.txt
+prices
+3
+8
+
+7
+21
+```
+
+```{code-cell} python3
+f = open('numbers.txt')
+
+total = 0.0
+for line in f:
+ try:
+ total += float(line)
+ except ValueError:
+ pass
+
+f.close()
+
+print(total)
+```
+
+```{solution-end}
+```
\ No newline at end of file