Skip to content
Snippets Groups Projects
Commit db978268 authored by Philip J Clark's avatar Philip J Clark
Browse files

Added Learn ultra quiz links, updated CP4 a bit and added link to new lecture01 recording

parent effb536a
No related branches found
No related tags found
No related merge requests found
%% Cell type:markdown id:57457292 tags:
# Checkpoint 4 OR Step-by-step guide to Writing a Computer Program
# Checkpoint 4 Step-by-step guide to Writing a Computer Program
This checkpoint is different from the others to give you a break. You just have to work through it and make sure you understand and can run it. Then ask a demonstrator to check you off when you have completed it.
## The problem
We want to write a program to display trignometric functions (sin, cos, tan, cot) and their first derivatives over their fundamental periods. The user should be allowed to choose interactively which function to plot.
## First steps
Before writing any computer code, it is worth first thinking about how the logic of our program should work.
For this task, one may do the following:
- Prompt the user to choose between sin/cos/tan/cot
- For the function the user has chosen, determine fundamental period.
- For the chosen function, calculate derivative.
- Plot chosen function and derivative.
The logic of this whole program will look as below:
```python
1. User chooses function, and we assign a value to each choice: sin=1, cos=2, tan=3, cot=4.
2. Calculation and Plotting
if user chose 1:
determine fundamental period of sin(x)
cos(x) is derivative of sin(x)
plot sin(x) and cos(x) over the fundamental period
else if user chose 2:
determine fundamental period of cos(x)
-sin(x) is derivative of cos(x)
plot cos(x) and -sin(x) over the fundamental period
else if user chose 3:
determine fundamental period of tan(x)
1/cos^2(x) is derivative of tan(x) #we worked out math separately
plot tan(x) and 1/cos^2(x) over the fundamental period
else: #this is the only possible remaining option for the user, that is to choose 4
determine fundamental period of cot(x)
-1/sin^2(x) is derivative of cot(x) [we worked out math separately]
plot cot(x) and -1/sin^2(x) over the fundamental period
3. Done!
````
>***Note***: For more complex programs it is worth doing this structure pen-and-paper before starting to write down any code in ```Python```. This style is called ***writing in pseudocode***, that is a universally understandable human-readable version of the logic of the program. There is an entire field called algorithmics which deals with this!
Let us now attempt to implement the above algorithm in ```Python```, below:
%% Cell type:code id:2da1b363 tags:
``` python
# Import necessary libraries and make our axes fonts and labels bold for a visually pleasing plot
import numpy as np
from matplotlib import pyplot as plt
plt.rcParams["font.weight"] = "bold"
plt.rcParams["axes.labelweight"] = "bold"
# Allow user to choose which function to plot and also print a short description of what the program aims to achieve
print("This is a short program to calculate and plot sin/cos/tan/cot and their derivatives over the fundamental period. \n")
user_choice = int(input("Please select your desired function: \n 1. sin(x) \n 2. cos(x) \n 3. tan(x) \n 4. cot(x) \n User choice: "))
# Calculate and plot
# Choice of sin
if user_choice == 1:
# Determine fundamental period of sin(x)
period = np.arange(0, 2*np.pi, 0.001)
# Calculate sin(x) over the period
function = np.sin(period)
# Calculate derivative over the period
derivative = np.cos(period)
# Plot the results
plt.figure(figsize=(10,6))
plt.plot(period, function, label='sin(x)')
plt.plot(period, derivative, label='cos(x)')
plt.title("sin(x) and its derivative", fontsize='large', fontweight='bold') # Add title/lables
plt.xlabel("Angle (radians)")
plt.ylabel("f(x)")
plt.legend()
plt.grid()
plt.show()
# Choice of cos
elif user_choice == 2:
# Determine fundamental period of cos(x)
period = np.arange(0, 2*np.pi, 0.001)
# Calculate cos(x) over the period
function = np.cos(period)
# Calculate derivative over the period
derivative = -np.sin(period)
# Plot the results
plt.figure(figsize=(10,6))
plt.plot(period, function, label='cos(x)')
plt.plot(period, derivative, label='-sin(x)')
plt.title("cos(x) and its derivative", fontsize='large', fontweight='bold') # Add title/lables
plt.xlabel("Angle (radians)")
plt.ylabel("f(x)")
plt.legend()
plt.grid()
plt.show()
#Choice of tan
elif user_choice == 3:
# Determine fundamental period of tan(x) [note this is different from that of sin & cos]
period = np.arange(0, np.pi, 0.001)
# Calculate tan(x) over the period
function = np.tan(period)
# Calculate derivative over the period
derivative = 1/np.cos(period)**2
# Plot the results
plt.figure(figsize=(10,6))
plt.plot(period, function, label='tan(x)')
plt.plot(period, derivative, label='1/cos^2(x)')
plt.title("tan(x) and its derivative", fontsize='large', fontweight='bold') # Add title/lables
plt.xlabel("Angle (radians)")
plt.ylabel("f(x)")
plt.ylim([-10,10]) # Note tan has a discontinuity, so in order for
# the plot to look meaningful, we restrict the plotting range for the y-axis
plt.legend()
plt.grid()
plt.show()
#Choice of cot
else:
# Determine fundamental period of cot(x) [note this is different from that of sin & cos]
period = np.arange(0, np.pi, 0.001)
# Calculate cos(x) over the period
function = 1 / np.tan(period) # Note NumPy does not have a cot function, but it is just 1/tan
# Calculate derivative over the period
derivative = - 1/np.sin(period)**2
# Plot the results
plt.figure(figsize=(10,6))
plt.plot(period, function, label='cot(x)')
plt.plot(period, derivative, label='-1/sin^2(x)')
plt.title("cot(x) and its derivative", fontsize='large', fontweight='bold') # Add title/lables
plt.xlabel("Angle (radians)")
plt.ylabel("f(x)")
plt.ylim([-10,10]) # Note cot has a discontinuity, so in order for
# the plot to look meaningful, we restrict the plotting range for the y-axis
plt.legend()
plt.grid()
plt.show()
```
%% Output
This is a short program to calculate and plot sin/cos/tan/cot and their derivatives over the fundamental period.
Please select your desired function:
1. sin(x)
2. cos(x)
3. tan(x)
4. cot(x)
User choice: 1
%% Cell type:markdown id:004db4eb tags:
## Some afterthoughts
Our program uses the simplest possible logic to perform the required tasks, without much thought. There are of course ways to optimise this, and so reduce the amount of code needed. However, this way of doing things gives one a very good and practical example of ***code reusability***, that is copy-pasting a part of code several times and only needing to perform minor alterations to change the results.
> Our program above has a **small bug**, which a user can easily detect while playing with the program. You should always be careful about situations like this, as any program should be bug-free, which is especially important given that some bugs can actually cause the program to halt and so fail to fulfil its intended purpose.
Let us attempt below some minor changes to our code, that aim to achieve 2 things:
1. Reduce the amount of code and make it more efficient.
2. Eliminate the annoying bug.
%% Cell type:code id:5fe8788b tags:
``` python
# Import necessary libraries and make our axes fonts and labels bold for a visually pleasing plot
import numpy as np
from matplotlib import pyplot as plt
plt.rcParams["font.weight"] = "bold"
plt.rcParams["axes.labelweight"] = "bold"
# Allow user to choose which function to plot and also print a short description of what the program aims to achieve
print("This is a short program to calculate and plot sin/cos/tan/cot and their derivatives over the fundamental period. \n")
user_choice = int(input("Please select your desired function: \n 1. sin(x) \n 2. cos(x) \n 3. tan(x) \n 4. cot(x) \n User choice: "))
# Calculate and plot
# Choice of sin
if user_choice == 1:
# Determine fundamental period of sin(x)
period = np.arange(0, 2*np.pi, 0.001)
# Calculate sin(x) over the period
function = np.sin(period)
# Calculate derivative over the period
derivative = np.cos(period)
#Define labels and bounds to use for plotting
fn_label = "sin(x)"
deriv_label = "cos(x)"
y_bound = 1.1
# Choice of cos
elif user_choice == 2:
# Determine fundamental period of cos(x)
period = np.arange(0, 2*np.pi, 0.001)
# Calculate cos(x) over the period
function = np.cos(period)
# Calculate derivative over the period
derivative = -np.sin(period)
#Define labels and bounds to use for plotting
fn_label = "cos(x)"
deriv_label = "-sin(x)"
y_bound = 1.1
#Choice of tan
elif user_choice == 3:
# Determine fundamental period of tan(x) [note this is different from that of sin & cos]
period = np.arange(0, np.pi, 0.001)
# Calculate tan(x) over the period
function = np.tan(period)
# Calculate derivative over the period
derivative = 1/np.cos(period)**2
#Define labels and bounds to use for plotting
fn_label = "tan(x)"
deriv_label = "1/cos^2(x)"
y_bound = 10
#Choice of cot
else:
# Determine fundamental period of cot(x) [note this is different from that of sin & cos]
period = np.arange(0.001, np.pi, 0.001)
# Calculate cos(x) over the period
function = 1 / np.tan(period) # Note NumPy does not have a cot function, but it is just 1/tan
# Calculate derivative over the period
derivative = - 1/np.sin(period)**2
#Define labels and bounds to use for plotting
fn_label = "cot(x)"
deriv_label = "-1/sin^2(x)"
y_bound = 10
# Plot the results
plt.figure(figsize=(10,6))
plt.plot(period, function, label=fn_label)
plt.plot(period, derivative, label=deriv_label)
title_choice = fn_label + " and its derivative" #Build the title of the plot to match the chosen function
plt.title(title_choice, fontsize='large', fontweight='bold') # Add title/lables
plt.xlabel("Angle (radians)")
plt.ylabel("f(x)")
plt.ylim([-y_bound, y_bound])
plt.legend()
plt.grid()
plt.show()
```
%% Output
This is a short program to calculate and plot sin/cos/tan/cot and their derivatives over the fundamental period.
Please select your desired function:
1. sin(x)
2. cos(x)
3. tan(x)
4. cot(x)
User choice: 4
%% Cell type:markdown id:66c48d22 tags:
## More afterthoughts
Now we seem to have removed the bug that existed (so one aim is checked - ***please read carefully the 2 codes to see the difference***) and have also reduced the amount of code that needed writing. We achieved the latter by decoupling the calculation and the plotting of the results, having devised a way in which the calculations produce standardised outputs that can then be used in a general way to plot them irrespective of the user's choice.
Let us try now to improve the code even further, trying both to reduce the written amount and to make it (slightly) more efficient and general.
%% Cell type:code id:fea833cb tags:
``` python
# Import necessary libraries and make our axes fonts and labels bold for a visually pleasing plot
import numpy as np
from matplotlib import pyplot as plt
plt.rcParams["font.weight"] = "bold"
plt.rcParams["axes.labelweight"] = "bold"
# Allow user to choose which function to plot and also print a short description of what the program aims to achieve
print("This is a short program to calculate and plot sin/cos/tan/cot and their derivatives over the fundamental period. \n")
user_choice = int(input("Please select your desired function: \n 1. sin(x) \n 2. cos(x) \n 3. tan(x) \n 4. cot(x) \n User choice: "))
#Define matching labels and bounds to use for plotting
fn_label = ["sin(x)","cos(x)","tan(x)","cot(x)"]
deriv_label = ["cos(x)","-sin(x)","1/cos^2(x)","-1/sin^2(x)"]
y_bound = [1.1, 1.1, 10, 10]
title_choice = fn_label[user_choice-1] + " and its derivative" #Build the title of the plot to match the chosen function
# Define appropriate periods and calculate functions and matching derivatives
periods = [np.arange(0, 2*np.pi, 0.001), np.arange(0, 2*np.pi, 0.001), np.arange(0, np.pi, 0.001), np.arange(0.001, np.pi, 0.001)]
functions = [lambda x: np.sin(x),lambda x: np.cos(x),lambda x: np.tan(x),lambda x: 1/np.tan(x)]
derivs = [lambda x: np.cos(x), lambda x: -np.sin(x), lambda x: 1/np.cos(x)**2, lambda x: -1/np.sin(x)**2]
# Calculate for the user's choice (note array are numbered 0-> n-1, while user has a choice of 1->n)
period = periods[user_choice-1]
function = functions[user_choice-1](period)
derivative = derivs[user_choice-1](period)
# Plot the results
plt.figure(figsize=(10,6))
plt.plot(period, function, label=fn_label[user_choice-1])
plt.plot(period, derivative, label=deriv_label[user_choice-1])
plt.title(title_choice, fontsize='large', fontweight='bold') # Add title/lables
plt.xlabel("Angle (radians)")
plt.ylabel("f(x)")
plt.ylim([-y_bound[user_choice-1], y_bound[user_choice-1]])
plt.legend()
plt.grid()
plt.show()
```
%% Output
This is a short program to calculate and plot sin/cos/tan/cot and their derivatives over the fundamental period.
Please select your desired function:
1. sin(x)
2. cos(x)
3. tan(x)
4. cot(x)
User choice: 4
%% Cell type:markdown id:c4a0e13b tags:
## Final thoughts
In the final code example above, we made use of the fact that the program has a very rigid structure. This begins from the limited user choice, and the fact that each choice is independent of others, which can allow us to produce matching arrays that make use of anonymous functions to calculate the desired function and its derivative and plot the result. You will see more detailed examples of all the concepts used in this section as you advance through the course.
> Please note that the final code is significantly less human-friendly than the very first iteration we tried, and this is to be expected. **Programming is generally not a linear process**, and one never aims to write the final version of a code on the first try. It is best practice to adopt a trial and error approach (which most programmers do), where you interatively improve on the code, rather then hope to produce the final version from the first attempt. This practice also turns out to be significantly faster and more efficient than the alternatives.
### Next steps
Once you have completed this checkpoint, please continue with the [Week4](../WeeklyTasks/Week4.ipynb) tasklist.
1. Make sure you have fully understood all of the above (that is all you have to do for this checkpoint).
2. Get Checkpoint 4 checked off by a TA.
3. Please continue with the [Week4](../WeeklyTasks/Week4.ipynb) tasklist.
%% Cell type:code id:63a15de4 tags:
``` python
```
......
No preview for this file type
%% Cell type:markdown id: tags:
# Before Course Starts
Welcome to Scientific Programming! This course aims to provide a gentle introduction to `Python` programming, making use of Jupyter notebooks.
## Expectations
The course is designed as an introduction to `Python` programming assumming no prior experience of programming whatsoever.
The assessment is performed through a series of checkpoints. For some checkpoints you will need to write the entire code from scratch (or may have some comments to help you structure your program). For others you will be given a working part of the final code needed, with gaps for you to fill in (which will be denoted in the code cells by `...` - the gaps most often will need to be filled with several lines of code, not just the line where the dots are present).
The total amount of work expected for this course (equivalent to the number of credits awarded for the successful completion of it) is **100 hours**, out of which about **3 x 7 = 21 hours** will be spent in in-class **workshops**, and the **rest (~80 hours)** are to be used for **individual study**.
***Note: It is not feasible to expect to parse and complete the entire course material exclusively during the allocated in-class workshops.***
For more information about the course, please watch the following online mini-lecture:
- [SciProg - L01 - Introduction and course structure (video)](https://ed-ac-uk.zoom.us/rec/share/zOy03-qGQiinUqbrxFLDvytIvqRvhl7vnh1sq29zMD0tXhtyZkMcPLLtfK3F208n.D_fLStkzPUU6xdx6)
- [SciProg - L01 - Introduction and course structure (pdf)](../Slides/sciprog-L01-introduction.pdf)
## No Requirements
This course is designed so that it can be performed entirely within your browser, not needing any local installation of Python or any other programming environments. This also means that it can be performed on any platform (Windows, Linux-based, MacOS, Chromebook), though access to a keyboard is highly beneficial.
By design, you will not need to worry about losing your computer or deleting files by mistake, as your progress throughout the course will be safely saved in the cloud.
In order to achieve this, we will be using the [Noteable](https://noteable.edina.ac.uk) service developed here, at the University of Edinburgh. This will provide a central server (and kernel) for Python, and so a medium upon which we can perform the actual programming, exclusively within Jupyter Notebooks.
**When you do checkpoints please first rename the checkpoint notebook which contains your solutions as CheckpointN_YourUUN, eg. Checkpoint1_s1234567**.
This is to avoid them being possibly overwritten by mistake and to allow us to distribute extra information if needed.
> It is worth (for offline use and for the future) to download and install [Anaconda](https://www.anaconda.com) on your personal computer so that you will always have access to a Python + JupyterLab environment (this will also be useful for future courses where Jupyter notebooks will be used). Please do this **now**!
> Once installed, you can open the Jupyter-notebook server (that looks just like the server in Noteable on which the current course runs) by searching for ***jupyter-notebook*** in your computer's applications or by typing ***jupyter-notebook*** into a terminal window of your operating system. More information can be found in the links at the bottom of this page.
## Jupyter Notebooks
Jupyter Notebooks are the most widely used means of communicating and performing interactive computing. In a notebook, you can blend computations and their outputs with explanatory text, mathematics and images.
> We think there is value in practising what you teach, so accordingly this entire course is written and delivered entirely within **Jupyter notebooks**!
The notebooks consist of cells, of which there are 2 types:
- ***Code cells*** that allow you to type Python code, perform calculations, plotting and anything you may want
- ***Markdown cells*** that enable you to type in Markdown format blocks of text, equations (using LaTeX style), include links and images
You will see the different types of cells and their usage all throughout the course, as the course notes comprise both *Markdown cells* explaining different concepts in programming, physics and mathematics, as well as *Code cells* that can be executed in-place, interactively, so you can see what exactly specific bits of code produce as an output.
## Questionnaire
Please complete the [Start of Course Questionnaire in Learn](https://www.learn.ed.ac.uk/ultra/courses/_108405_1/outline/assessment/_9437648_1/overview?courseId=_108405_1)
Please complete the [Start of Course Questionnaire in Learn](https://www.learn.ed.ac.uk/ultra/courses/_117833_1/outline/assessment/_10718488_1/overview?)
You are now ready to move on to [Week 1](Week1.ipynb) and begin the actual course! Have fun!
## Additional Information
If you are so-inclined, more information about the infrastructure and philosophy of Jupyter can be found directly at the source, [Jupyter.org](https://jupyter.org/try-jupyter/retro/notebooks/?path=notebooks/Intro.ipynb).
For a quick, simple guide to the Jupyter environment you can consult [Datacamp](https://www.datacamp.com/tutorial/tutorial-jupyter-notebook).
%% Cell type:markdown id: tags:
......
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"tags": [
......@@ -104,7 +103,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.16"
"version": "3.9.17"
}
},
"nbformat": 4,
......
%% Cell type:markdown id: tags:
# Week Two
## Online mini-lecture
Please watch the following online mini-lecture:
- [SciProg - L02 - Adding Structure using functions (video)](https://ed-ac-uk.zoom.us/rec/share/4KGc7RWfsL0k8k7JxI5jyiVBdf_eMGDxdry5jsz3xpvPu6EReL9BO74TlKh5qcDR.aXNq9P93PsIvzhWb?startTime=1663587375000)
- [SciProg - L02 - Adding Structure using functions (pdf)](../Slides/sciprog-L02-structure.pdf)
## Course notes
Study the following sections of the course notes before your workshop session:
- [Random Numbers](../CourseNotes/random.ipynb)
- [Basic Functions](../CourseNotes/basicfunctions.ipynb)
- [Conditionals](../CourseNotes/conditionalstatements.ipynb)
## Multiple choice questions
Ensure you have completed the on-line quiz [MCQ Test 1](https://www.learn.ed.ac.uk/ultra/courses/_108405_1/outline/assessment/_9430135_1/overview?courseId=_108405_1)
Ensure you have completed the on-line quiz [MCQ Test 1](https://www.learn.ed.ac.uk/ultra/courses/_117833_1/outline/assessment/_10718497_1/overview?)
## Workshop
In the workshop you should:
1. Work through the example codes in the Functions and Conditionals folders and ensure they work and that you understand them.
2. Do [Checkpoint 2](../Checkpoints/Checkpoint2.ipynb)
3. Have Checkpoint 2 assessed and checked off by a TA.
## To do next
<!---
The tasks to do next are:
1. Complete the on-line [MCQ Test 2](https://www.learn.ed.ac.uk/ultra/courses/_108405_1/outline/assessment/_9430146_1/overview?courseId=_108405_1) in Learn.
2. Please watch the following online mini-lecture:
- [SciProg - L03 - Flow control (video)](https://ed-ac-uk.zoom.us/rec/share/x2cCNw9WJeqtHWRFv57sC1r1QWD4ikzFXM6o7HsyuWQwfLHDFM1VlnzuEPJt5WMZ.5LUDLkNm0irxWxLA?startTime=1663591435000)
- [SciProg - L03 - Flow control (pdf)](../Slides/sciprog-L03-flow-control.pdf)
3. Pre-read the following sections of the notes:
>- [Lists](../CourseNotes/simplelists.ipynb)
>- [Loops](../CourseNotes/loops.ipynb)
>- [Plotting](../CourseNotes/plotting.ipynb)
4. Explore the code example themes ***Lists***, ***Loops*** and ***Plotting*** from [here](../CodeExamples/CodeExamples.ipynb).
5.
-->
Continue your journey through this course by looking at [Week 3](Week3.ipynb).
%% Cell type:code id: tags:
``` python
```
......
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
......@@ -55,7 +54,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
......@@ -69,7 +68,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.10"
"version": "3.9.17"
}
},
"nbformat": 4,
......
%% Cell type:markdown id: tags:
# Week Five
## Online mini-lecture
Please watch the following online mini-lecture:
- [SciProg - L05 - Functions and Lists (video)](https://ed-ac-uk.zoom.us/rec/share/ckl9Gj8YuPVbaC2dXCjEJA9wVaARETkvP53NE1ivr_s_R2ZKntu-Rpb3bzWTgOkI.mSWzj2ScX9GJPZ99?startTime=1663597243000)
- [SciProg - L05 - Functions and Lists (pdf)](../Slides/sciprog-L05-functions-lists.pdf)
## Course notes
Study the following sections of the course notes before your workshop session:
- [More Functions](../CourseNotes/MoreFunctions.ipynb)
- [Functions and Lists](../CourseNotes/FunctionsAndLists.ipynb)
- Preread [Checkpoint 5](../Checkpoints/Checkpoint5.ipynb) and in particular the suggested code structure in the Hint.
## Multiple choice questions
Ensure you have completed the on-line quiz FOUR.
Ensure you have completed the on-line quiz [MCQ Test 4](https://www.learn.ed.ac.uk/ultra/courses/_117833_1/outline/assessment/_10718529_1/overview?)
## Workshop
In the workshop you should:
1. Work through the example codes in Further Functions and make sure you understand them. If you have time look at those in More Complex.
2. Do [Checkpoint 5](../Checkpoints/Checkpoint5.ipynb). Check carefully that you have the correct structure for checkpoint 5 in the Hint and also think carefully what you need to store in lists.
3. Have Checkpoint 5 assessed and checked off by a TA.
## Do before next week
<!---
The tasks do to before the next session are:
1. Complete the on-line [MCQ Test 5](https://www.learn.ed.ac.uk/ultra/courses/_108405_1/outline/assessment/_9430171_1/overview?courseId=_108405_1)
2. Please watch the following online mini-lecture:
- [SciProg - L06 - More advanced python (video)](https://ed-ac-uk.zoom.us/rec/share/vXCNX_qCmIMJgrBboGOGmyhNixP1CnPDzbf4KnltD9bt_n2GQWWJFQ2Q0qSKzexz.-CDImVCmIaYjwilk?startTime=1663597908000)
- [SciProg - L06 - More advanced python (pdf)](../Slides/sciprog-L06-more-python.pdf)
3. Read the following sections of the notes:
>- [Scope of Variables](../CourseNotes/Scope.ipynb)
>- [Lambda Functions](../CourseNotes/lambda.ipynb)
>- [Map and Zip](../CourseNotes/AdvancedListProcessing.ipynb)
>- [Objects](../CourseNotes/ObjectsandOOP.ipynb)
4. Explore the code example themes ***More Complex***, ***Scope*** and ***Objects*** from [here](../CodeExamples/CodeExamples.ipynb).
5.
-->
Continue your journey through this course by looking at [Week 6](Week6.ipynb).
%% Cell type:code id: tags:
``` python
```
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment