diff --git a/.gitignore b/.gitignore
index 2c338fe..365f9fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -358,3 +358,5 @@ NuGet.config
# MacOS files
.DS_Store
**/.trydotnet-builderror
+
+.ipynb_checkpoints/
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..07bb640
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,76 @@
+FROM jupyter/scipy-notebook:latest
+
+# Install .NET CLI dependencies
+
+ARG NB_USER=jovyan
+ARG NB_UID=1000
+ENV USER ${NB_USER}
+ENV NB_UID ${NB_UID}
+ENV HOME /home/${NB_USER}
+
+WORKDIR ${HOME}
+
+USER root
+RUN apt-get update
+RUN apt-get install -y curl
+
+# Install .NET CLI dependencies
+RUN apt-get install -y --no-install-recommends \
+ libc6 \
+ libgcc1 \
+ libgssapi-krb5-2 \
+ libicu60 \
+ libssl1.1 \
+ libstdc++6 \
+ zlib1g
+
+RUN rm -rf /var/lib/apt/lists/*
+
+# Install .NET Core SDK
+
+# When updating the SDK version, the sha512 value a few lines down must also be updated.
+ENV DOTNET_SDK_VERSION 3.1.200
+
+RUN curl -SL --output dotnet.tar.gz https://dotnetcli.blob.core.windows.net/dotnet/Sdk/$DOTNET_SDK_VERSION/dotnet-sdk-$DOTNET_SDK_VERSION-linux-x64.tar.gz \
+ && dotnet_sha512='5b9398c7bfe7f67cd9f38fdd4e6e429e1b6aaac0fe04672be0f8dca26580fb46906fd1d2deea6a7d3fb07d77e898f067d3ac1805fe077dc7c1adf9515c9bc9a9' \
+ && echo "$dotnet_sha512 dotnet.tar.gz" | sha512sum -c - \
+ && mkdir -p /usr/share/dotnet \
+ && tar -zxf dotnet.tar.gz -C /usr/share/dotnet \
+ && rm dotnet.tar.gz \
+ && ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet
+
+# Enable detection of running in a container
+ENV DOTNET_RUNNING_IN_CONTAINER=true \
+ # Enable correct mode for dotnet watch (only mode supported in a container)
+ DOTNET_USE_POLLING_FILE_WATCHER=true \
+ # Skip extraction of XML docs - generally not useful within an image/container - helps performance
+ NUGET_XMLDOC_MODE=skip \
+ # Opt out of telemetry until after we install jupyter when building the image, this prevents caching of machine id
+ DOTNET_TRY_CLI_TELEMETRY_OPTOUT=true
+
+# Copy notebooks
+COPY ./notebooks/ ${HOME}/Notebooks/
+
+# Copy package sources
+COPY ./NuGet.config ${HOME}/nuget.config
+
+RUN chown -R ${NB_UID} ${HOME}
+USER ${USER}
+
+#Install nteract
+RUN pip install nteract_on_jupyter
+
+# Install lastest build from master branch of Microsoft.DotNet.Interactive from myget
+RUN dotnet tool install -g Microsoft.dotnet-interactive --version 1.0.126104 --add-source "https://dotnet.myget.org/F/dotnet-try/api/v3/index.json"
+
+ENV PATH="${PATH}:${HOME}/.dotnet/tools"
+RUN echo "$PATH"
+
+# Install kernel specs
+RUN dotnet interactive jupyter install
+
+# Enable telemetry once we install jupyter for the image
+ENV DOTNET_TRY_CLI_TELEMETRY_OPTOUT=false
+
+# Set root to Notebooks
+WORKDIR ${HOME}/Notebooks/
diff --git a/NuGet.config b/NuGet.config
new file mode 100644
index 0000000..bdff66c
--- /dev/null
+++ b/NuGet.config
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/notebooks/hello-csharp/branches-and-loops.ipynb b/notebooks/hello-csharp/branches-and-loops.ipynb
new file mode 100644
index 0000000..a304210
--- /dev/null
+++ b/notebooks/hello-csharp/branches-and-loops.ipynb
@@ -0,0 +1,369 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Learn conditional logic with branch and loop statements\n",
+ "\n",
+ "*In this tutorial about branches and loops, you'll use Jupyter notebooks to learn C# interactively. You'll write C# code and see the results of compiling and running your code directly.*\n",
+ "\n",
+ "This tutorial contains a series of lessons that explore branching and looping constructs in C#. These lessons teach you the fundamentals of the C# language.\n",
+ "\n",
+ "## Make decisions using the if statement\n",
+ "\n",
+ "Run the following cell:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "int a = 5;\n",
+ "int b = 6;\n",
+ "if (a + b > 10)\n",
+ " Console.WriteLine(\"The answer is greater than 10.\");"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Modify the declaration of `b` so that the sum is less than 10: `int b = 3;`\n",
+ "\n",
+ "Run the cell again. Because the answer is less than 10, nothing is printed. The **condition** you're testing is false. You don't have any code to execute because you've only written one of the possible branches for an `if` statement: the true branch. Try again with `int b = 15`.\n",
+ "\n",
+ "> As you explore C# (or any programming language), you'll make mistakes when you write code. The **compiler** will find those errors and report them to you. When the output contains error messages, look closely at the example code, and the code in the interactive window to see what to fix. That exercise will help you learn the structure of C# code.\n",
+ "\n",
+ "This first sample shows the power of `if` and boolean types. A *boolean* is a variable that can have one of two values: `true` or `false`. C# defines a special type, `bool` for boolean variables. The `if` statement checks the value of a `bool`. When the value is `true`, the statement following the `if` executes. Otherwise, it is skipped.\n",
+ "\n",
+ "This process of checking conditions and executing statements based on those conditions is very powerful. Let's explore more.\n",
+ "\n",
+ "## Make if and else work together\n",
+ "\n",
+ "To execute different code in both the true and false branches, you create an `else` branch that executes when the condition is false. Try this:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "int a = 5;\n",
+ "int b = 3;\n",
+ "if (a + b > 10)\n",
+ " Console.WriteLine(\"The answer is greater than 10\");\n",
+ "else\n",
+ " Console.WriteLine(\"The answer is not greater than 10\");"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The statement following the `else` keyword executes only when the condition being tested is `false`. Combining `if` and `else` with boolean conditions provides all the power you need.\n",
+ "\n",
+ "> The indentation under the `if` and `else` statements is for human readers. The C# language doesn't treat indentation or white space as significant. The statement following the `if` or `else` keyword will be executed based on the condition. All the samples in this tutorial follow a common practice to indent lines based on the control flow of statements.\n",
+ "\n",
+ "Because indentation is not significant, you need to use `{` and `}` to indicate when you want more than one statement to be part of the block\n",
+ "that executes conditionally. C# programmers typically use those braces on all `if` and `else` clauses. The following example is the same as what you\n",
+ "just created. Try it."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "int a = 5;\n",
+ "int b = 3;\n",
+ "if (a + b > 10)\n",
+ "{\n",
+ " Console.WriteLine(\"The answer is greater than 10\");\n",
+ "}\n",
+ "else\n",
+ "{\n",
+ " Console.WriteLine(\"The answer is not greater than 10\");\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "> Through the rest of this tutorial, the code samples all include the braces, following accepted practices.\n",
+ "\n",
+ "You can test more complicated conditions:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "int a = 5;\n",
+ "int b = 3;\n",
+ "int c = 4;\n",
+ "if ((a + b + c > 10) && (a == b))\n",
+ "{\n",
+ " Console.WriteLine(\"The answer is greater than 10\");\n",
+ " Console.WriteLine(\"And the first number is equal to the second\");\n",
+ "}\n",
+ "else\n",
+ "{\n",
+ " Console.WriteLine(\"The answer is not greater than 10\");\n",
+ " Console.WriteLine(\"Or the first number is not equal to the second\");\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The `==` symbol tests for *equality*. Using `==` distinguishes the test for equality from assignment, which you saw in `a = 5`.\n",
+ "\n",
+ "The `&&` represents \"and\". It means both conditions must be true to execute the statement in the true branch. These examples also show that you can have multiple\n",
+ "statements in each conditional branch, provided you enclose them in `{` and `}`.\n",
+ " \n",
+ "You can also use `||` to represent \"or\":"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "int a = 5;\n",
+ "int b = 3;\n",
+ "int c = 4;\n",
+ "if ((a + b + c > 10) || (a == b))\n",
+ "{\n",
+ " Console.WriteLine(\"The answer is greater than 10\");\n",
+ " Console.WriteLine(\"Or the first number is equal to the second\");\n",
+ "}\n",
+ "else\n",
+ "{\n",
+ " Console.WriteLine(\"The answer is not greater than 10\");\n",
+ " Console.WriteLine(\"And the first number is not equal to the second\");\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Modify the values of `a`, `b`, and `c` and switch between `&&` and `||` to explore. You'll gain more understanding of how the `&&` and `||` operators work.\n",
+ "\n",
+ "## Use loops to repeat operations\n",
+ "\n",
+ "Another important concept to create larger programs is **loops**. You'll\n",
+ "use loops to repeat statements that you want executed more than once. Try\n",
+ "this code:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "int counter = 0;\n",
+ "while (counter < 10)\n",
+ "{\n",
+ " Console.WriteLine($\"Hello World! The counter is {counter}\");\n",
+ " counter++;\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The `while` statement checks a condition and executes the statement following the `while`. It will repeat checking the condition and executing those statements until the condition is false.\n",
+ "\n",
+ "There's one other new operator in this example. The `++` after the `counter` variable is the **increment** operator. It adds 1 to the value of counter, and stores that value in the counter variable.\n",
+ "\n",
+ "> Make sure that the `while` loop condition does switch to false as you execute the code. Otherwise, you create an **infinite loop** where your program never ends. Let's not demonstrate that, because the engine that runs your code will time out and you'll see no output from your program.\n",
+ "\n",
+ "The `while` loop tests the condition before executing the code following the `while`. The `do` ... `while` loop executes the code first, and then checks the condition. It looks like this:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "int counter = 0;\n",
+ "do\n",
+ "{\n",
+ " Console.WriteLine($\"Hello World! The counter is {counter}\");\n",
+ " counter++;\n",
+ "} while (counter < 10);"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This `do` loop and the earlier `while` loop work the same.\n",
+ "\n",
+ "Let's move on to one last loop statement.\n",
+ "\n",
+ "## Work with the for loop\n",
+ "\n",
+ "Another common loop statement that you'll see in C# code is the `for` loop. Try this code in the interactive window:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for(int counter = 0; counter < 10; counter++)\n",
+ "{\n",
+ " Console.WriteLine($\"Hello World! The counter is {counter}\");\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This does the same work as the `while` loop and the `do` loop you've already used. The `for` statement has three parts that control how it works.\n",
+ "\n",
+ "The first part is the **for initializer**: `int counter = 0;` declares that `counter` is the loop variable, and sets its initial value to `0`.\n",
+ "\n",
+ "The middle part is the **for condition**: `counter < 10` declares that this `for` loop continues to execute as long as the value of counter is less than 10.\n",
+ "\n",
+ "The final part is the **for iterator**: `counter++` specifies how to modify the loop variable after executing the block following the `for` statement. Here, it specifies that `counter` should be incremented by 1 each time the block executes.\n",
+ "\n",
+ "Experiment with these yourself. Try each of the following:\n",
+ "\n",
+ "- Change the initializer to start at a different value.\n",
+ "- Change the condition to stop at a different value.\n",
+ "\n",
+ "When you're done, let's move on to write some code yourself to\n",
+ "use what you've learned.\n",
+ "\n",
+ "## Created nested loops\n",
+ "\n",
+ "A `while`, `do` or `for` loop can be nested inside another loop to create a matrix using the combination of each item in the outer loop with each item in the inner loop. Let's do that to build a set of alphanumeric pairs to represent rows and columns.\n",
+ "\n",
+ "One `for` loop can generate the rows:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for (int row = 1; row < 11; row++)\n",
+ "{\n",
+ " Console.WriteLine($\"The row is {row}\");\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Another loop can generate the columns:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for (char column = 'a'; column < 'k'; column++)\n",
+ "{\n",
+ " Console.WriteLine($\"The column is {column}\");\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can nest one loop inside the other to form pairs:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for (int row = 1; row < 11; row++)\n",
+ "{\n",
+ " for (char column = 'a'; column < 'k'; column++)\n",
+ " {\n",
+ " Console.Write($\"({row}, {column}) \");\n",
+ " }\n",
+ " Console.WriteLine();\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can see that the outer loop increments once for each full run of the\n",
+ "inner loop. Reverse the row and column nesting, and see the changes for yourself.\n",
+ "\n",
+ "## Combine branches and loops\n",
+ "\n",
+ "Now that you've seen the `if` statement and the looping\n",
+ "constructs in the C# language, see if you can write C# code to\n",
+ "find the sum of all integers 1 through 20 that are divisible\n",
+ "by 3. Here are a few hints:\n",
+ "\n",
+ "- The `%` operator gives you the remainder of a division operation.\n",
+ "- The `if` statement gives you the condition to see if a number should be part of the sum.\n",
+ "- The `for` loop can help you repeat a series of steps for all the numbers 1 through 20.\n",
+ "\n",
+ "Try it yourself. Then check how you did. As a hint, you should get 63 for an answer."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "When you're ready, you can explore the [list collection](list-collection.ipynb)."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": ".NET (C#)",
+ "language": "C#",
+ "name": ".net-csharp"
+ },
+ "language_info": {
+ "file_extension": ".cs",
+ "mimetype": "text/x-csharp",
+ "name": "C#",
+ "pygments_lexer": "csharp",
+ "version": "8.0"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/notebooks/hello-csharp/hello-world.ipynb b/notebooks/hello-csharp/hello-world.ipynb
new file mode 100644
index 0000000..11f90c8
--- /dev/null
+++ b/notebooks/hello-csharp/hello-world.ipynb
@@ -0,0 +1,191 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Hello World - Introduction to C# interactive tutorial\n",
+ "\n",
+ "*In this tutorial, you'll use Jupyter notebooks to learn C# interactively. You write C# code and see the results of compiling and running your code directly in the notebook.*\n",
+ "\n",
+ "It contains a series of lessons that begin with a \"Hello World\" program. These lessons teach you the fundamentals of the C# language.\n",
+ "\n",
+ "## Run your first C# program\n",
+ "\n",
+ "Run the following cell:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "Console.WriteLine(\"Hello World!\");"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "Congratulations! You've run your first C# program. It's a simple program that prints the message \"Hello World!\". It used the `System.Console.WriteLine` method to print that message. `Console` is a type that represents the console window. `WriteLine` is a method of the `Console` type that prints a line of text to that text console.\n",
+ "\n",
+ "Let's move on and explore more. The rest of this lesson explores working with the `string` type, which represents text in C#. Like the `Console` type, the `string` type has methods. The `string` methods work with text.\n",
+ "\n",
+ "## Declare and use variables\n",
+ "\n",
+ "Your first program printed the `string` \"Hello World!\" on the screen.\n",
+ "\n",
+ "> As you explore C# (or any programming language), you'll make mistakes when you write code. The **compiler** will find those errors and report them to you. When the output contains error messages, look closely at the example code, and the code in the interactive window to see what to fix. That exercise will help you learn the structure of C# code.\n",
+ "\n",
+ "The first cell prints message. You can write more useful programs by using **variables**. A **variable** is a symbol you can\n",
+ "use to run the same code with different values. Let's try it! Execute the following cell:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "string aFriend = \"Bill\";\n",
+ "Console.WriteLine(aFriend);"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The first line declares a variable, `aFriend` and assigns it a value, \"Bill\". The second line rints out the name.\n",
+ "\n",
+ "You can assign different values to any variable you declare. You can change the name to one of your friends. Add these two lines in the above cell after the code you've already added:\n",
+ "\n",
+ "```csharp\n",
+ "aFriend = \"Maira\";\n",
+ "Console.WriteLine(aFriend);\n",
+ "```\n",
+ "\n",
+ "Notice that the same line of code prints two different messages, based on the value stored in the `aFriend` variable. You may have also noticed that the word \"Hello\" was missing in the last two messages. Let's fix that now. Modify the lines that print the message to the following, and run the cells:\n",
+ "\n",
+ "```csharp\n",
+ "Console.WriteLine(\"Hello \" + aFriend);\n",
+ "```\n",
+ "\n",
+ "You've been using `+` to build strings from **variables** and **constant** strings. There's a better way. You can place a variable between `{` and `}` characters to tell C# to replace that text with the value of the variable. This is called *String interpolation*.\n",
+ "\n",
+ "If you add a `$` before the opening quote of the string, you can then include variables, like `aFriend`, inside the string between curly braces. Give it a try:\n",
+ "\n",
+ "```csharp\n",
+ "Console.WriteLine($\"Hello {aFriend}\");\n",
+ "```\n",
+ "\n",
+ "## Do more with strings\n",
+ "\n",
+ "You've been using a **method**, `System.Console.WriteLine`, to print messages. A **method** is a block of code that implements some action. It has a name, so you can access it.\n",
+ "\n",
+ "Suppose your strings have leading or trailing spaces that you don't want to display. You want to **trim** the spaces from the strings.\n",
+ "The `System.String.Trim` method and related methods `System.String.TrimStart` and `System.String.TrimEnd` do that work. You can just use those methods to remove leading and trailing spaces. Try the following cell:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "string greeting = \" Hello World! \";\n",
+ "Console.WriteLine($\"[{greeting}]\");\n",
+ "\n",
+ "string trimmedGreeting = greeting.TrimStart();\n",
+ "Console.WriteLine($\"[{trimmedGreeting}]\");\n",
+ "\n",
+ "trimmedGreeting = greeting.TrimEnd();\n",
+ "Console.WriteLine($\"[{trimmedGreeting}]\");\n",
+ "\n",
+ "trimmedGreeting = greeting.Trim();\n",
+ "Console.WriteLine($\"[{trimmedGreeting}]\");"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The square brackets `[` and `]` help visualize what the `Trim`, `TrimStart` and `TrimEnd` methods do. The brackets show where whitespace starts and ends.\n",
+ "\n",
+ "This sample reinforces a couple of important concepts for working with strings. The methods that manipulate strings return new string objects rather than making modifications in place. You can see that each call to any of the `Trim` methods returns a new string but doesn't change the original message.\n",
+ "\n",
+ "There are other methods available to work with a string. For example, you've probably used a search and replace command in an editor or word processor before. The `System.String.Replace` method does something similar in a string. It searches for a substring and replaces it with different text. The `System.String.Replace` method takes two **parameters**. These are the strings between the parentheses. The first string is the text to search for. The second string is the text to replace it with. Try it for yourself. Add this code to the above cell:\n",
+ "\n",
+ "```csharp\n",
+ "string sayHello = \"Hello World!\";\n",
+ "Console.WriteLine(sayHello);\n",
+ "sayHello = sayHello.Replace(\"Hello\", \"Greetings\");\n",
+ "Console.WriteLine(sayHello);\n",
+ "```\n",
+ "\n",
+ "Two other useful methods make a string ALL CAPS or all lower case. Try the following code in the preceding cell:\n",
+ "\n",
+ "```csharp\n",
+ "Console.WriteLine(sayHello.ToUpper());\n",
+ "Console.WriteLine(sayHello.ToLower());\n",
+ "```\n",
+ "\n",
+ "## Search strings\n",
+ "\n",
+ "The other part of a *search and replace* operation is to find text in a string. You can use the `System.String.Contains` method for searching. It tells you if a string contains a substring inside it. Try the following cell to explore `System.String.Contains`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "string songLyrics = \"You say goodbye, and I say hello\";\n",
+ "Console.WriteLine(songLyrics.Contains(\"goodbye\"));\n",
+ "Console.WriteLine(songLyrics.Contains(\"greetings\"));"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The `System.String.Contains` method returns a **boolean** value which tells you if the string you were searching for was found. A **boolean** stores either a `true` or a `false` value. When displayed as text output, they are capitalized: `True` and `False`, respectively. You'll learn more about **boolean** values in a later lesson.\n",
+ "\n",
+ "***Challenge***\n",
+ "\n",
+ "There are two similar methods, `System.String.StartsWith` and `System.String.EndsWith` that also search for sub-strings in a string. These find a substring at the beginning or the end of the string. Try to modify the previous sample to use `System.String.StartsWith` and `System.String.EndsWith` instead of `System.String.Contains`. Search for \"You\" or \"goodbye\" at the beginning of a string. Search for \"hello\" or \"goodbye\" at the end of a string.\n",
+ "\n",
+ "> Watch your punctuation when you test for the text at the end of the string. If the string ends with a period, you must check for a string that ends with a period.\n",
+ "\n",
+ "You should get `true` for starting with \"You\" and ending with \"hello\" and false for starting with or ending with \"goodbye\".\n",
+ "\n",
+ "Keep learning by trying the [numbers in C#](numbers.ipynb) lesson."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": ".NET (C#)",
+ "language": "C#",
+ "name": ".net-csharp"
+ },
+ "language_info": {
+ "file_extension": ".cs",
+ "mimetype": "text/x-csharp",
+ "name": "C#",
+ "pygments_lexer": "csharp",
+ "version": "8.0"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/notebooks/hello-csharp/list-collection.ipynb b/notebooks/hello-csharp/list-collection.ipynb
new file mode 100644
index 0000000..4dec4fc
--- /dev/null
+++ b/notebooks/hello-csharp/list-collection.ipynb
@@ -0,0 +1,217 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Learn to manage data collections using the generic list type\n",
+ "\n",
+ "*This tutorial teaches you C# interactively, using your browser to write C# code and see the results of compiling and running your code. It contains a series of lessons that create, modify, and explore collections and arrays.*\n",
+ "\n",
+ "## Create lists\n",
+ "\n",
+ "Run the following cell:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "var names = new List { \"\", \"Ana\", \"Felipe\" };\n",
+ "foreach (var name in names)\n",
+ "{\n",
+ " Console.WriteLine($\"Hello {name.ToUpper()}!\");\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You've created a list of strings, added three names to that list, and printed out the names in all CAPS. You're using concepts that you've learned in earlier tutorials to loop through the list.\n",
+ "\n",
+ "The code to display names makes use of the *string interpolation* feature. When you precede a `string` with the `$` character, you can embed C# code in the string declaration. The actual string replaces that C# code with the value it generates. In this example, it replaces the `{name.ToUpper()}` with each name, converted to capital letters, because you called the `System.String.ToUpper` method.\n",
+ "\n",
+ "Let's keep exploring.\n",
+ "\n",
+ "## Modify list contents\n",
+ "\n",
+ "The collection you created uses the `System.Collections.Generic.List` type. This type stores sequences of elements. You specify the type of the elements between the angle brackets.\n",
+ "\n",
+ "One important aspect of this `System.Collections.Generic.List` type is that it can grow or shrink, enabling you to add or remove elements. You can see the results by modifying the contents after you've displayed its contents.Try the following code:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "Console.WriteLine();\n",
+ "names.Add(\"Maria\");\n",
+ "names.Add(\"Bill\");\n",
+ "names.Remove(\"Ana\");\n",
+ "foreach (var name in names)\n",
+ "{\n",
+ " Console.WriteLine($\"Hello {name.ToUpper()}!\");\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You've added two more names to the end of the list. You've also removed one as well. The output from this block of code shows the initial contents, then prints a blank line and the new contents.\n",
+ "\n",
+ "The `System.Collections.Generic.List` enables you to reference individual items by **index** as well. You access items using the `[` and `]` tokens. Try it:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "Console.WriteLine($\"My name is {names[0]}.\");\n",
+ "Console.WriteLine($\"I've added {names[2]} and {names[3]} to the list.\");"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You're not allowed to access past the end of the list. You can check how long the list is using the `System.Collections.Generic.List.Count` property. Try it:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "Console.WriteLine($\"The list has {names.Count} people in it\");"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In C#, indices start at 0, so the largest valid index is one less than the number of items in the list.\n",
+ "\n",
+ "## Search and sort lists\n",
+ "\n",
+ "Our samples use relatively small lists, but your applications may often create lists with many more elements, sometimes numbering in the thousands. To find elements in these larger collections, you need to search the list for different items. The `System.Collections.Generic.List.IndexOf` method searches for an item and returns the index of the item. Try it to see how it works:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "var index = names.IndexOf(\"Felipe\");\n",
+ "if (index != -1)\n",
+ " Console.WriteLine($\"The name {names[index]} is at index {index}\");\n",
+ "\n",
+ "var notFound = names.IndexOf(\"Not Found\");\n",
+ " Console.WriteLine($\"When an item is not found, IndexOf returns {notFound}\");"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You may not know if an item is in the list, so you should always check the index returned by `System.Collections.Generic.List.IndexOf`. If it is -1, the item was not found.\n",
+ "\n",
+ "The items in your list can be sorted as well. The `System.Collections.Generic.List.Sort` method sorts all the items in the list in their normal order (alphabetically in the case of strings):"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "names.Sort();\n",
+ "foreach (var name in names)\n",
+ "{\n",
+ " Console.WriteLine($\"Hello {name.ToUpper()}!\");\n",
+ "}\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Lists of other types\n",
+ "\n",
+ "You've been using the `string` type in lists so far. Let's make a `List` using a different type. Let's build a set of numbers:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "var fibonacciNumbers = new List {1, 1};"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "That creates a list of integers, and sets the first two integers to the value 1. The *Fibonacci Sequence*, a sequence of numbers, starts with two 1s. Each next Fibonacci number is found by taking the sum of the previous two numbers. Try this code:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "var previous = fibonacciNumbers[fibonacciNumbers.Count - 1];\n",
+ "var previous2 = fibonacciNumbers[fibonacciNumbers.Count - 2];\n",
+ "\n",
+ "fibonacciNumbers.Add(previous + previous2);\n",
+ "\n",
+ "foreach(var item in fibonacciNumbers)\n",
+ " Console.WriteLine(item);"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Challenge\n",
+ "\n",
+ "See if you can put together some of the concepts from this and earlier lessons. Expand on what you've built so far with Fibonacci Numbers. Try and write the code to generate the first 20 numbers in the sequence. (As a hint, the 20th Fibonacci number is 6765.)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": ".NET (C#)",
+ "language": "C#",
+ "name": ".net-csharp"
+ },
+ "language_info": {
+ "file_extension": ".cs",
+ "mimetype": "text/x-csharp",
+ "name": "C#",
+ "pygments_lexer": "csharp",
+ "version": "8.0"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/notebooks/hello-csharp/numbers.ipynb b/notebooks/hello-csharp/numbers.ipynb
new file mode 100644
index 0000000..7d4d801
--- /dev/null
+++ b/notebooks/hello-csharp/numbers.ipynb
@@ -0,0 +1,324 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Manipulate integral and floating point numbers in C#\n",
+ "\n",
+ "*In this tutorial about numeric types, you'll use Jupyter notebooks to learn C# interactively. You're going to write C# code and see the results of compiling and running your code directly in the notebook.*\n",
+ "\n",
+ "It contains a series of lessons that explore numbers and math operations in C#. These lessons teach you the fundamentals of the C# language.\n",
+ "\n",
+ "## Working with integer math\n",
+ "\n",
+ "Run the following cell:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "int a = 18;\n",
+ "int b = 6;\n",
+ "int c = a + b;\n",
+ "Console.WriteLine(c);"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You've seen one of the fundamental math operations with integers. The `int` type represents an **integer**, a positive or negative whole number. You use the `+` symbol for addition. Other common mathematical operations for integers include:\n",
+ "\n",
+ "- `-` for subtraction\n",
+ "- `*` for multiplication\n",
+ "- `/` for division\n",
+ "\n",
+ "Start by exploring those different operations. Modify the third line to try each of these operations. After each edit, select the **Run** button.\n",
+ "\n",
+ "- Subtraction: `int c = a - b;`\n",
+ "- Multiplication: `int c = a * b;`\n",
+ "- Division: `int c = a / b;`\n",
+ "```\n",
+ "\n",
+ "You can also experiment by writing multiple mathematics operations in the same line, if you'd like.\n",
+ "\n",
+ "> As you explore C# (or any programming language), you'll make mistakes when you write code. The **compiler** will find those errors and report them to you. When the output contains error messages, look closely at the example code, and the code in the interactive window to see what to fix. That exercise will help you learn the structure of C# code.\n",
+ "\n",
+ "## Explore order of operations\n",
+ "\n",
+ "The C# language defines the precedence of different mathematics operations with rules consistent with the rules you learned in mathematics. Multiplication and division take precedence over addition and subtraction. Explore that by running the following cell:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "int a = 5;\n",
+ "int b = 4;\n",
+ "int c = 2;\n",
+ "int d = a + b * c;\n",
+ "Console.WriteLine(d);"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The output demonstrates that the multiplication is performed before the addition.\n",
+ "\n",
+ "You can force a different order of operation by adding parentheses around the operation or operations you want performed first. Modify the fourth line in the cell above to force the addition to be performed first: `int d = (a + b) * c;`\n",
+ "\n",
+ "Explore more by combining many different operations. Replace the fourth line above with something like this. `int d = (a + b) - 6 * c + (12 * 4) / 3 + 12;`\n",
+ "\n",
+ "You may have noticed an interesting behavior for integers. Integer division always produces an integer result, even when you'd expect the result to include a decimal or fractional portion.\n",
+ "\n",
+ "## Explore integer precision and limits\n",
+ "\n",
+ "If you haven't seen this behavior, try the following cell:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "int a = 7;\n",
+ "int b = 4;\n",
+ "int c = 3;\n",
+ "int d = (a + b) / c;\n",
+ "int e = (a + b) % c;\n",
+ "Console.WriteLine($\"quotient: {d}\");\n",
+ "Console.WriteLine($\"remainder: {e}\");"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "That last sample showed you that integer division truncates the result. It showed how you can get the **remainder** by using the **remainder** operator, the `%` character.\n",
+ "\n",
+ "The C# integer type differs from mathematical integers in one other way: the `int` type has minimum and maximum limits. Run this cell to see those limits:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "int max = int.MaxValue;\n",
+ "int min = int.MinValue;\n",
+ "Console.WriteLine($\"The range of integers is {min} to {max}\");"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If a calculation produces a value that exceeds those limits, you have an **underflow** or **overflow** condition. The answer appears to wrap from one limit to the other. Add these two lines to the preceding cell to see an example:\n",
+ "\n",
+ "```csharp\n",
+ "int what = max + 3;\n",
+ "Console.WriteLine($\"An example of overflow: {what}\");\n",
+ "```\n",
+ "\n",
+ "Notice that the answer is very close to the minimum (negative) integer. It's the same as `min + 2`. The addition operation **overflowed** the allowed values for integers. The answer is a very large negative number because an overflow \"wraps around\" from the largest possible integer value to the smallest.\n",
+ "\n",
+ "There are other numeric types with different limits and precision that you would use when the `int` type doesn't meet your needs. Let's explore those types of numbers next.\n",
+ "\n",
+ "## Work with the double type\n",
+ "\n",
+ "The `double` numeric type represents a double-precision floating point number. Those terms may be new to you. A **floating point** number is useful to represent non-integral numbers that may be very large or small in magnitude. **Double-precision** is a relative term that describes the numbers of binary digits used to store the value. **Double precision** number have twice the number of binary digits as **single-precision**. On modern computers, it is more common to use double precision than single precision numbers. **Single precision** numbers are declared using the `float` keyword. Let's explore. Try the following cell:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "double a = 5;\n",
+ "double b = 4;\n",
+ "double c = 2;\n",
+ "double d = (a + b) / c;\n",
+ "Console.WriteLine(d);"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Notice that the answer includes the decimal portion of the quotient. Try a slightly more complicated expression with doubles:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "double a = 19;\n",
+ "double b = 23;\n",
+ "double c = 8;\n",
+ "double d = (a + b) / c;\n",
+ "Console.WriteLine(d);"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The range of a double value is much greater than integer values. Try the following cell:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "double max = double.MaxValue;\n",
+ "double min = double.MinValue;\n",
+ "Console.WriteLine($\"The range of double is {min} to {max}\");"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "These values are printed out in scientific notation. The number to the left of the `E` is the significand. The number to the right is the exponent,\n",
+ "as a power of 10.\n",
+ " \n",
+ "Just like decimal numbers in math, doubles in C# can have rounding errors. Try this cell:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "double third = 1.0 / 3.0;\n",
+ "Console.WriteLine(third);"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You know that `0.3` is `3/10` and not exactly the same as `1/3`. Similarly, `0.33` is `33/100`. That's closer to `1/3`, but still not exact. \n",
+ "\n",
+ "***Challenge***\n",
+ "\n",
+ "Try other calculations with large numbers, small numbers, multiplication, and division using the `double` type. Try more complicated calculations. Use the cell below for your ideas."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Work with decimal types\n",
+ "\n",
+ "You've seen the basic numeric types in C#: integers and doubles. There's one other type to learn: the `decimal` type. The `decimal` type has a smaller range but greater precision than `double`. Let's take a look:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "decimal min = decimal.MinValue;\n",
+ "decimal max = decimal.MaxValue;\n",
+ "Console.WriteLine($\"The range of the decimal type is {min} to {max}\");"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Notice that the range is smaller than the `double` type. You can see the greater precision with the decimal type by trying the following cell:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "double a = 1.0;\n",
+ "double b = 3.0;\n",
+ "Console.WriteLine(a / b);\n",
+ "\n",
+ "decimal c = 1.0M;\n",
+ "decimal d = 3.0M;\n",
+ "Console.WriteLine(c / d);"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The `M` suffix on the numbers is how you indicate that a constant should use the `decimal` type.\n",
+ "\n",
+ "Notice that the math using the decimal type has more digits to the right of the decimal point.\n",
+ "\n",
+ "The `M` suffix on the numbers is how you indicate that a constant should use the `decimal` type. Otherwise, the compiler assumes the `double` type.\n",
+ "\n",
+ "> The letter `M` was chosen as the most visually distinct letter between the `double` and `decimal` keywords.\n",
+ "\n",
+ "Notice that the math using the decimal type has more digits to the right of the decimal point.\n",
+ "\n",
+ "***Challenge***\n",
+ "\n",
+ "Now that you've seen the different numeric types, write code that calculates the area of a circle whose radius is 2.50 centimeters. Remember that the area of a circle is the radius squared multiplied by PI. One hint: .NET contains a constant for PI, `System.Math.PI` that you can use for that value. `System.Math.PI`, like all constants declared in the `System.Math` namespace, is a `double` value. For that reason, you should use `double` instead of `decimal` values for this challenge.\n",
+ "\n",
+ "You should get an answer between 19 and 20."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Next, try the tutorial on [branches and loops](branches-and-loops.ipynb)."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": ".NET (C#)",
+ "language": "C#",
+ "name": ".net-csharp"
+ },
+ "language_info": {
+ "file_extension": ".cs",
+ "mimetype": "text/x-csharp",
+ "name": "C#",
+ "pygments_lexer": "csharp",
+ "version": "8.0"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}