diff --git a/.gitignore b/.gitignore index 075b254..dfec022 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /.quarto/ +users.txt \ No newline at end of file diff --git a/_site/module-1/slides/3-python-basics.html b/_site/module-1/slides/3-python-basics.html index 555d6e3..08afe63 100644 --- a/_site/module-1/slides/3-python-basics.html +++ b/_site/module-1/slides/3-python-basics.html @@ -579,6 +579,19 @@

Using both types of Quotation marks

variable_b = 'I would like to show you "this"' +
+

f-strings

+ +
+
+
f_string.py
+
+
age = 25
+print(f"The patient's age is : { age }")
+
+

Indentation

+
+

Comments

+ +
+
+
docstrings.py
+
+
def i_am_function(args1, args2):
+    """A concise title
+
+    A description of the function.
+
+    Args:
+        args1: I am the first argument to the function.
+        args2: I am the second argument to the function.
+    Returns:
+        x: the addition of the 2 provided arguments.
+    """
+
+    x = args1 + args2
+    
+    return x
@@ -717,16 +757,16 @@

Control flow - if statements

if_statement.py
-
patient_allergy = "amoxicillin"
-
-if patient_allergy == "amoxicillin":
-    allergy_group = "penicillins"
-elif patient_allergy == "tazocin":
-    allergy_group = "penicillins"
-else:
-    allergy_group = "others"
-
-print("Patient is allergic to", allergy_group)
+
patient_allergy = "amoxicillin"
+
+if patient_allergy == "amoxicillin":
+    allergy_group = "penicillins"
+elif patient_allergy == "tazocin":
+    allergy_group = "penicillins"
+else:
+    allergy_group = "others"
+
+print("Patient is allergic to", allergy_group)

Output

    Patient is allergic to penicillins
@@ -737,10 +777,10 @@

Control flow - for loops

for_loop.py
-
list_of_numbers = [1, 2, 3, 4, 5]
-
-for number in list_of_numbers:
-    print(number)
+
list_of_numbers = [1, 2, 3, 4, 5]
+
+for number in list_of_numbers:
+    print(number)

Output

    1
@@ -755,11 +795,11 @@ 

Control flow - while loops

while_loop.py
-
count = 1
-
-while count <= 5:
-    print(count)
-    count += 1
+
count = 1
+
+while count <= 5:
+    print(count)
+    count += 1

Output

    1
@@ -783,13 +823,13 @@ 

Functions (methods)

functions.py
-
def name_of_function(argument_1, argument_2):
-    a_variable = argument_1 + argument_2
-    another_variable = "a return value"
-
-    print (a_variable)
-
-    return another_variable
+
def name_of_function(argument_1, argument_2):
+    a_variable = argument_1 + argument_2
+    another_variable = "a return value"
+
+    print (a_variable)
+
+    return another_variable
@@ -825,12 +865,12 @@

Error Handling

functions.py
-
try:
-    variable = 1 + "a"
-except:
-    print("I knew that you could not add an integer and a string!")
-else:
-    print("Somehow I did not get an error!")
+
try:
+    variable = 1 + "a"
+except:
+    print("I knew that you could not add an integer and a string!")
+else:
+    print("Somehow I did not get an error!")

Output

    I knew that you could not add an integer and a string!
@@ -872,20 +912,20 @@

Compare the Traceback to the code

functions.py
-
class FruitPrices:
-    def __init__(self):
-        self.prices = {"apple": 1.55, "banana": 2.44}
-
-    def get_price(self, fruit):
-        return self._price(fruit)
-
-    def _price(self, fruit):
-        return self.prices[fruit]
-
-
-fruit_prices = FruitPrices()
-
-print(fruit_prices.get_price("pear")) # 'pear' key does not exist!
+
class FruitPrices:
+    def __init__(self):
+        self.prices = {"apple": 1.55, "banana": 2.44}
+
+    def get_price(self, fruit):
+        return self._price(fruit)
+
+    def _price(self, fruit):
+        return self.prices[fruit]
+
+
+fruit_prices = FruitPrices()
+
+print(fruit_prices.get_price("pear")) # 'pear' key does not exist!
diff --git a/_site/search.json b/_site/search.json index d60c6d7..cb1993c 100644 --- a/_site/search.json +++ b/_site/search.json @@ -964,5 +964,19 @@ "title": "Python basics", "section": "Comments", "text": "Comments\n\nComments are useful in explaining what code is supposed to do.\nThey are essential for when you, and others, need to read your code later to problem solve or add to your code.\nUse them sparingly, as they can clutter code.\nTry and make variable and function names self explanatory.\nYou can comment with the hastag or encapsulate with triple quotation marks:\n\n\n\ncomments.py\n\n# This is a single line comment\na_string = \"a string\"\n\n\"\"\" Double quotation mark multiline comment\n Here is some more of the comment\n\"\"\"\ndef i_am_a_function():\n return True\n\n''' Single quotation mark multiline comment\n Here is some more of the comment\n'''\ndef i_am_another_function():\n return True" + }, + { + "objectID": "module-1/slides/3-python-basics.html#f-strings", + "href": "module-1/slides/3-python-basics.html#f-strings", + "title": "Python basics", + "section": "f-strings", + "text": "f-strings\n\nUserful to know\n\n\n\nf_string.py\n\nage = 25\nprint(f\"The patient's age is : { age }\")" + }, + { + "objectID": "module-1/slides/3-python-basics.html#comments-1", + "href": "module-1/slides/3-python-basics.html#comments-1", + "title": "Python basics", + "section": "Comments", + "text": "Comments\n\nYou will also come across something called docstrings. These are basically comments associated with functions / methods and classes.\nYou will see them associated with modules (at the top of files).\n\n\n\ndocstrings.py\n\ndef i_am_function(args1, args2):\n \"\"\"A concise title\n\n A description of the function.\n\n Args:\n args1: I am the first argument to the function.\n args2: I am the second argument to the function.\n Returns:\n x: the addition of the 2 provided arguments.\n \"\"\"\n\n x = args1 + args2\n \n return x" } ] \ No newline at end of file diff --git a/create_user_folders.py b/create_user_folders.py new file mode 100644 index 0000000..dfe9aa2 --- /dev/null +++ b/create_user_folders.py @@ -0,0 +1,31 @@ +import shutil +from pathlib import Path + + +def create_user_folders() -> None: + """Creates user folders with module materials + + For all the names in the 'user.txt' file, creates a new folder in the user + folder with the user's name. The modules folder is then copied across. If the + users folder already exists, then no new folder is created or files / folders + copied across. + """ + with open("users.txt", "r") as file: + for line in file: + username = line.strip() + username = username.replace(" ", "_") + folder_path = Path("users") / username + if folder_path.exists(): + print(f"The folder {folder_path} already exists.") + else: + folder_path.mkdir(parents=True) + print(f"The folder {folder_path} has been created.") + shutil.copytree( + Path("modules"), folder_path, dirs_exist_ok=True + ) + + return + + +if __name__ == "__main__": + create_user_folders() diff --git a/module-1/hands-on/lesson_3.py b/module-1/hands-on/lesson_3.py deleted file mode 100644 index f836005..0000000 --- a/module-1/hands-on/lesson_3.py +++ /dev/null @@ -1,69 +0,0 @@ -"""Lesson 3 - -Let's build an app. Some useful link - -https://pathlabs.rlbuht.nhs.uk/eGFRcalculator.htm -https://www.nhs.uk/conditions/kidney-disease/diagnosis/ -""" - -import streamlit as st - -"""Exercise 1 - 'Hello world!' web app style! -Run the app using the command: -$ streamlit run lesson_3.py -""" - - -"""def main(): - st.write(f"Hello world!") - return - - -if __name__ == "__main__": - main()""" - -"""Exercise 2 -1. Comment out the above code. -2. Uncomment the code below -3. Follow the steps below -""" - -""" -# Write a function named 'calculate_egfr'. -# Define a variable in this function called egfr and set it to '45'. -# Have this function return egfr. - - -def main(): - # Call the 'calculate_egfr' function above - # Print the returned value to the browser - return - - -if __name__ == "__main__": - main() - -# Run the above code and see if you have the nubmer 45 in the browser window -""" - -"""Exercise 3 -1. Comment out the above code. -2. Uncomment the code below -3. Follow the steps below -""" - - -# Add arguements 'creatinine, age, gender, race' to function below -def calculate_egf(): - egfr = 45 - return egfr - - -def main(): - egfr = calculate_egf() - st.write(f"{egfr}") - return - - -if __name__ == "__main__": - main() diff --git a/module-1/hands-on/.streamlit/config.toml b/modules/module-1/hands-on/.streamlit/config.toml similarity index 87% rename from module-1/hands-on/.streamlit/config.toml rename to modules/module-1/hands-on/.streamlit/config.toml index ca2fcae..e2349d6 100644 --- a/module-1/hands-on/.streamlit/config.toml +++ b/modules/module-1/hands-on/.streamlit/config.toml @@ -3,7 +3,6 @@ primaryColor="#F63366" backgroundColor="#FFFFFF" secondaryBackgroundColor="#F0F2F6" textColor="#000000" -codeColor="#000000" [runner] magicEnabled = false \ No newline at end of file diff --git a/module-1/hands-on/answers/__init__.py b/modules/module-1/hands-on/answers/__init__.py similarity index 100% rename from module-1/hands-on/answers/__init__.py rename to modules/module-1/hands-on/answers/__init__.py diff --git a/module-1/hands-on/answers/lesson_2_anwers.py b/modules/module-1/hands-on/answers/lesson_2_anwers.py similarity index 100% rename from module-1/hands-on/answers/lesson_2_anwers.py rename to modules/module-1/hands-on/answers/lesson_2_anwers.py diff --git a/module-1/hands-on/answers/lesson_3_answers.py b/modules/module-1/hands-on/answers/lesson_3_answers.py similarity index 98% rename from module-1/hands-on/answers/lesson_3_answers.py rename to modules/module-1/hands-on/answers/lesson_3_answers.py index 9994871..69d1519 100644 --- a/module-1/hands-on/answers/lesson_3_answers.py +++ b/modules/module-1/hands-on/answers/lesson_3_answers.py @@ -39,14 +39,14 @@ def calculate_egfr(creatinine, age, gender, race): "Invalid race. Please specify 'Afro-Caribbean' or 'other'." ) - eGFR = ( + egfr = ( 175 * ((creatinine * 0.011312) ** (-1.154)) * (age ** (-0.203)) * gender_factor * race_factor ) - return int(eGFR) + return int(egfr) def get_ckd_stage(egfr): @@ -91,10 +91,12 @@ def main(): except Exception as e: st.write(f"Awaiting appropriate inputs") else: - ckd_stage = get_ckd_stage(egfr) st.write(f"eGFR: { egfr }") + ckd_stage = get_ckd_stage(egfr) st.write(f"CKD stage { ckd_stage }") + return + if __name__ == "__main__": main() diff --git a/module-1/hands-on/lesson_1.py b/modules/module-1/hands-on/lesson_1.py similarity index 100% rename from module-1/hands-on/lesson_1.py rename to modules/module-1/hands-on/lesson_1.py diff --git a/module-1/hands-on/lesson_2.py b/modules/module-1/hands-on/lesson_2.py similarity index 100% rename from module-1/hands-on/lesson_2.py rename to modules/module-1/hands-on/lesson_2.py diff --git a/modules/module-1/hands-on/lesson_3.py b/modules/module-1/hands-on/lesson_3.py new file mode 100644 index 0000000..84d275b --- /dev/null +++ b/modules/module-1/hands-on/lesson_3.py @@ -0,0 +1,446 @@ +"""Lesson 3 + +Let's build a clinical web app. Some useful links: + +https://pathlabs.rlbuht.nhs.uk/eGFRcalculator.htm +https://www.nhs.uk/conditions/kidney-disease/diagnosis/ +""" + +import streamlit as st + +"""Exercise 1 - 'Hello world!' web app style! +Run the app using the command: +$ streamlit run lesson_3.py +""" + + +def main(): + st.title("My first web app") + st.write("Hello world!") + return + + +if __name__ == "__main__": + main() + +"""Exercise 2 - Creating your first function +1. Comment out the above code. +2. Uncomment the code below +3. Follow the steps below +""" + +""" +# Write a function named 'calculate_egfr'. +# Define a variable in this function called egfr and set it to '45'. +# Have this function return egfr. + + +def main(): + # Call the 'calculate_egfr' function above + # Print the returned value to the browser + return + + +if __name__ == "__main__": + main() + +# Run the above code and see if you have the nubmer 45 in the browser window +""" + +"""Exercise 3 - time for some arguments +1. Comment out the above code. +2. Uncomment the code below +3. Follow the steps below +""" + +""" +# Add arguements 'creatinine, age, gender, race' to function below +def calculate_egf(): + egfr = 45 + return # Return a string with 'creatinine, age, gender, race and egfr' + + +def main(): + st.title("eGFR calculator") + # Create variables 'creatinine, age, gender, race' with some initial values. + # Pass arguements 'creatinine, age, gender, race' to the function call below. + return_string = calculate_egf() + st.write(f"{ return_string }") + return + + +if __name__ == "__main__": + main() + +# Run the above code and make see if all 'creatinine, age, gender, race and egfr' are in the browser. + +""" + + +"""Exercise 4 - you like maths right? +1. Comment out the above code. +2. Uncomment the code below +3. Follow the steps below + +You will be using the below equation for calculating the eGFR: + +eGFR = 175 * ((creatinine × 0.011312) ^ (-1.154)) x (age ^ (-0.203)) + x (0.742 if female) x (1.212 if Afro-Caribbean) +""" + +""" +def calculate_egf(creatinine, age, gender, race): + # Calculate a 'gender_factor' which is 1 for 'Males' and 0.742 for 'Females' + # If gender is not "Male" or "Female" (python is capitalisation sensitive) + # then raise an error with: + # raise ValueError ("Your error message") + + # Calculate a 'race_factor' which is 1.212 for 'Afro-Caribbean' and 1 for 'other' + # If race is not "Afro-Caribbean" or "other" (python is capitalisation sensitive) + # then raise an error with: + # raise ValueError ("Your error message") + + # Calculate eGFR using the equation mentioned above + egfr = 0 + + # Return egfr as an integer (hint use 'int(variable)') + return egfr + + +def main(): + st.title("eGFR calculator") + creatinine = 110 + age = 55 + gender = "Male" + race = "Afro-Caribbean" + egfr = calculate_egf(creatinine, age, gender, race) + st.write(f"{ egfr }") + return + + +if __name__ == "__main__": + main() + +# Run the above code and make see if a sensible eGFR is displayed in the browser. +""" + +"""Exercise 5 - time for some input! +1. Comment out the above code. +2. Uncomment the code below +3. Follow the steps below +""" + +""" +def calculate_egf(creatinine, age, gender, race): + if gender == "Male": + gender_factor = 1 + elif gender == "Female": + gender_factor = 0.742 + else: + raise ValueError( + "Invalid gender. Please specify 'Male' for male or 'Female' for female." + ) + + if race == "Afro-Caribbean": + race_factor = 1.212 + elif race == "other": + race_factor = 1 + else: + raise ValueError( + "Invalid race. Please specify 'Afro-Caribbean' or 'other'." + ) + + egfr = ( + 175 + * ((creatinine * 0.011312) ** (-1.154)) + * (age ** (-0.203)) + * gender_factor + * race_factor + ) + return int(egfr) + + +def main(): + st.title("eGFR calculator") + # Convert 'creatinine and age' into input fields for the web browser. + # Hint: use 'variable_name = st.number_input("Display name:", step=1)'. + creatinine = 110 + age = 55 + # Convert 'gender and race' into selection fields for the web browser. + # Hint: use 'variable_name = st.selectbox("Display name:", ["", "option 1", "option 2"])'. + gender = "Male" + race = "Afro-Caribbean" + egfr = calculate_egf(creatinine, age, gender, race) + st.write(f"{ egfr }") + return + + +if __name__ == "__main__": + main() + +# Run the above code and make see if a sensible eGFR is displayed in the browser. +# If you get errors in the terminal and the browse, do not worry, we will fix +# these in the next exercise. +""" + +"""Exercise 6 - errors, you should sort them out! +1. Comment out the above code. +2. Uncomment the code below +3. Follow the steps below +""" + +""" +def calculate_egf(creatinine, age, gender, race): + if gender == "Male": + gender_factor = 1 + elif gender == "Female": + gender_factor = 0.742 + else: + raise ValueError( + "Invalid gender. Please specify 'Male' for male or 'Female' for female." + ) + + if race == "Afro-Caribbean": + race_factor = 1.212 + elif race == "other": + race_factor = 1 + else: + raise ValueError( + "Invalid race. Please specify 'Afro-Caribbean' or 'other'." + ) + + egfr = ( + 175 + * ((creatinine * 0.011312) ** (-1.154)) + * (age ** (-0.203)) + * gender_factor + * race_factor + ) + return int(egfr) + + +def main(): + st.title("eGFR calculator") + + creatinine = st.number_input("Creatinine:", step=1) + age = st.number_input("Age:", step=1) + gender = st.selectbox("Gender:", ["", "Male", "Female"]) + race = st.selectbox("Gender:", ["", "Afro-Caribbean", "other"]) + + # You now need to handle the exceptions caused by erroneous input variables, + # eg 'creatinine, age, gender, race'. + # You do this with the 'try, except, else' exception handlers. + # With the except clause, you should display an appropriate message to the + # Browser. + egfr = calculate_egf(creatinine, age, gender, race) + st.write(f"{ egfr }") + return + + +if __name__ == "__main__": + main() + +# Run the above code and make see if a sensible eGFR is displayed in the browser. +""" + +"""Exercise 7 - don't forget about the stages! +1. Comment out the above code. +2. Uncomment the code below +3. Follow the steps below +""" + +""" +def calculate_egfr(creatinine, age, gender, race): + if gender == "Male": + gender_factor = 1 + elif gender == "Female": + gender_factor = 0.742 + else: + raise ValueError( + "Invalid gender. Please specify 'Male' for male or 'Female' for female." + ) + + if race == "Afro-Caribbean": + race_factor = 1.212 + elif race == "other": + race_factor = 1 + else: + raise ValueError( + "Invalid race. Please specify 'Afro-Caribbean' or 'other'." + ) + + egfr = ( + 175 + * ((creatinine * 0.011312) ** (-1.154)) + * (age ** (-0.203)) + * gender_factor + * race_factor + ) + return int(egfr) + + +# Create a function that takes in the argument eGFR and returns the CKD stage. +# See 'https://www.nhs.uk/conditions/kidney-disease/diagnosis/' for these stages. + + +def main(): + st.title("eGFR calculator") + + creatinine = st.number_input("Creatinine:", step=1) + age = st.number_input("Age:", step=1) + gender = st.selectbox("Gender:", ["", "Male", "Female"]) + race = st.selectbox("Gender:", ["", "Afro-Caribbean", "other"]) + + try: + egfr = calculate_egfr(creatinine, age, gender, race) + except Exception as e: + st.write(f"Awaiting appropriate inputs") + else: + st.write(f"eGFR: { egfr }") + # call the ckd stage function and print to the browser the CKD stage. + return + + +if __name__ == "__main__": + main() + +# Run the above code and make see if a sensible eGFR is displayed in the browser. +""" + +"""Exercise 8 - finished product! +1. Comment out the above code. +2. Uncomment the code below. +3. Below is the final app in working form with added docstring comments. +""" + +''' +def calculate_egfr(creatinine, age, gender, race): + if gender == "Male": + gender_factor = 1 + elif gender == "Female": + gender_factor = 0.742 + else: + raise ValueError( + "Invalid gender. Please specify 'Male' for male or 'Female' for female." + ) + + if race == "Afro-Caribbean": + race_factor = 1.212 + elif race == "other": + race_factor = 1 + else: + raise ValueError( + "Invalid race. Please specify 'Afro-Caribbean' or 'other'." + ) + + egfr = ( + 175 + * ((creatinine * 0.011312) ** (-1.154)) + * (age ** (-0.203)) + * gender_factor + * race_factor + ) + return int(egfr) + + +# Create a function that takes in as an argument the eGFR and returns the CKD +# stage. See 'https://www.nhs.uk/conditions/kidney-disease/diagnosis/' for +# these stages. + + +def calculate_egfr(creatinine, age, gender, race): + """Calculate eGFR + + Calculate estimated glomerular filtration rate (eGFR) using serum creatinine levels, + age, gender, and race. + + Formula (for adults): eGFR = 175 * ((creatinine × 0.011312) ^ (-1.154)) x (age ^ (-0.203)) + x (0.742 if female) x (1.212 if Afro-Caribbean) + Args: + creatinine: Serum creatinine level (mg/dL) + age: Age of the patient + gender: Gender of the patient (Male, Female) + race: Race of the patient (Afro-Caribbean or other) + Returns: + float: Estimated glomerular filtration rate (eGFR) + """ + if gender == "Male": + gender_factor = 1 + elif gender == "Female": + gender_factor = 0.742 + else: + raise ValueError( + "Invalid gender. Please specify 'Male' for male or 'Female' for female." + ) + + if race == "Afro-Caribbean": + race_factor = 1.212 + elif race == "other": + race_factor = 1 + else: + raise ValueError( + "Invalid race. Please specify 'Afro-Caribbean' or 'other'." + ) + + egfr = ( + 175 + * ((creatinine * 0.011312) ** (-1.154)) + * (age ** (-0.203)) + * gender_factor + * race_factor + ) + return int(egfr) + + +def get_ckd_stage(egfr): + """Get CKD stage + + Determine the stage of chronic kidney disease (CKD) based on estimated glomerular filtration rate (eGFR). + + Args: + egfr: Estimated glomerular filtration rate (eGFR) + + Returns: + str: CKD stage + """ + if egfr > 90: + return "1" + elif 60 <= egfr <= 89: + return "2" + elif 45 <= egfr <= 59: + return "3a" + elif 30 <= egfr <= 44: + return "3b" + elif 15 <= egfr <= 29: + return "4" + else: + return "5" + + +def main(): + """The main Streamlit code + + Runs the Streamlit web app + """ + st.title("eGFR calculator") + + creatinine = st.number_input("Creatinine:", step=1) + age = st.number_input("Age:", step=1) + gender = st.selectbox("Gender:", ["", "Male", "Female"]) + race = st.selectbox("Gender:", ["", "Afro-Caribbean", "other"]) + + try: + egfr = calculate_egfr(creatinine, age, gender, race) + except Exception as e: + st.write(f"Awaiting appropriate inputs") + else: + st.write(f"eGFR: { egfr }") + ckd_stage = get_ckd_stage(egfr) + st.write(f"CKD stage { ckd_stage }") + + return + + +if __name__ == "__main__": + main() +''' diff --git a/module-1/index.qmd b/modules/module-1/index.qmd similarity index 100% rename from module-1/index.qmd rename to modules/module-1/index.qmd diff --git a/module-1/slides/1-introduction.qmd b/modules/module-1/slides/1-introduction.qmd similarity index 100% rename from module-1/slides/1-introduction.qmd rename to modules/module-1/slides/1-introduction.qmd diff --git a/module-1/slides/2-the-shell.qmd b/modules/module-1/slides/2-the-shell.qmd similarity index 100% rename from module-1/slides/2-the-shell.qmd rename to modules/module-1/slides/2-the-shell.qmd diff --git a/module-1/slides/3-python-basics.qmd b/modules/module-1/slides/3-python-basics.qmd similarity index 94% rename from module-1/slides/3-python-basics.qmd rename to modules/module-1/slides/3-python-basics.qmd index df043dc..d6d60bc 100644 --- a/module-1/slides/3-python-basics.qmd +++ b/modules/module-1/slides/3-python-basics.qmd @@ -147,6 +147,15 @@ variable_a = "I want to highlight 'this' word" variable_b = 'I would like to show you "this"' ``` +## f-strings + +* Userful to know + +```{.python filename="f_string.py"} +age = 25 +print(f"The patient's age is : { age }") +``` + ## Indentation * Python is extremely sensitive to indentation. One extra space or tab in front of a line of code (an expression) and you will not hear the end of it in terms of errors or strange results. Indentation (in the form of `tabs`) of expressions shows the computer which previous expression it relates to. @@ -233,6 +242,30 @@ def i_am_another_function(): return True ``` +## Comments + +* You will also come across something called docstrings. These are basically comments associated with functions / methods and classes. +* You will see them associated with modules (at the top of files). + +```{.python filename="docstrings.py"} +def i_am_function(args1, args2): + """A concise title + + A description of the function. + + Args: + args1: I am the first argument to the function. + args2: I am the second argument to the function. + Returns: + x: the addition of the 2 provided arguments. + """ + + x = args1 + args2 + + return x +``` + + ## Basic Operators * Operators manipulate and compare data (which are stored in variables). Operator types include: diff --git a/module-1/slides/4-lets-build.qmd b/modules/module-1/slides/4-lets-build.qmd similarity index 100% rename from module-1/slides/4-lets-build.qmd rename to modules/module-1/slides/4-lets-build.qmd